JSON input for standalone apps¶
Celeritas standalone applications such as celer-sim and celer-optical
accept structured JSON input based on the celeritas::inp data structures.
The Input documents the underlying C++ types; this page explains how
those types are represented in JSON and gives minimal working examples.
JSON encoding conventions¶
Structs¶
A C++ struct is represented as a JSON object with matching field names.
For example, a struct like:
struct Timers
{
bool action{false};
bool step{false};
};
becomes a JSON object where the keys have the same names as the members:
{
"action": false,
"step": false
}
Arrays, maps, and sets¶
std::vector<T> and celeritas::Array<T> values become JSON arrays.
std::unordered_set<T> values become JSON arrays of unique values, and
std::map<K, V> values become JSON objects.
Enums¶
Celeritas enumerations are encoded in JSON as strings rather than integer values.
For example, the C++ enumeration
enum class InterpolationType
{
linear,
poly_spline,
cubic_spline,
size_
};
is represented in JSON using the corresponding string values: "linear",
"poly_spline", and "cubic_spline". A field InterpolationType type
whose value is InterpolationType::linear in JSON becomes:
{
"type": "linear"
}
Optional values¶
Fields with type std::optional<T> support several different JSON behaviors:
If the field is omitted, the existing value is unchanged. This allows the containing input structure to define a custom default value.
If the field is set to
null, the optional is reset tostd::nullopt.If the field is set to a non-null value, the optional is initialized to the given value.
If the field is set to
{}, the optional is initialized with a default-constructedT.
For example, omitting the optional device field in the System
input preserves the existing value supplied by the containing structure (i.e.,
the device remains disabled):
{
"system": {}
}
Setting the field to null explicitly clears the optional value (i.e.,
disables the device):
{
"system": {
"device": null
}
}
Setting the field to an object initializes the optional and reads the nested value (i.e., enables the device with custom stack and heap sizes):
{
"system": {
"device": {
"stack_size": 1024,
"heap_size": 8192
}
}
}
Setting the field to an empty object initializes the optional with the contained type’s default (i.e., enables the device with the default stack and heap size):
{
"system": {
"device": {}
}
}
This means omission and {} are not equivalent: omission preserves the value
that was already present, while {} replaces it with an initialized contained
object using default values.
Variants¶
Many Celeritas input types are std::variant objects. In JSON, these are
encoded as objects with a required _type field that identifies the selected
alternative.
For example, the Field input type is defined as:
using Field = std::variant<NoField,
UniformField,
RZMapField,
CylMapField,
CartMapField>;
A C++ value such as
inp::Field field = inp::NoField{};
is represented in JSON as:
{
"_type": "none"
}
Similarly, a uniform magnetic field can be specified in C++ as:
inp::Field field = [] {
inp::UniformField result;
result.strength = {0.0, 0.0, 1.0};
return result;
}();
and in JSON as:
{
"_type": "uniform",
"strength": [0.0, 0.0, 1.0]
}
The _type field selects the variant alternative, and the remaining fields
specify the data for that alternative. The _type value does not necessarily
match the C++ type name. Refer to the documented string values for the variant
being encoded.
See Example: encoding inp::Events in JSON for an example combining several variant-valued fields.
Example: encoding inp::Events in JSON¶
The inp::Events input type is a useful example of Celeritas JSON encoding
because it combines several common patterns in one place.
A C++ setup constructing a primary generator for celer-sim might look like:
inp::Events events = [] {
inp::CorePrimaryGenerator result;
result.shape = inp::PointDistribution{{0.0, 0.0, 0.0}};
result.angle = inp::IsotropicDistribution{};
result.energy = inp::MonoenergeticDistribution{10.0};
result.num_events = 1;
result.primaries_per_event = 10000;
result.pdg = {PDGNumber{11}};
}();
events.merge = false;
In JSON, this is represented as:
{
"generator": {
"_type": "primary",
"shape": {
"_type": "delta",
"value": [0.0, 0.0, 0.0]
},
"angle": {
"_type": "isotropic"
},
"energy": {
"_type": "delta",
"value": 10.0
},
"num_events": 1,
"primaries_per_event": 10000,
"pdg": [11]
},
"merge": false
}
This example illustrates several of the JSON encoding conventions used by Celeritas:
generatoris astd::variantand is encoded with a_typefield.shape,angle, andenergyare also variants and each uses its own_typefield.The
pdgvector is encoded as a JSON array.Scalar fields such as
num_eventsandmergeare encoded directly as JSON numbers and booleans.