CDT++
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Utilities.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2017 Adam Getchell
5 ******************************************************************************/
6
10
11#ifndef INCLUDE_UTILITIES_HPP_
12#define INCLUDE_UTILITIES_HPP_
13
14#include <filesystem>
15#include <fstream>
16#include <gsl/gsl>
17#include <mutex>
18#include <random>
19#include <span>
20#include <stdexcept>
21#include <string>
22// H. Hinnant date and time library
23#include <date/tz.h>
24
26// #include <format>
27
28// M. O'Neill Permutation Congruential Generator library
29#include "pcg_random.hpp"
30
31// V. Zverovich {fmt} library
32#include <fmt/ostream.h>
33
34// G. Melman spdlog library
35#include <spdlog/sinks/basic_file_sink.h>
36#include <spdlog/sinks/stdout_color_sinks.h>
37#include <spdlog/spdlog.h>
38
39// Global project settings
40#include "Settings.hpp"
41
42enum class topology_type
43{
44 TOROIDAL,
45 SPHERICAL
46};
47
52inline auto operator<<(std::ostream& t_os,
53 topology_type const& t_topology) -> std::ostream&
54{
55 switch (t_topology)
56 {
57 case topology_type::SPHERICAL: return t_os << "spherical";
58 case topology_type::TOROIDAL: return t_os << "toroidal";
59 default: return t_os << "none";
60 }
61} // operator<<
62
63namespace utilities
64{
73 [[nodiscard]] inline auto current_date_time()
74 {
76 // auto time = std::chrono::zoned_time(std::chrono::current_zone(),
77 // std::chrono::system_clock::now());
78 // return std::formatter<std::chrono::system_clock::time_point,
79 // char>::format(time, "{:%Y-%m-%d.%X%Z}");
80 date::zoned_time const time(date::current_zone(),
81 std::chrono::system_clock::now());
82 return format("%Y-%m-%d.%X%Z", time);
83 } // current_date_time
84
93 [[nodiscard]] inline auto make_filename(
94 topology_type const& t_topology, Int_precision t_dimension,
95 Int_precision t_number_of_simplices, Int_precision t_number_of_timeslices,
96 double t_initial_radius,
97 double t_foliation_spacing) noexcept -> std::filesystem::path
98 {
99 std::string filename;
100 if (t_topology == topology_type::SPHERICAL) { filename += "S"; }
101 else { filename += "T"; }
102 // std::to_string() works in C++11, but not earlier
103 filename += std::to_string(t_dimension);
104
105 filename += "-";
106
107 filename += std::to_string(t_number_of_timeslices);
108
109 filename += "-";
110
111 filename += std::to_string(t_number_of_simplices);
112
113 filename += "-I";
114
115 filename += std::to_string(t_initial_radius);
116
117 filename += "-R";
118
119 filename += std::to_string(t_foliation_spacing);
120
121 // Append current time
122 filename += "-";
123 filename += current_date_time();
124
125 // Append .off file extension
126 filename += ".off";
127 return filename;
128 } // make_filename
129
130 template <typename ManifoldType>
131 [[nodiscard]] auto make_filename(ManifoldType const& manifold)
132 {
133 return make_filename(ManifoldType::topology, ManifoldType::dimension,
134 manifold.N3(), manifold.max_time(),
135 manifold.initial_radius(),
136 manifold.foliation_spacing());
137 } // make_filename
138
143 template <typename TriangulationType>
144 void print_delaunay(TriangulationType const& t_triangulation)
145 {
146 fmt::print(
147 "Triangulation has {} vertices and {} edges and {} faces and {} "
148 "simplices.\n",
149 t_triangulation.number_of_vertices(),
150 t_triangulation.number_of_finite_edges(),
151 t_triangulation.number_of_finite_facets(),
152 t_triangulation.number_of_finite_cells());
153 } // print_delaunay
154
162 template <typename TriangulationType>
163 void write_file(std::filesystem::path const& filename,
164 TriangulationType triangulation)
165 {
166 static std::mutex mutex;
167 fmt::print("Writing to file {}\n", filename.string());
168 std::scoped_lock const lock(mutex);
169 std::ofstream file(filename, std::ios::out);
170 if (!file.is_open())
171 {
172 throw std::filesystem::filesystem_error(
173 "Could not open file for writing", filename,
174 std::make_error_code(std::errc::bad_file_descriptor));
175 }
176 file << triangulation;
177 } // write_file
178
185 template <typename ManifoldType>
186 void write_file(ManifoldType const& t_universe)
187 {
188 std::filesystem::path filename;
189 filename.assign(make_filename(t_universe));
190 write_file(filename, t_universe.get_delaunay());
191 } // write_file
192
197 template <typename TriangulationType>
198 auto read_file(std::filesystem::path const& filename) -> TriangulationType
199 {
200 static std::mutex mutex;
201 fmt::print("Reading from file {}\n", filename.string());
202 std::scoped_lock const lock(mutex);
203 std::ifstream file(filename, std::ios::in);
204 if (!file.is_open())
205 {
206 throw std::filesystem::filesystem_error(
207 "Could not open file for reading", filename,
208 std::make_error_code(std::errc::bad_file_descriptor));
209 }
210 TriangulationType triangulation;
211 file >> triangulation;
212 return triangulation;
213 } // read_file
214
216 [[nodiscard]] inline auto die_roll() noexcept
217 {
218 pcg_extras::seed_seq_from<std::random_device> seed_source;
219
220 // Make a random number generator
221 pcg64 rng(seed_source);
222
223 // Choose random number from 1 to 6
224 std::uniform_int_distribution uniform_dist(1, 6); // NOLINT
225 Int_precision const roll = uniform_dist(rng);
226 return roll;
227 } // die_roll()
228
242 template <typename NumberType, class Distribution>
243 [[nodiscard]] auto generate_random(NumberType t_min_value,
244 NumberType t_max_value) noexcept
245 {
246 pcg_extras::seed_seq_from<std::random_device> seed_source;
247 // Make a random number generator
248 pcg64 generator(seed_source);
249 Distribution distribution(t_min_value, t_max_value);
250 return distribution(generator);
251 } // generate_random()
252
255 inline auto make_random_generator() noexcept
256 {
257 pcg_extras::seed_seq_from<std::random_device> seed_source;
258 pcg64 generator(seed_source);
259 return generator;
260 } // make_random_generator()
261
264 template <typename IntegerType>
265 [[nodiscard]] auto constexpr generate_random_int(
266 IntegerType t_min_value, IntegerType t_max_value) noexcept
267 {
268 using int_dist = std::uniform_int_distribution<IntegerType>;
269 return generate_random<IntegerType, int_dist>(t_min_value, t_max_value);
270 } // generate_random_int()
271
273 template <typename IntegerType>
274 [[nodiscard]] auto generate_random_timeslice(
275 IntegerType&& t_max_timeslice) noexcept -> decltype(auto)
276 {
277 return generate_random_int(static_cast<IntegerType>(1),
278 std::forward<IntegerType>(t_max_timeslice));
279 } // generate_random_timeslice()
280
283 template <typename FloatingPointType>
284 [[nodiscard]] auto constexpr generate_random_real(
285 FloatingPointType t_min_value, FloatingPointType t_max_value) noexcept
286 {
287 using real_dist = std::uniform_real_distribution<FloatingPointType>;
288 return generate_random<FloatingPointType, real_dist>(t_min_value,
289 t_max_value);
290 } // generate_random_real()
291
293 [[nodiscard]] auto constexpr generate_probability() noexcept
294 {
295 auto constexpr min = 0.0L;
296 auto constexpr max = 1.0L;
297 return generate_random_real(min, max);
298 } // generate_probability()
299
314 Int_precision const t_dimension, Int_precision t_number_of_simplices,
315 Int_precision t_number_of_timeslices)
316 {
317#ifndef NDEBUG
318 spdlog::debug("{} simplices on {} timeslices desired.\n",
319 t_number_of_simplices, t_number_of_timeslices);
320#endif
321
322 auto const simplices_per_timeslice =
323 t_number_of_simplices / t_number_of_timeslices;
324 if (t_dimension == 3)
325 {
326 // Avoid segfaults for small values
327 if (t_number_of_simplices == t_number_of_timeslices)
328 {
329 return 2 * simplices_per_timeslice;
330 }
331 if (t_number_of_simplices < 1000) // NOLINT
332 {
333 return static_cast<Int_precision>(
334 0.4L * // NOLINT
335 static_cast<long double>(simplices_per_timeslice));
336 }
337 if (t_number_of_simplices < 10000) // NOLINT
338 {
339 return static_cast<Int_precision>(
340 0.2L * // NOLINT
341 static_cast<long double>(simplices_per_timeslice));
342 }
343 if (t_number_of_simplices < 100000) // NOLINT
344 {
345 return static_cast<Int_precision>(
346 0.15L * // NOLINT
347 static_cast<long double>(simplices_per_timeslice));
348 }
349
350 return static_cast<Int_precision>(
351 0.1L * static_cast<long double>(simplices_per_timeslice)); // NOLINT
352 }
353 throw std::invalid_argument("Currently, dimensions cannot be >3.");
354
355 } // expected_points_per_timeslice
356
365 [[nodiscard]] inline auto Gmpzf_to_double(Gmpzf const& t_value) -> double
366 {
367 return t_value.to_double();
368 } // Gmpzf_to_double
369
394 inline void create_logger()
395 try
396 {
397 auto const console_sink =
398 std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
399 console_sink->set_level(spdlog::level::info);
400
401 auto const debug_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
402 "logs/debug-log.txt", true);
403 debug_sink->set_level(spdlog::level::debug);
404
405 auto const trace_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
406 "logs/trace-log.txt", true);
407 trace_sink->set_level(spdlog::level::trace);
408
409 spdlog::sinks_init_list sink_list = {console_sink, debug_sink, trace_sink};
410
411 auto const logger = std::make_shared<spdlog::logger>(
412 "multi_sink", sink_list.begin(), sink_list.end());
413 // This allows the logger to capture all events
414 logger->set_level(spdlog::level::trace);
415 // The sinks will filter items further via should_log()
416 logger->info("Multi-sink logger initialized.\n");
417 logger->debug("Debug logger initialized.\n");
418 logger->trace("Trace logger initialized.\n");
419 logger->debug(
420 "You must build in Debug mode for anything to be recorded in this "
421 "file.\n");
422
423 register_logger(logger);
424 set_default_logger(logger);
425 }
426 catch (spdlog::spdlog_ex const& ex)
427 {
428 // Use default logger
429 spdlog::error("Logger initialization failed: {}\n", ex.what());
430 spdlog::warn("Default logger set.\n");
431
432 } // create_logger
433
438 template <typename Point>
439 auto point_to_str(Point const& t_point) -> std::string
440 {
441 std::stringstream stream;
442 stream << t_point;
443 return stream.str();
444 } // point_to_str
445
449 inline auto topology_to_str(topology_type const& t_topology) -> std::string
450 {
451 std::stringstream stream;
452 stream << t_topology;
453 return stream.str();
454 } // topology_to_str
455} // namespace utilities
456#endif // INCLUDE_UTILITIES_HPP_
Global integer and precision settings.
std::int_fast32_t Int_precision
Definition: Settings.hpp:31
auto operator<<(std::ostream &t_os, topology_type const &t_topology) -> std::ostream &
Convert topology_type to string output.
Definition: Utilities.hpp:52
auto topology_to_str(topology_type const &t_topology) -> std::string
Convert a topology to a string using it's << operator.
Definition: Utilities.hpp:449
auto generate_random_timeslice(IntegerType &&t_max_timeslice) noexcept -> decltype(auto)
Generate a random timeslice.
Definition: Utilities.hpp:274
auto die_roll() noexcept
Roll a die with PCG.
Definition: Utilities.hpp:216
void print_delaunay(TriangulationType const &t_triangulation)
Print triangulation statistics.
Definition: Utilities.hpp:144
auto read_file(std::filesystem::path const &filename) -> TriangulationType
Read triangulation from file.
Definition: Utilities.hpp:198
auto make_filename(topology_type const &t_topology, Int_precision t_dimension, Int_precision t_number_of_simplices, Int_precision t_number_of_timeslices, double t_initial_radius, double t_foliation_spacing) noexcept -> std::filesystem::path
Generate useful filenames.
Definition: Utilities.hpp:93
auto point_to_str(Point const &t_point) -> std::string
Covert a CGAL point to a string.
Definition: Utilities.hpp:439
auto constexpr generate_probability() noexcept
Generate a probability.
Definition: Utilities.hpp:293
auto Gmpzf_to_double(Gmpzf const &t_value) -> double
Convert Gmpzf into a double.
Definition: Utilities.hpp:365
auto current_date_time()
Return current date and time.
Definition: Utilities.hpp:73
auto make_random_generator() noexcept
Make a high-quality random number generator usable by std::shuffle.
Definition: Utilities.hpp:255
void create_logger()
Create console and file loggers.
Definition: Utilities.hpp:394
void write_file(std::filesystem::path const &filename, TriangulationType triangulation)
Write triangulation to file.
Definition: Utilities.hpp:163
auto constexpr generate_random_int(IntegerType t_min_value, IntegerType t_max_value) noexcept
Generate random integers by calling generate_random, preserves template argument deduction.
Definition: Utilities.hpp:265
auto constexpr generate_random_real(FloatingPointType t_min_value, FloatingPointType t_max_value) noexcept
Generate random real numbers by calling generate_random, preserves template argument deduction.
Definition: Utilities.hpp:284
topology_type
clang-15 does not support std::format
Definition: Utilities.hpp:43
auto expected_points_per_timeslice(Int_precision const t_dimension, Int_precision t_number_of_simplices, Int_precision t_number_of_timeslices)
Calculate expected # of points per simplex.
Definition: Utilities.hpp:313
auto generate_random(NumberType t_min_value, NumberType t_max_value) noexcept
Generate random numbers.
Definition: Utilities.hpp:243