Enhanced deserialisation¶
This is how a basic JSON input file for Tudat looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | {
"initialEpoch": 0,
"finalEpoch": 3600,
"spice": {
"useStandardKernels": true
},
"bodies": {
"Earth": {
"useDefaultSettings": true,
"ephemeris": {
"type": "constant",
"constantState": [0, 0, 0, 0, 0, 0]
}
},
"asterix": {
"initialState": {
"type": "keplerian",
"semiMajorAxis": 7.5E+6,
"eccentricity": 0.1,
"inclination": 1.4888
}
}
},
"propagators": [
{
"integratedStateType": "translational",
"bodiesToPropagate": ["asterix"],
"centralBodies": ["Earth"],
"accelerations": {
"asterix": {
"Earth": [
{
"type": "pointMassGravity"
}
]
}
}
}
],
"integrator": {
"type": "rungeKutta4",
"stepSize": 10
},
"export": [
{
"file": "@path(epochs.txt)",
"variables": [
{
"type": "independent"
}
],
"epochsInFirstColumn": false
},
{
"file": "@path(states.txt)",
"variables": [
{
"type": "state"
}
],
"epochsInFirstColumn": false
}
],
"options": {
"defaultValueUsedForMissingKey": "continueSilently",
"unusedKey": "printWarning"
}
}
|
The nlohmann::json
object created by parsing the contents of this file, referred to as mainJson
, is used throughout the examples in this tutorial to explain the features that have been added to the JSON Interface regarding Enhanced deserialisation, Enhanced value access and Enhanced value set.
Modular files¶
The JSON Interface library introduces a set of functions that can be used to parse modular JSON files. A modular JSON file is a JSON file in which special syntax is used to include (parts of) other JSON files (see Modular files). The following definitions are introduced:
- Declaration file: file in which a JSON key and corresponding value are defined.
- Parent file: file from which the declaration file is directly referenced.
- Root file: file provided as input argument to the
json_interface
application.
The function void parseModularJSON( nlohman::json& jsonObject, const boost::filesystem::path& filePath, ... )
declared in Tudat/JsonInterface/Support/deserialization.h
can be used to parse a modular JSON file. This function combines recursively the contents of all the files referenced from jsonObject
obtained by parsing filePath
, and updates the jsonObject
(passed by reference).
Each of the referenced JSON files is parsed individually using the function nlohmann::json readJSON( const boost::filesystem::path& filePath, ... )
declared in Tudat/JsonInterface/Support/deserialization.h
. In addition to parsing the contents of the file at filePath
using the nlohmann::json::parse
function, this function adds the following features:
- If the file to be parsed contains a syntax error (i.e. invalid JSON syntax), the
nlohmann::json::parse
throws an error indicating the byte in which the syntax error is found. ThereadJSON
catches this error and uses this information to throw an error indicating the line and column of the syntax error.- The file paths in the input file(s) are made relative to the root file’s directory. To do so, we have to indicate that a given string represents a relative path by using the syntax
"@path(pathRelativeToDeclarationFile)"
which will be replaced to"pathRelativeToRootFile"
.- The following substrings found inside any JSON string are replaced during run-time by:
${FILE_DIR}
: absolute path of the directory where the declaration file is located.${FILE_STEM}
: filename (without extension) of the declaration file.${FILE_NAME}
: filename (with extension) of the declaration file.${PARENT_FILE_DIR}
: absolute path of the directory where the parent file is located.${PARENT_FILE_STEM}
: filename (without extension) of the parent file.${PARENT_FILE_NAME}
: filename (with extension) of the parent file.${ROOT_FILE_DIR}
: absolute path of the directory where the root file is located.${ROOT_FILE_STEM}
: filename (without extension) of the root file.${ROOT_FILE_NAME}
: filename (with extension) of the root file.
Mergeable files¶
In addition to modular JSON files, in which the content of (part of) other JSON files is included, the json_interace
also introduces support for mergeable JSON files (see Multi-case simulations). Since the json_interface
application expects a root JSON file containing an object, when providing a root JSON file containing an array, the contents of this array can be merged to generate a single JSON object to be used to set up the simulation. For instance, the following input file:
[
"$(main.json)",
{
"bodies.asterix.initialState.eccentricity": 0
}
]
can be merged leading to a JSON object identical to the one that would have been obtained by parsing main.json
, but with the initial eccentricty of the body asterix
set to 0
. The file must be first de-modularized (by replacing "$(main.json)"
by an object retrieved from that file) and then merged, by (re-)defining the keys indicated in the second element of the array with the corresponding values. Thus, the returned nlohmann::json
has value type object. Note that the following file would not result in the same merged nlohmann::json
object:
[
"$(main.json)",
{
"bodies": {
"asterix": {
"initialState": {
"eccentricity": 0
}
}
}
}
]
since this would re-define the key bodies of main.json
to be an object containing only one element (the body asterix
) whose only property would be an initialState
with an eccentricity
set to 0
.
In order to merge a nlohmann::json
of value type array into a one of value type object, the function void mergeJSON( nlohmann::json& jsonObject, const boost::filesystem::path& filePath )
declared in Tudat/JsonInterface/Support/deserialization.h
is used. If the passed jsonObject
is not of value type array, this function does nothing.
Full deserialisation sequence¶
All the features described previously are combined into the function nlohmann::json getDeserializedJSON( const boost::filesystem::path& filePath )
declared in Tudat/JsonInterface/Support/deserialization.h
. This function replaces relative paths, combines modular files and merges objects when possible. This is the function that should be called when creating a nlohmann::json
object to be used to set up a simulation. In general, this function is only called once during the life-cycle of the application.
When testing individual parts of the JSON Interface library, the input nlohmann::json
object is not necessarily of value type object, and thus this function cannot be used, as the expected object may be of value type array. Thus, in Unit testing, modular and mergeable JSON files are not used and the function parseJSON
is used instead. In practice, for non-modular files, the only thing this function does is replacing strings such as "@path(text)"
by "text"
.
Note
Immediately before or after parsing a JSON input file (using either getDeserializedJSON
or parseJSON
), the current working directory must be changed to the root input file’s directory using boost::filesystem::current_path( rootFile.parent_path( ) )
, so that the relative paths defined in the obtained nlohmann::json
are valid.