10#ifndef CDT_PLUSPLUS_RUNTIME_CONFIG_HPP
11#define CDT_PLUSPLUS_RUNTIME_CONFIG_HPP
23namespace cdt::runtime_config
41 double m_initial_radius;
42 double m_foliation_spacing;
44 std::size_t m_threads;
46 explicit Triangulation(
68 auto operator=(Triangulation
const& other) -> Triangulation& =
default;
71 auto operator=(Triangulation&& other)
noexcept -> Triangulation& =
default;
72 ~Triangulation() =
default;
76 {
return m_topology; }
80 {
return m_simplices; }
84 {
return m_timeslices; }
88 {
return m_dimensions; }
92 {
return m_initial_radius; }
96 {
return m_foliation_spacing; }
103 [[nodiscard]]
auto threads() const noexcept -> std::
size_t
104 {
return m_threads; }
113 long double alpha,
long double k,
121 long double m_lambda;
127 long double const alpha,
long double const k,
147 auto operator=(Simulation
const& other) -> Simulation& =
default;
150 auto operator=(Simulation&& other)
noexcept -> Simulation& =
default;
151 ~Simulation() =
default;
155 {
return m_triangulation; }
158 [[nodiscard]]
auto alpha() const noexcept ->
long double {
return m_alpha; }
161 [[nodiscard]]
auto k() const noexcept ->
long double {
return m_k; }
164 [[nodiscard]]
auto lambda() const noexcept ->
long double
173 {
return m_checkpoint; }
177 {
return m_write_files; }
182 template <
typename FloatingPo
int>
183 [[nodiscard]]
auto checked_finite(
char const* name,
184 FloatingPoint
const value)
187 if (!std::isfinite(value))
189 throw std::invalid_argument(std::string{name} +
" must be finite.");
194 [[nodiscard]]
inline auto checked_int(
char const* name,
195 long long const value)
198 if (!std::in_range<Int_precision>(value))
200 throw std::out_of_range(std::string{name} +
201 " exceeds the supported integer range.");
206 [[nodiscard]]
inline auto checked_threads(
long long const value)
211 throw std::invalid_argument(
"Thread count must be positive.");
213 if (!std::in_range<std::size_t>(value))
215 throw std::out_of_range(
216 "Thread count exceeds the supported size range.");
218#if !defined(CDT_ENABLE_PARALLEL_TRIANGULATION) || \
219 !CDT_ENABLE_PARALLEL_TRIANGULATION
222 throw std::invalid_argument(
223 "This build supports only --threads 1; use the parallel preset "
224 "for larger values.");
227 return static_cast<std::size_t
>(value);
230 [[nodiscard]]
inline auto select_topology(
bool const spherical,
233 if (spherical == toroidal)
235 throw std::invalid_argument(
236 "Specify exactly one topology: --spherical or --toroidal.");
240 throw std::invalid_argument(
241 "Toroidal triangulations are not yet supported.");
246 using GeneratedPopulation = utilities::Generated_population_bounds;
248 [[nodiscard]]
inline auto make_generated_population(
250 double const initial_radius,
double const foliation_spacing)
251 -> GeneratedPopulation
253 auto const bounds = utilities::generated_population_bounds(
256 if (bounds.points_per_timeslice < 2)
258 throw std::invalid_argument(
259 "Simplices and timeslices would create an empty triangulation; "
260 "increase the simplices per timeslice.");
263 auto const first_layer_points =
264 static_cast<long double>(bounds.points_per_timeslice) *
266 if (first_layer_points < 2.0L)
268 throw std::invalid_argument(
269 "Initial radius is too small to populate the first timeslice.");
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()))
277 throw std::out_of_range(
278 "Foliation parameters generate too many points per timeslice.");
304 bool const spherical,
bool const toroidal,
long long const simplices,
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);
318 if (checked_dimensions != 3)
320 throw std::invalid_argument(
321 "Only three-dimensional triangulations are supported.");
323 if (checked_simplices < 2 || checked_timeslices < 2)
325 throw std::invalid_argument(
326 "Simplices and timeslices must each be at least 2.");
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)
335 throw std::invalid_argument(
"Initial radius must be positive.");
337 if (checked_foliation_spacing <= 0.0)
339 throw std::invalid_argument(
"Foliation spacing must be positive.");
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);
350 checked_initial_radius,
351 checked_foliation_spacing,
371 long double const k,
long double const lambda,
long long const passes,
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)
379 throw std::domain_error(
"Alpha in 3D must be greater than 1/2.");
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)
387 throw std::invalid_argument(
"Passes must be positive.");
389 if (checked_checkpoint <= 0)
391 throw std::invalid_argument(
"Checkpoint interval must be positive.");
395 checked_lambda, checked_passes, checked_checkpoint,
Run-owned random-number generation and reproducible stream splitting.
Root entropy value used to reproduce a random run.
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.
@ SPHERICAL
Supported spherical spatial slices.
std::int32_t Int_precision