Skip to content

Commit

Permalink
Improve JSON I/O for celer-g4/sim apps (celeritas-project#1045)
Browse files Browse the repository at this point in the history
* Write optional arguments from celer-sim as "null"
* Fix ORANGE version reading
* Add to_string(Version)
* Save Celeritas version and format to celer-sim IO output
* Add json utils for helper functions and version save/load
* Update IO to use JSON utils
* Change default JSON output filename and support writing to stdout
* Save and check version for celer-g4
* Detect and exit early on unknown option
  • Loading branch information
sethrj committed Dec 5, 2023
1 parent 8d085a6 commit d42f872
Show file tree
Hide file tree
Showing 14 changed files with 286 additions and 116 deletions.
10 changes: 4 additions & 6 deletions app/celer-g4/GlobalSetup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,14 @@ void GlobalSetup::ReadInput(std::string const& filename)
{
if (ends_with(filename, ".json"))
{
#if CELERITAS_USE_JSON
using std::to_string;

CELER_LOG(status) << "Reading JSON input from '" << filename << "'";
std::ifstream infile(filename);
CELER_VALIDATE(infile, << "failed to open '" << filename << "'");
#if CELERITAS_USE_JSON
nlohmann::json::parse(infile).get_to(input_);
#else
CELER_NOT_CONFIGURED("nlohmann_json");
#endif

// Input options
if (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE)
Expand All @@ -146,9 +147,6 @@ void GlobalSetup::ReadInput(std::string const& filename)
options_->cuda_heap_size = input_.cuda_heap_size;
options_->sync = input_.sync;
options_->default_stream = input_.default_stream;
#else
CELER_NOT_CONFIGURED("nlohmann_json");
#endif
}
else if (ends_with(filename, ".mac"))
{
Expand Down
29 changes: 14 additions & 15 deletions app/celer-g4/RunInputIO.json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "RunInputIO.json.hh"

#include "corecel/cont/ArrayIO.json.hh"
#include "corecel/io/JsonUtils.json.hh"
#include "corecel/io/Logger.hh"
#include "corecel/io/StringEnumMapper.hh"
#include "corecel/sys/Environment.hh"
Expand Down Expand Up @@ -54,13 +55,11 @@ void to_json(nlohmann::json& j, SensitiveDetectorType const& value)
*/
void from_json(nlohmann::json const& j, RunInput& v)
{
#define RI_LOAD_OPTION(NAME) \
do \
{ \
if (j.contains(#NAME)) \
j.at(#NAME).get_to(v.NAME); \
} while (0)
#define RI_LOAD_REQUIRED(NAME) j.at(#NAME).get_to(v.NAME)
#define RI_LOAD_OPTION(NAME) CELER_JSON_LOAD_OPTION(j, v, NAME)
#define RI_LOAD_REQUIRED(NAME) CELER_JSON_LOAD_REQUIRED(j, v, NAME)

// Check version (if available)
check_format(j, "celer-g4");

RI_LOAD_REQUIRED(geometry_file);
RI_LOAD_OPTION(event_file);
Expand Down Expand Up @@ -119,7 +118,7 @@ void from_json(nlohmann::json const& j, RunInput& v)
#undef RI_LOAD_OPTION
#undef RI_LOAD_REQUIRED

CELER_VALIDATE(v.event_file.empty() != !v.primary_options,
CELER_VALIDATE(v.event_file.empty() == static_cast<bool>(v.primary_options),
<< "either a HepMC3 filename or options to generate "
"primaries must be provided (but not both)");
CELER_VALIDATE(v.physics_list == PhysicsListSelection::geant_physics_list
Expand All @@ -138,15 +137,15 @@ void from_json(nlohmann::json const& j, RunInput& v)
*/
void to_json(nlohmann::json& j, RunInput const& v)
{
#define RI_SAVE_OPTION(NAME) \
CELER_JSON_SAVE_WHEN(j, v, NAME, v.NAME != default_args.NAME)
#define RI_SAVE(NAME) CELER_JSON_SAVE(j, v, NAME)

j = nlohmann::json::object();
RunInput const default_args;
#define RI_SAVE_OPTION(NAME) \
do \
{ \
if (!(v.NAME == default_args.NAME)) \
j[#NAME] = v.NAME; \
} while (0)
#define RI_SAVE(NAME) j[#NAME] = v.NAME

// Save version and format type
save_format(j, "celer-g4");

RI_SAVE(geometry_file);
RI_SAVE_OPTION(event_file);
Expand Down
6 changes: 6 additions & 0 deletions app/celer-g4/celer-g4.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
#endif
}
if (celeritas::starts_with(filename, "--"))
{
CELER_LOG(critical) << "Unknown option \"" << filename << "\"";
celeritas::app::print_usage(argv[0]);
return EXIT_FAILURE;
}

// Create params, which need to be shared with detectors as well as
// initialization, and can be written for output
Expand Down
107 changes: 44 additions & 63 deletions app/celer-sim/RunnerInputIO.json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#include <string>

#include "corecel/cont/ArrayIO.json.hh"
#include "corecel/io/JsonUtils.json.hh"
#include "corecel/io/LabelIO.json.hh"
#include "corecel/io/Logger.hh"
#include "corecel/io/StringEnumMapper.hh"
#include "corecel/io/StringUtils.hh"
#include "corecel/sys/EnvironmentIO.json.hh"
Expand Down Expand Up @@ -52,23 +52,13 @@ namespace app
*/
void from_json(nlohmann::json const& j, RunnerInput& v)
{
#define LDIO_LOAD_OPTION(NAME) \
do \
{ \
if (j.contains(#NAME)) \
j.at(#NAME).get_to(v.NAME); \
} while (0)
#define LDIO_LOAD_DEPRECATED(OLD, NEW) \
do \
{ \
if (j.contains(#OLD)) \
{ \
CELER_LOG(warning) << "Deprecated option '" << #OLD << "': use '" \
<< #NEW << "' instead"; \
j.at(#OLD).get_to(v.NEW); \
} \
} while (0)
#define LDIO_LOAD_REQUIRED(NAME) j.at(#NAME).get_to(v.NAME)
#define LDIO_LOAD_REQUIRED(NAME) CELER_JSON_LOAD_REQUIRED(j, v, NAME)
#define LDIO_LOAD_OPTION(NAME) CELER_JSON_LOAD_OPTION(j, v, NAME)
#define LDIO_LOAD_DEPRECATED(OLD, NEW) \
CELER_JSON_LOAD_DEPRECATED(j, v, OLD, NEW)

// Check version (if available)
check_format(j, "celer-sim");

LDIO_LOAD_OPTION(cuda_heap_size);
LDIO_LOAD_OPTION(cuda_stack_size);
Expand Down Expand Up @@ -127,6 +117,7 @@ void from_json(nlohmann::json const& j, RunnerInput& v)
LDIO_LOAD_OPTION(track_order);
LDIO_LOAD_OPTION(physics_options);

#undef LDIO_LOAD_DEPRECATED
#undef LDIO_LOAD_OPTION
#undef LDIO_LOAD_REQUIRED

Expand All @@ -148,70 +139,60 @@ void from_json(nlohmann::json const& j, RunnerInput& v)
*/
void to_json(nlohmann::json& j, RunnerInput const& v)
{
#define LDIO_SAVE(NAME) CELER_JSON_SAVE(j, v, NAME)
#define LDIO_SAVE_WHEN(NAME, COND) CELER_JSON_SAVE_WHEN(j, v, NAME, COND)
#define LDIO_SAVE_OPTION(NAME) \
LDIO_SAVE_WHEN(NAME, v.NAME != default_args.NAME)

j = nlohmann::json::object();
RunnerInput const default_args;
//! Save if not unspecified or if applicable
#define LDIO_SAVE_OPTION(NAME) \
do \
{ \
if (v.NAME != default_args.NAME) \
j[#NAME] = v.NAME; \
} while (0)
//! Always save
#define LDIO_SAVE_REQUIRED(NAME) j[#NAME] = v.NAME

// Save version and celer-sim format
save_format(j, "celer-sim");

LDIO_SAVE_OPTION(cuda_heap_size);
LDIO_SAVE_OPTION(cuda_stack_size);
LDIO_SAVE_REQUIRED(environ);
LDIO_SAVE(environ);

LDIO_SAVE_REQUIRED(geometry_file);
LDIO_SAVE_REQUIRED(physics_file);
LDIO_SAVE(geometry_file);
LDIO_SAVE(physics_file);
LDIO_SAVE_OPTION(event_file);
if (v.event_file.empty())
{
LDIO_SAVE_REQUIRED(primary_options);
}
LDIO_SAVE_WHEN(primary_options, v.event_file.empty());

LDIO_SAVE_OPTION(mctruth_file);
if (!v.mctruth_file.empty())
{
LDIO_SAVE_REQUIRED(mctruth_filter);
}
LDIO_SAVE_OPTION(simple_calo);
LDIO_SAVE_OPTION(action_diagnostic);
LDIO_SAVE_OPTION(step_diagnostic);
LDIO_SAVE_WHEN(mctruth_filter, !v.mctruth_file.empty());
LDIO_SAVE(simple_calo);
LDIO_SAVE(action_diagnostic);
LDIO_SAVE(step_diagnostic);
LDIO_SAVE_OPTION(step_diagnostic_bins);
LDIO_SAVE_OPTION(write_track_counts);
LDIO_SAVE(write_track_counts);

LDIO_SAVE_REQUIRED(seed);
LDIO_SAVE_REQUIRED(num_track_slots);
LDIO_SAVE(seed);
LDIO_SAVE(num_track_slots);
LDIO_SAVE_OPTION(max_steps);
LDIO_SAVE_REQUIRED(initializer_capacity);
LDIO_SAVE_REQUIRED(max_events);
LDIO_SAVE_REQUIRED(secondary_stack_factor);
LDIO_SAVE_REQUIRED(use_device);
LDIO_SAVE_REQUIRED(sync);
LDIO_SAVE_REQUIRED(merge_events);
LDIO_SAVE_REQUIRED(default_stream);
LDIO_SAVE_REQUIRED(warm_up);
LDIO_SAVE(initializer_capacity);
LDIO_SAVE(max_events);
LDIO_SAVE(secondary_stack_factor);
LDIO_SAVE(use_device);
LDIO_SAVE(sync);
LDIO_SAVE(merge_events);
LDIO_SAVE(default_stream);
LDIO_SAVE(warm_up);

LDIO_SAVE_OPTION(field);
if (v.field != RunnerInput::no_field())
{
LDIO_SAVE_REQUIRED(field_options);
}
LDIO_SAVE_WHEN(field_options, v.field != RunnerInput::no_field());

LDIO_SAVE_OPTION(step_limiter);
LDIO_SAVE_REQUIRED(brem_combined);
LDIO_SAVE(brem_combined);

LDIO_SAVE_REQUIRED(track_order);
if (v.physics_file.empty() || !ends_with(v.physics_file, ".root"))
{
LDIO_SAVE_REQUIRED(physics_options);
}
LDIO_SAVE(track_order);
LDIO_SAVE_WHEN(physics_options,
v.physics_file.empty()
|| !ends_with(v.physics_file, ".root"));

#undef LDIO_SAVE_OPTION
#undef LDIO_SAVE_REQUIRED
#undef LDIO_SAVE_WHEN
#undef LDIO_SAVE
}

//---------------------------------------------------------------------------//
Expand Down
1 change: 1 addition & 0 deletions app/celer-sim/simple-driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def strtobool(text):
'default_stream': False,
'brem_combined': True,
'physics_options': physics_options,
'field': None,
}

with open(f'{run_name}.inp.json', 'w') as f:
Expand Down
28 changes: 20 additions & 8 deletions src/accel/SharedParams.cc
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ void SharedParams::try_output() const
if (CELERITAS_USE_JSON && !params_ && filename.empty())
{
// Setup was not called but JSON is available: make a default filename
filename = "celeritas.json";
filename = "celeritas.out.json";
CELER_LOG(debug) << "Set default Celeritas output filename";
}

Expand All @@ -619,13 +619,25 @@ void SharedParams::try_output() const

if (CELERITAS_USE_JSON)
{
CELER_LOG(info) << "Writing Geant4 diagnostic output to \"" << filename
<< '"';

std::ofstream outf(filename);
CELER_VALIDATE(
outf, << "failed to open output file at \"" << filename << '"');
output_reg_->output(&outf);
auto msg = CELER_LOG(info);
msg << "Wrote Geant4 diagnostic output to ";
std::ofstream outf;
std::ostream* os{nullptr};
if (filename == "-")
{
os = &std::cout;
msg << "<stdout>";
}
else
{
os = &outf;
outf.open(filename);
CELER_VALIDATE(
outf, << "failed to open output file at \"" << filename << '"');
msg << '"' << filename << '"';
}
CELER_ASSERT(os);
output_reg_->output(os);
}
else
{
Expand Down
14 changes: 7 additions & 7 deletions src/celeritas/ext/GeantPhysicsOptionsIO.json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <string>

#include "corecel/io/JsonUtils.json.hh"
#include "corecel/io/StringEnumMapper.hh"
#include "corecel/math/QuantityIO.json.hh"

Expand Down Expand Up @@ -62,13 +63,10 @@ void to_json(nlohmann::json& j, RelaxationSelection const& value)
*/
void from_json(nlohmann::json const& j, GeantPhysicsOptions& options)
{
#define GPO_LOAD_OPTION(NAME) CELER_JSON_LOAD_OPTION(j, options, NAME)

options = {};
#define GPO_LOAD_OPTION(NAME) \
do \
{ \
if (j.contains(#NAME)) \
j.at(#NAME).get_to(options.NAME); \
} while (0)

GPO_LOAD_OPTION(coulomb_scattering);
GPO_LOAD_OPTION(compton_scattering);
GPO_LOAD_OPTION(photoelectric);
Expand Down Expand Up @@ -108,8 +106,10 @@ void from_json(nlohmann::json const& j, GeantPhysicsOptions& options)
*/
void to_json(nlohmann::json& j, GeantPhysicsOptions const& options)
{
#define GPO_SAVE_OPTION(NAME) CELER_JSON_SAVE(j, options, NAME)

j = nlohmann::json::object();
#define GPO_SAVE_OPTION(NAME) j[#NAME] = options.NAME

GPO_SAVE_OPTION(coulomb_scattering);
GPO_SAVE_OPTION(compton_scattering);
GPO_SAVE_OPTION(photoelectric);
Expand Down
20 changes: 7 additions & 13 deletions src/celeritas/user/RootStepWriterIO.json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include <string>

#include "corecel/io/JsonUtils.json.hh"

#include "RootStepWriter.hh"

namespace celeritas
Expand All @@ -19,12 +21,7 @@ namespace celeritas
*/
void from_json(nlohmann::json const& j, SimpleRootFilterInput& options)
{
#define SRFI_LOAD_OPTION(NAME) \
do \
{ \
if (j.contains(#NAME)) \
j.at(#NAME).get_to(options.NAME); \
} while (0)
#define SRFI_LOAD_OPTION(NAME) CELER_JSON_LOAD_OPTION(j, options, NAME)
SRFI_LOAD_OPTION(track_id);
SRFI_LOAD_OPTION(event_id);
SRFI_LOAD_OPTION(parent_id);
Expand All @@ -38,13 +35,10 @@ void from_json(nlohmann::json const& j, SimpleRootFilterInput& options)
*/
void to_json(nlohmann::json& j, SimpleRootFilterInput const& options)
{
j["track_id"] = options.track_id;
#define SRFI_SAVE_OPTION(NAME) \
do \
{ \
if (options.NAME != options.unspecified) \
j[#NAME] = options.NAME; \
} while (0)
#define SRFI_SAVE_OPTION(NAME) \
CELER_JSON_SAVE_WHEN(j, options, NAME, options.NAME != options.unspecified)

CELER_JSON_SAVE(j, options, track_id);
SRFI_SAVE_OPTION(event_id);
SRFI_SAVE_OPTION(parent_id);
SRFI_SAVE_OPTION(action_id);
Expand Down
1 change: 1 addition & 0 deletions src/corecel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ endif()
if(CELERITAS_USE_JSON)
list(APPEND SOURCES
AssertIO.json.cc
io/JsonUtils.json.cc
sys/DeviceIO.json.cc
sys/KernelRegistryIO.json.cc
sys/MemRegistryIO.json.cc
Expand Down

0 comments on commit d42f872

Please sign in to comment.