|
Orrery
A GPU-accelerated N-body gravitational simulator
|
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< SolverKind > | orrery::sim::parse_solver_kind (std::string_view text) noexcept |
| The inverse of the above, empty for a word that names nothing. | |
| std::optional< IntegratorKind > | orrery::sim::parse_integrator_kind (std::string_view text) noexcept |
| std::optional< InitialConditionKind > | orrery::sim::parse_initial_condition_kind (std::string_view text) noexcept |
| std::optional< ExecutorKind > | orrery::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. | |
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.
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.