Orrery
A GPU-accelerated N-body gravitational simulator
Loading...
Searching...
No Matches
configuration.hpp File Reference

Everything a run is, as data. More...

#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "orrery/core/types.hpp"

Go to the source code of this file.

Classes

struct  orrery::sim::RunSettings
 How far to go, and from what stream of random numbers. More...
struct  orrery::sim::InitialConditionSettings
 What the run starts from. More...
struct  orrery::sim::SolverSettings
 Which solver, and the parameters that decide what it computes. More...
struct  orrery::sim::IntegratorSettings
struct  orrery::sim::OutputSettings
 What the run writes down, and how often. More...
struct  orrery::sim::Configuration
 A whole run, as data. More...

Enumerations

enum class  orrery::sim::SolverKind : std::uint8_t { kDirect , kBarnesHut , kSyclDirect , kSyclTree }
 Which force solver computes the accelerations. More...
enum class  orrery::sim::IntegratorKind : std::uint8_t { kVelocityVerlet , kYoshida4 , kRungeKutta4 }
 Which integrator advances the state.
enum class  orrery::sim::InitialConditionKind : std::uint8_t {
  kPlummer , kUniformSphere , kKepler , kDiscGalaxy ,
  kGalaxyCollision
}
 Which configuration the run starts from.
enum class  orrery::sim::ExecutorKind : std::uint8_t { kSerial , kStatic , kWorkStealing }
 How the CPU solvers divide their loop over target particles. More...

Functions

std::string_view orrery::sim::to_string (SolverKind kind) noexcept
 The spelling each of the above has in a configuration file.
std::string_view orrery::sim::to_string (IntegratorKind kind) noexcept
std::string_view orrery::sim::to_string (InitialConditionKind kind) noexcept
std::string_view orrery::sim::to_string (ExecutorKind kind) noexcept
std::optional< SolverKindorrery::sim::parse_solver_kind (std::string_view text) noexcept
 The inverse of the above, empty for a word that names nothing.
std::optional< IntegratorKindorrery::sim::parse_integrator_kind (std::string_view text) noexcept
std::optional< InitialConditionKindorrery::sim::parse_initial_condition_kind (std::string_view text) noexcept
std::optional< ExecutorKindorrery::sim::parse_executor_kind (std::string_view text) noexcept
std::string orrery::sim::solver_kind_names ()
 Every spelling each enumeration accepts, for the help text and for the error message that lists the alternatives when a word names nothing.
std::string orrery::sim::integrator_kind_names ()
std::string orrery::sim::initial_condition_kind_names ()
std::string orrery::sim::executor_kind_names ()
std::vector< std::string > orrery::sim::problems_with (const Configuration &configuration)
 Every objection to configuration, in the order the fields appear.
core::Real orrery::sim::resolved_scale_radius (const InitialConditionSettings &settings) noexcept
 The scale radius the Plummer sampler will actually use.

Detailed Description

Everything a run is, as data.

A simulation in this project is decided by about twenty numbers: what to start from, what to integrate it with, what to compute the forces with, how far to go, and what to write down on the way. This file is the type that holds those numbers, and it is deliberately nothing more than that. It builds no solver, opens no file and validates nothing at construction, so a configuration can be assembled by the parser, by the command line, or by a test writing three fields, and all three produce the same kind of object.

Two things follow from keeping it inert.

The first is that a run is reproducible from a document. Every choice that affects the answer is a field here, including the seed, so a configuration file plus a revision of this repository determines the trajectory. That is the property the whole phase exists to provide: a result nobody can regenerate is an anecdote.

The second is that the checks are a function rather than a constructor. problems_with returns every objection at once rather than throwing on the first, because a person who has written a configuration file with three mistakes in it should be told about three mistakes rather than made to discover them one run at a time.

What is not here

A duration in units of time. A run is a number of steps, and the finishing time is the step count times the timestep. The alternative, stopping when the simulated time passes some target, has to round somewhere, and the rounding would decide whether a resumed run took the same number of steps as an uninterrupted one. Section 7 of the implementation plan requires an interrupted run to resume to bitwise-identical state, and a step count is the only way to say what a run is that cannot make that fail.

Enumeration Type Documentation

◆ SolverKind

enum class orrery::sim::SolverKind : std::uint8_t
strong

Which force solver computes the accelerations.

The two GPU entries are accepted by the parser in every build, including one compiled without the SYCL backend, and refused when the run is assembled. That separation is deliberate: a configuration file is a document rather than a program, and it should mean the same thing whatever binary reads it. The alternative, a parser that rejects the word sycl-tree in a build without SYCL, would report a spelling mistake for a file that is spelled correctly.

◆ ExecutorKind

enum class orrery::sim::ExecutorKind : std::uint8_t
strong

How the CPU solvers divide their loop over target particles.

A run should use the work-stealing scheduler, which is the default and what Phase 6 measured. The other two are here because a run that reproduces a figure has to be able to ask for the scheme the figure was taken with.

Function Documentation

◆ to_string()

std::string_view orrery::sim::to_string ( SolverKind kind)
nodiscardnoexcept

The spelling each of the above has in a configuration file.

One function per enumeration rather than a template, so that the strings sit beside the values they name and a value added later fails to compile until it has been given a spelling.

◆ parse_solver_kind()

std::optional< SolverKind > orrery::sim::parse_solver_kind ( std::string_view text)
nodiscardnoexcept

The inverse of the above, empty for a word that names nothing.

Paired with to_string in the same file and tested for round-tripping, because a spelling that can be written and not read back is a configuration file this project produces and cannot consume.

◆ problems_with()

std::vector< std::string > orrery::sim::problems_with ( const Configuration & configuration)
nodiscard

Every objection to configuration, in the order the fields appear.

Empty for a configuration that can be run. Each message names the setting in the spelling the file uses, so that the report can be read beside the document that caused it.

This is a separate step from parsing because the two answer different questions. The parser decides whether the file is a configuration; this decides whether the configuration is a run. A file with steps = -1 in it fails the first and a file with steps = 0 fails neither, but neither is worth starting.

◆ resolved_scale_radius()

core::Real orrery::sim::resolved_scale_radius ( const InitialConditionSettings & settings)
nodiscardnoexcept

The scale radius the Plummer sampler will actually use.

Zero in the settings means the standard N-body value. Writing that value as a default member initialiser would make initial_conditions/plummer.hpp an include of this header and so of everything that mentions a configuration, which is a heavy way to spell one constant and would put a sampler on the include path of the command-line parser. Resolving it in one function instead keeps this header inert data and keeps the parser, the validator and the assembly from each having their own idea of what an unset scale radius means.