Enhanced value set¶
In the previous section, the enhanced value access functionality has been introduced. This functionality allows the user to easily validate their input JSON files by providing comprehensible error messages in case non-defaultable properties are missing or the provided values are not convertible to the expected type. This was achieved by using KeyPath
s, special keys and the getValue
function.
However, there is nothing like a setValue
function, and KeyPath
s are not used in to_json
functions. This is so because there is no need for validation when converting Tudat objects to JSON. If the process is not successful, it will be the developer’s fault and not the user’s. Additionally, although it is not always possible to access an arbitrary key, since it may be undefined, it is always possible to define any arbitrary key for a nlohmann::json
object.
Nonetheless, there are a few functions provided by the json_interface
that can make the writing of to_json
functions easier, namely:
void assignIfNotNaN( nlohmann::json& j, const std::string& key, const EquatableType& value )
: updates or definesj[ key ]
only ifvalue == value
(this comparison returnsfalse
forTUDAT_NAN
). Can only be used when the comparison operator is defined forEquatableType
.void assignIfNotNull( nlohmann::json& j, const std::string& key, const boost::shared_ptr< T >& object )
: updates or definesj[ key ]
only ifobject != NULL
.void assignIfNotEmpty( nlohmann::json& j, const std::string& key, const ContainerType& container )
: updates or definesj[ key ]
only ifobject.empty( ) == false
. Can only be used when the methodempty
is defined forContainerType
.
Note that the following is not possible:
nlohmann::json mainJson;
KeyPath keyPath = "integrator" / "type";
mainJson[ keyPath ] = "rungeKutta4"; // compile error
mainJson[ "integrator.type" ] = "rungeKutta4"; // wrong! {"integrator.type":"rungeKutta4"}
Instead, the default basic value set methods have to be used:
nlohmann::json mainJson;
mainJson[ "integrator" ][ "type" ] = "rungeKutta4";
If one wants to use the properties of a given object to update the keys of a nlohmann::json
object that is above in the key tree, e.g.:
inline void to_json( nlohmann::json& j, const Integrator& integrator )
{
j[ "type" ] = integrator.type;
j[ "stepSize" ] = integrator.stepSize;
j[ "<-" / "initialEpoch" ] = integrator.initialTime; // compile error
}
this is not possible (yet). This kind of implementation is required only once in the whole JSON Interface library, when converting a Simulation
object to nlohmann::json
, as the information contained in the propagator settings is stored in three different places in the simulation object (part of its information is stored in the key propagators of the mainJson
, the termination settings are stored in the key termination of the mainJson
, and the print interval is stored in the options.printInterval key path of the mainJson
). To do so, the following implementation was chosen (code has been simplified):
void to_json( nlohmann::json& mainJson, const Simulation& simulation )
{
...
mainJson[ "integrator" ] = simulation.integrator;
...
propagators::to_json( mainJson, simulation.propagator );
}
namespace propagators
{
void to_json( nlohmann::json& mainJson, const Propagator& propagator )
{
mainJson[ "propagators" ][ 0 ][ "type" ] = propagator.type;
mainJson[ "propagators" ][ 0 ][ "centralBodies" ] = propagator.centralBodies;
...
mainJson[ "termination" ] = propagator.terminationSettings;
mainJson[ "options" ][ "printInterval" ] = propagator.printInterval;
}
}
This is the only case in which a to_json
function is manually called in the JSON Interface library. Note that, when passed to the to_json
function, the mainJson
object is not re-initialised, so the keys defined before this function call are kept.