CDT++ 1.0.0
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Runtime_config.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2026 Adam Getchell
5 ******************************************************************************/
6
9
10#ifndef CDT_PLUSPLUS_RUNTIME_CONFIG_HPP
11#define CDT_PLUSPLUS_RUNTIME_CONFIG_HPP
12
13#include <cmath>
14#include <cstddef>
15#include <limits>
16#include <stdexcept>
17#include <string>
18#include <utility>
19
20#include "Random.hpp"
21#include "Utilities.hpp"
22
23namespace cdt::runtime_config
24{
28 class Triangulation
29 {
30 friend auto make_triangulation(bool spherical, bool toroidal,
31 long long simplices, long long timeslices,
32 long long dimensions, double initial_radius,
33 double foliation_spacing,
34 cdt::RandomSeed seed, long long threads)
35 -> Triangulation;
36
37 Topology m_topology;
38 Int_precision m_simplices;
39 Int_precision m_timeslices;
40 Int_precision m_dimensions;
41 double m_initial_radius;
42 double m_foliation_spacing;
43 cdt::RandomSeed m_seed;
44 std::size_t m_threads;
45
46 explicit Triangulation(
49 double const initial_radius, double const foliation_spacing,
50 cdt::RandomSeed const seed, std::size_t const threads) noexcept
51 : m_topology{topology}
52 , m_simplices{simplices}
53 , m_timeslices{timeslices}
54 , m_dimensions{dimensions}
55 , m_initial_radius{initial_radius}
56 , m_foliation_spacing{foliation_spacing}
57 , m_seed{seed}
58 , m_threads{threads}
59 {}
60
61 public:
63 Triangulation(Triangulation const& other) = default;
65 Triangulation(Triangulation&& other) noexcept = default;
68 auto operator=(Triangulation const& other) -> Triangulation& = default;
71 auto operator=(Triangulation&& other) noexcept -> Triangulation& = default;
72 ~Triangulation() = default;
73
75 [[nodiscard]] auto topology() const noexcept -> Topology
76 { return m_topology; }
77
79 [[nodiscard]] auto simplices() const noexcept -> Int_precision
80 { return m_simplices; }
81
83 [[nodiscard]] auto timeslices() const noexcept -> Int_precision
84 { return m_timeslices; }
85
87 [[nodiscard]] auto dimensions() const noexcept -> Int_precision
88 { return m_dimensions; }
89
91 [[nodiscard]] auto initial_radius() const noexcept -> double
92 { return m_initial_radius; }
93
95 [[nodiscard]] auto foliation_spacing() const noexcept -> double
96 { return m_foliation_spacing; }
97
99 [[nodiscard]] auto seed() const noexcept -> cdt::RandomSeed
100 { return m_seed; }
101
103 [[nodiscard]] auto threads() const noexcept -> std::size_t
104 { return m_threads; }
105 };
106
110 class Simulation
111 {
113 long double alpha, long double k,
114 long double lambda, long long passes,
115 long long checkpoint, bool write_files)
116 -> Simulation;
117
118 Triangulation m_triangulation;
119 long double m_alpha;
120 long double m_k;
121 long double m_lambda;
122 Int_precision m_passes;
123 Int_precision m_checkpoint;
124 bool m_write_files;
125
126 explicit Simulation(Triangulation const& triangulation,
127 long double const alpha, long double const k,
128 long double const lambda, Int_precision const passes,
130 bool const write_files) noexcept
131 : m_triangulation{triangulation}
132 , m_alpha{alpha}
133 , m_k{k}
134 , m_lambda{lambda}
135 , m_passes{passes}
136 , m_checkpoint{checkpoint}
137 , m_write_files{write_files}
138 {}
139
140 public:
142 Simulation(Simulation const& other) = default;
144 Simulation(Simulation&& other) noexcept = default;
147 auto operator=(Simulation const& other) -> Simulation& = default;
150 auto operator=(Simulation&& other) noexcept -> Simulation& = default;
151 ~Simulation() = default;
152
154 [[nodiscard]] auto triangulation() const noexcept -> Triangulation const&
155 { return m_triangulation; }
156
158 [[nodiscard]] auto alpha() const noexcept -> long double { return m_alpha; }
159
161 [[nodiscard]] auto k() const noexcept -> long double { return m_k; }
162
164 [[nodiscard]] auto lambda() const noexcept -> long double
165 { return m_lambda; }
166
168 [[nodiscard]] auto passes() const noexcept -> Int_precision
169 { return m_passes; }
170
172 [[nodiscard]] auto checkpoint() const noexcept -> Int_precision
173 { return m_checkpoint; }
174
176 [[nodiscard]] auto write_files() const noexcept -> bool
177 { return m_write_files; }
178 };
179
180 namespace detail
181 {
182 template <typename FloatingPoint>
183 [[nodiscard]] auto checked_finite(char const* name,
184 FloatingPoint const value)
185 -> FloatingPoint
186 {
187 if (!std::isfinite(value))
188 {
189 throw std::invalid_argument(std::string{name} + " must be finite.");
190 }
191 return value;
192 }
193
194 [[nodiscard]] inline auto checked_int(char const* name,
195 long long const value)
197 {
198 if (!std::in_range<Int_precision>(value))
199 {
200 throw std::out_of_range(std::string{name} +
201 " exceeds the supported integer range.");
202 }
203 return static_cast<Int_precision>(value);
204 }
205
206 [[nodiscard]] inline auto checked_threads(long long const value)
207 -> std::size_t
208 {
209 if (value <= 0)
210 {
211 throw std::invalid_argument("Thread count must be positive.");
212 }
213 if (!std::in_range<std::size_t>(value))
214 {
215 throw std::out_of_range(
216 "Thread count exceeds the supported size range.");
217 }
218#if !defined(CDT_ENABLE_PARALLEL_TRIANGULATION) || \
219 !CDT_ENABLE_PARALLEL_TRIANGULATION
220 if (value != 1)
221 {
222 throw std::invalid_argument(
223 "This build supports only --threads 1; use the parallel preset "
224 "for larger values.");
225 }
226#endif
227 return static_cast<std::size_t>(value);
228 }
229
230 [[nodiscard]] inline auto select_topology(bool const spherical,
231 bool const toroidal) -> Topology
232 {
233 if (spherical == toroidal)
234 {
235 throw std::invalid_argument(
236 "Specify exactly one topology: --spherical or --toroidal.");
237 }
238 if (toroidal)
239 {
240 throw std::invalid_argument(
241 "Toroidal triangulations are not yet supported.");
242 }
243 return Topology::SPHERICAL;
244 }
245
246 using GeneratedPopulation = utilities::Generated_population_bounds;
247
248 [[nodiscard]] inline auto make_generated_population(
249 Int_precision const simplices, Int_precision const timeslices,
250 double const initial_radius, double const foliation_spacing)
251 -> GeneratedPopulation
252 {
253 auto const bounds = utilities::generated_population_bounds(
254 Int_precision{3}, simplices, timeslices, initial_radius,
255 foliation_spacing);
256 if (bounds.points_per_timeslice < 2)
257 {
258 throw std::invalid_argument(
259 "Simplices and timeslices would create an empty triangulation; "
260 "increase the simplices per timeslice.");
261 }
262
263 auto const first_layer_points =
264 static_cast<long double>(bounds.points_per_timeslice) *
265 initial_radius;
266 if (first_layer_points < 2.0L)
267 {
268 throw std::invalid_argument(
269 "Initial radius is too small to populate the first timeslice.");
270 }
271
272 if (!std::isfinite(bounds.last_layer_points) ||
273 bounds.last_layer_points >
274 static_cast<long double>(
275 std::numeric_limits<Int_precision>::max()))
276 {
277 throw std::out_of_range(
278 "Foliation parameters generate too many points per timeslice.");
279 }
280 return bounds;
281 }
282 } // namespace detail
283
303 [[nodiscard]] inline auto make_triangulation(
304 bool const spherical, bool const toroidal, long long const simplices,
305 long long const timeslices, long long const dimensions,
306 double const initial_radius, double const foliation_spacing,
308 long long const threads = 1) -> Triangulation
309 {
310 auto const topology = detail::select_topology(spherical, toroidal);
311 auto const checked_simplices =
312 detail::checked_int("Number of simplices", simplices);
313 auto const checked_timeslices =
314 detail::checked_int("Number of timeslices", timeslices);
315 auto const checked_dimensions =
316 detail::checked_int("Dimensionality", dimensions);
317
318 if (checked_dimensions != 3)
319 {
320 throw std::invalid_argument(
321 "Only three-dimensional triangulations are supported.");
322 }
323 if (checked_simplices < 2 || checked_timeslices < 2)
324 {
325 throw std::invalid_argument(
326 "Simplices and timeslices must each be at least 2.");
327 }
328
329 auto const checked_initial_radius =
330 detail::checked_finite("Initial radius", initial_radius);
331 auto const checked_foliation_spacing =
332 detail::checked_finite("Foliation spacing", foliation_spacing);
333 if (checked_initial_radius <= 0.0)
334 {
335 throw std::invalid_argument("Initial radius must be positive.");
336 }
337 if (checked_foliation_spacing <= 0.0)
338 {
339 throw std::invalid_argument("Foliation spacing must be positive.");
340 }
341
342 [[maybe_unused]] auto const population = detail::make_generated_population(
343 checked_simplices, checked_timeslices, checked_initial_radius,
344 checked_foliation_spacing);
345 auto const checked_threads = detail::checked_threads(threads);
346 return Triangulation{topology,
347 checked_simplices,
348 checked_timeslices,
349 checked_dimensions,
350 checked_initial_radius,
351 checked_foliation_spacing,
352 seed,
353 checked_threads};
354 }
355
369 [[nodiscard]] inline auto make_simulation(
370 Triangulation const& triangulation, long double const alpha,
371 long double const k, long double const lambda, long long const passes,
372 long long const checkpoint, bool const write_files) -> Simulation
373 {
374 auto const checked_alpha = detail::checked_finite("Alpha", alpha);
375 auto const checked_k = detail::checked_finite("K", k);
376 auto const checked_lambda = detail::checked_finite("Lambda", lambda);
377 if (checked_alpha <= 0.5L)
378 {
379 throw std::domain_error("Alpha in 3D must be greater than 1/2.");
380 }
381
382 auto const checked_passes = detail::checked_int("Passes", passes);
383 auto const checked_checkpoint =
384 detail::checked_int("Checkpoint interval", checkpoint);
385 if (checked_passes <= 0)
386 {
387 throw std::invalid_argument("Passes must be positive.");
388 }
389 if (checked_checkpoint <= 0)
390 {
391 throw std::invalid_argument("Checkpoint interval must be positive.");
392 }
393
394 return Simulation{triangulation, checked_alpha, checked_k,
395 checked_lambda, checked_passes, checked_checkpoint,
397 }
398} // namespace cdt::runtime_config
399
400#endif // CDT_PLUSPLUS_RUNTIME_CONFIG_HPP
Run-owned random-number generation and reproducible stream splitting.
Utility functions.
Root entropy value used to reproduce a random run.
Definition Random.hpp:49
auto operator=(Simulation const &other) -> Simulation &=default
auto operator=(Simulation &&other) noexcept -> Simulation &=default
auto write_files() const noexcept -> bool
auto passes() const noexcept -> Int_precision
auto checkpoint() const noexcept -> Int_precision
friend auto make_simulation(Triangulation const &triangulation, long double alpha, long double k, long double lambda, long long passes, long long checkpoint, bool write_files) -> Simulation
Validate the complete simulation configuration.
auto lambda() const noexcept -> long double
Simulation(Simulation const &other)=default
auto triangulation() const noexcept -> Triangulation const &
auto k() const noexcept -> long double
auto alpha() const noexcept -> long double
Simulation(Simulation &&other) noexcept=default
Triangulation(Triangulation const &other)=default
auto topology() const noexcept -> Topology
auto simplices() const noexcept -> Int_precision
friend auto make_triangulation(bool spherical, bool toroidal, long long simplices, long long timeslices, long long dimensions, double initial_radius, double foliation_spacing, cdt::RandomSeed seed, long long threads) -> Triangulation
Validate raw triangulation options and narrow them into project types.
auto initial_radius() const noexcept -> double
Triangulation(Triangulation &&other) noexcept=default
auto dimensions() const noexcept -> Int_precision
auto threads() const noexcept -> std::size_t
auto operator=(Triangulation const &other) -> Triangulation &=default
auto operator=(Triangulation &&other) noexcept -> Triangulation &=default
auto seed() const noexcept -> cdt::RandomSeed
auto foliation_spacing() const noexcept -> double
auto timeslices() const noexcept -> Int_precision
clang-15 does not support std::format
Topology
Spatial-topology label stored by configuration and persistence APIs.
Definition Utilities.hpp:74
@ SPHERICAL
Supported spherical spatial slices.
Definition Utilities.hpp:76
std::int32_t Int_precision
Definition Settings.hpp:30