From 4e3aee15e08fd3810d197ce067d9387afd3696a8 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 3 Jan 2025 19:20:18 -0500 Subject: [PATCH 01/30] Don't pass output manager into celer-sim runner This means it's more difficult to get the processed input if there's an error, but it makes the structure easier. --- app/celer-sim/Runner.cc | 9 +++------ app/celer-sim/Runner.hh | 10 +++++----- app/celer-sim/celer-sim.cc | 33 ++++++++++++++++++++++----------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index d9510375e4..bb052e8c81 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -119,12 +119,10 @@ size_type calc_num_streams(RunnerInput const& inp, size_type num_events) /*! * Construct on all threads from a JSON input and shared output manager. */ -Runner::Runner(RunnerInput const& inp, SPOutputRegistry output) +Runner::Runner(RunnerInput const& inp) { using SPImporter = std::shared_ptr; - CELER_EXPECT(output); - this->setup_globals(inp); // Possible Geant4 world volume so we can reuse geometry @@ -152,7 +150,7 @@ Runner::Runner(RunnerInput const& inp, SPOutputRegistry output) auto const imported = (*import)(); ScopedRootErrorHandler scoped_root_error; - this->build_core_params(inp, std::move(output), g4world, imported); + this->build_core_params(inp, g4world, imported); this->build_diagnostics(inp); this->build_step_collectors(inp); this->build_optical_collector(inp, imported); @@ -278,7 +276,6 @@ void Runner::setup_globals(RunnerInput const& inp) const * Construct core parameters. */ void Runner::build_core_params(RunnerInput const& inp, - SPOutputRegistry&& outreg, G4VPhysicalVolume const* g4world, ImportData const& imported) { @@ -289,7 +286,7 @@ void Runner::build_core_params(RunnerInput const& inp, // Create action manager params.action_reg = std::make_shared(); - params.output_reg = std::move(outreg); + params.output_reg = std::make_shared(); // Load geometry: use existing world volume or reload from geometry file params.geometry = [&geo_file = inp.geometry_file, g4world] { diff --git a/app/celer-sim/Runner.hh b/app/celer-sim/Runner.hh index 8cc2ebc362..3c434ab634 100644 --- a/app/celer-sim/Runner.hh +++ b/app/celer-sim/Runner.hh @@ -24,7 +24,6 @@ namespace celeritas { class CoreParams; class OpticalCollector; -class OutputRegistry; class ParticleParams; class RootFileManager; class StepCollector; @@ -49,12 +48,11 @@ class Runner using Input = RunnerInput; using MapStrDouble = std::unordered_map; using RunnerResult = TransporterResult; - using SPOutputRegistry = std::shared_ptr; //!@} public: - // Construct on all threads from a JSON input and shared output manager - Runner(RunnerInput const& inp, SPOutputRegistry output); + // Construct on all threads from a parsed JSON input + Runner(RunnerInput const& inp); // Warm up by running a single step with no active tracks void warm_up(); @@ -74,6 +72,9 @@ class Runner // Get the accumulated action times MapStrDouble get_action_times() const; + // Access core params + CoreParams const& core_params() const { return *core_params_; } + private: //// TYPES //// @@ -99,7 +100,6 @@ class Runner void setup_globals(RunnerInput const&) const; void build_core_params(RunnerInput const&, - SPOutputRegistry&&, G4VPhysicalVolume const*, ImportData const&); void build_step_collectors(RunnerInput const&); diff --git a/app/celer-sim/celer-sim.cc b/app/celer-sim/celer-sim.cc index eca3e47f73..aa98a8a4dc 100644 --- a/app/celer-sim/celer-sim.cc +++ b/app/celer-sim/celer-sim.cc @@ -40,6 +40,7 @@ #include "corecel/sys/Stopwatch.hh" #include "corecel/sys/TracingSession.hh" #include "celeritas/Types.hh" +#include "celeritas/global/CoreParams.hh" #include "Runner.hh" #include "RunnerInput.hh" @@ -69,9 +70,9 @@ int get_openmp_thread() //---------------------------------------------------------------------------// /*! - * Run, launch, and output. + * Run, launch, and get output. */ -void run(std::istream* is, std::shared_ptr output) +std::shared_ptr run(std::istream* is) { CELER_EXPECT(is); ScopedMem record_mem("celer-sim.run"); @@ -79,8 +80,6 @@ void run(std::istream* is, std::shared_ptr output) // Read input options and save a copy for output auto run_input = std::make_shared(); nlohmann::json::parse(*is).get_to(*run_input); - output->insert(std::make_shared>( - OutputInterface::Category::input, "*", run_input)); // Start profiling TracingSession tracing_session{run_input->tracing_file}; @@ -89,13 +88,17 @@ void run(std::istream* is, std::shared_ptr output) // Create runner and save setup time Stopwatch get_setup_time; - Runner run_stream(*run_input, output); + Runner run_stream(*run_input); SimulationResult result; result.setup_time = get_setup_time(); - if (run_input->transporter_result) - { - result.events.resize(run_stream.num_events()); - } + result.events.resize( + run_input->transporter_result ? run_stream.num_events() : 1); + + // Add processed input to resulting output + auto output = run_stream.core_params().output_reg(); + CELER_ASSERT(output); + output->insert(std::make_shared>( + OutputInterface::Category::input, "*", run_input)); // Allocate device streams, or use the default stream if there is only one. size_type num_streams = run_stream.num_streams(); @@ -155,6 +158,8 @@ void run(std::istream* is, std::shared_ptr output) result.total_time = get_transport_time(); record_mem = {}; output->insert(std::make_shared(std::move(result))); + + return output; } //---------------------------------------------------------------------------// @@ -255,24 +260,30 @@ int main(int argc, char* argv[]) } // Set up output - auto output = std::make_shared(); + std::shared_ptr output; int return_code = EXIT_SUCCESS; try { - celeritas::app::run(instream, output); + output = celeritas::app::run(instream); + CELER_ASSERT(output); } catch (std::exception const& e) { CELER_LOG(critical) << "While running input at " << filename << ": " << e.what(); return_code = EXIT_FAILURE; + if (!output) + { + output = std::make_shared(); + } output->insert(std::make_shared( std::current_exception())); } // Write system properties and (if available) results CELER_LOG(status) << "Saving output"; + CELER_ASSERT(output); output->output(&cout); cout << endl; From 3ab6b82e719f336402b5a40cf72d6411264bbb51 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Sat, 4 Jan 2025 19:24:35 -0500 Subject: [PATCH 02/30] Move validation to main .cc from JSON reading --- app/celer-g4/GlobalSetup.cc | 5 +++++ app/celer-g4/RunInputIO.json.cc | 21 ++++++++------------- app/celer-sim/Runner.cc | 7 +++++++ app/celer-sim/RunnerInputIO.json.cc | 6 ------ 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/celer-g4/GlobalSetup.cc b/app/celer-g4/GlobalSetup.cc index 6ea8e6a3c9..014d2f0d8f 100644 --- a/app/celer-g4/GlobalSetup.cc +++ b/app/celer-g4/GlobalSetup.cc @@ -132,6 +132,11 @@ void GlobalSetup::ReadInput(std::string const& filename) CELER_ASSERT(instream); nlohmann::json::parse(*instream).get_to(input_); + CELER_VALIDATE(input_.event_file.empty() + == static_cast(input_.primary_options), + << "either a HepMC3 filename or options to generate " + "primaries must be provided (but not both)"); + if (input_.cuda_stack_size != RunInput::unspecified) { options_->cuda_stack_size = input_.cuda_stack_size; diff --git a/app/celer-g4/RunInputIO.json.cc b/app/celer-g4/RunInputIO.json.cc index 4bf4c3eabc..0cf64790b3 100644 --- a/app/celer-g4/RunInputIO.json.cc +++ b/app/celer-g4/RunInputIO.json.cc @@ -144,19 +144,14 @@ void from_json(nlohmann::json const& j, RunInput& v) #undef RI_LOAD_OPTION #undef RI_LOAD_REQUIRED - - // TODO: move these validation checks to GlobalSetup - CELER_VALIDATE(v.event_file.empty() == static_cast(v.primary_options), - << "either a HepMC3 filename or options to generate " - "primaries must be provided (but not both)"); - CELER_VALIDATE(v.physics_list != PhysicsListSelection::ftfp_bert - || !j.contains("physics_options"), - << "'physics_options' can only be specified for " - "'celer_ftfp_bert' or 'celer_em'"); - CELER_VALIDATE((v.field != RunInput::no_field() || v.field_type == "rzmap") - || !j.contains("field_options"), - << "'field_options' cannot be specified without providing " - "'field'"); + CELER_VALIDATE( + v.physics_list != PhysicsListSelection::ftfp_bert + || !j.contains("physics_options"), + << R"('physics_options' can only be specified for 'celer_ftfp_bert' or 'celer_em')"); + CELER_VALIDATE( + (v.field != RunInput::no_field() || v.field_type == "rzmap") + || !j.contains("field_options"), + << R"('field_options' cannot be specified without providing 'field')"); } //---------------------------------------------------------------------------// diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index bb052e8c81..69a1212ec9 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -121,6 +121,13 @@ size_type calc_num_streams(RunnerInput const& inp, size_type num_events) */ Runner::Runner(RunnerInput const& inp) { + CELER_VALIDATE(inp.event_file.empty() != !inp.primary_options, + << "either a event filename or options to generate " + "primaries must be provided (but not both)"); + CELER_VALIDATE(!inp.mctruth_filter || !inp.mctruth_file.empty(), + << "'mctruth_filter' cannot be specified without providing " + "'mctruth_file'"); + using SPImporter = std::shared_ptr; this->setup_globals(inp); diff --git a/app/celer-sim/RunnerInputIO.json.cc b/app/celer-sim/RunnerInputIO.json.cc index 37020713d6..42d5242a13 100644 --- a/app/celer-sim/RunnerInputIO.json.cc +++ b/app/celer-sim/RunnerInputIO.json.cc @@ -128,12 +128,6 @@ void from_json(nlohmann::json const& j, RunnerInput& v) #undef LDIO_LOAD_OPTION #undef LDIO_LOAD_REQUIRED - CELER_VALIDATE(v.event_file.empty() != !v.primary_options, - << "either a event filename or options to generate " - "primaries must be provided (but not both)"); - CELER_VALIDATE(!v.mctruth_filter || !v.mctruth_file.empty(), - << "'mctruth_filter' cannot be specified without providing " - "'mctruth_file'"); CELER_VALIDATE(v.field != RunnerInput::no_field() || !j.contains("field_options"), << "'field_options' cannot be specified without providing " From 137c2c4834b83f233a16b4249c4f80e401e9f7c8 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 24 Jan 2025 11:48:37 -0800 Subject: [PATCH 03/30] Fix `Overload` to work with references in addition to rvalue refs --- src/corecel/cont/VariantUtils.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/corecel/cont/VariantUtils.hh b/src/corecel/cont/VariantUtils.hh index 8a78b5075f..3c80144269 100644 --- a/src/corecel/cont/VariantUtils.hh +++ b/src/corecel/cont/VariantUtils.hh @@ -32,10 +32,13 @@ struct Overload : Ts... using Ts::operator()...; }; -// Template deduction guide +// Template deduction guides template Overload(Ts&&...) -> Overload; +template +Overload(Ts&...) -> Overload; + //---------------------------------------------------------------------------// /*! * Create a wrapper functor for unifying the return type. From 7f4d80459404dad5505159497966bf64e11fc156 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 24 Jan 2025 11:50:39 -0800 Subject: [PATCH 04/30] Move ROOT core output to celeritas --- app/celer-sim/CMakeLists.txt | 4 --- app/celer-sim/Runner.cc | 3 +- .../celeritas/io/RootCoreParamsOutput.cc | 35 +++---------------- .../celeritas/io/RootCoreParamsOutput.hh | 30 ++++------------ 4 files changed, 12 insertions(+), 60 deletions(-) rename app/celer-sim/RootOutput.cc => src/celeritas/io/RootCoreParamsOutput.cc (64%) rename app/celer-sim/RootOutput.hh => src/celeritas/io/RootCoreParamsOutput.hh (52%) diff --git a/app/celer-sim/CMakeLists.txt b/app/celer-sim/CMakeLists.txt index e411d2bc59..a7d2dd1c6b 100644 --- a/app/celer-sim/CMakeLists.txt +++ b/app/celer-sim/CMakeLists.txt @@ -23,10 +23,6 @@ endif() if(CELERITAS_USE_OpenMP) list(APPEND LIBRARIES OpenMP::OpenMP_CXX) endif() -if(CELERITAS_USE_ROOT) - list(APPEND SOURCES RootOutput.cc) - list(APPEND LIBRARIES ROOT::Core ROOT::Tree) -endif() # Add the executable celeritas_add_executable(celer-sim ${SOURCES}) diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index 69a1212ec9..7da8cb5ef2 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -44,6 +44,7 @@ #include "celeritas/geo/GeoParams.hh" // IWYU pragma: keep #include "celeritas/global/CoreParams.hh" #include "celeritas/io/EventReader.hh" +#include "celeritas/io/RootCoreParamsOutput.hh" #include "celeritas/io/RootEventReader.hh" #include "celeritas/mat/MaterialParams.hh" #include "celeritas/optical/CherenkovParams.hh" @@ -70,7 +71,6 @@ #include "celeritas/user/StepData.hh" #include "celeritas/user/StepDiagnostic.hh" -#include "RootOutput.hh" #include "RunnerInput.hh" #include "Transporter.hh" @@ -166,7 +166,6 @@ Runner::Runner(RunnerInput const& inp) if (root_manager_) { - write_to_root(inp, root_manager_.get()); write_to_root(*core_params_, root_manager_.get()); } diff --git a/app/celer-sim/RootOutput.cc b/src/celeritas/io/RootCoreParamsOutput.cc similarity index 64% rename from app/celer-sim/RootOutput.cc rename to src/celeritas/io/RootCoreParamsOutput.cc index 839b45271a..90f5569da2 100644 --- a/app/celer-sim/RootOutput.cc +++ b/src/celeritas/io/RootCoreParamsOutput.cc @@ -2,43 +2,20 @@ // Copyright Celeritas contributors: see top-level COPYRIGHT file for details // SPDX-License-Identifier: (Apache-2.0 OR MIT) //---------------------------------------------------------------------------// -//! \file celer-sim/RootOutput.cc +//! \file celeritas/io/RootCoreParamsOutput.cc //---------------------------------------------------------------------------// -#include "RootOutput.hh" +#include "RootCoreParamsOutput.hh" #include #include #include #include "corecel/sys/ActionRegistry.hh" -#include "celeritas/ext/GeantPhysicsOptionsIO.json.hh" -#include "celeritas/global/CoreParams.hh" -#include "RunnerInput.hh" -#include "RunnerInputIO.json.hh" +#include "RootFileManager.hh" namespace celeritas { -namespace app -{ -//---------------------------------------------------------------------------// -/*! - * Store input information to the ROOT MC truth output file. - */ -void write_to_root(RunnerInput const& cargs, RootFileManager* root_manager) -{ - CELER_EXPECT(cargs); - CELER_EXPECT(root_manager); - - std::string str_input(nlohmann::json(cargs).dump()); - std::string str_phys(nlohmann::json(cargs.physics_options).dump()); - - auto tree_input = root_manager->make_tree("input", "input"); - tree_input->Branch("input", &str_input); - tree_input->Branch("physics_options", &str_phys); - tree_input->Fill(); // Writing happens at destruction -} - //---------------------------------------------------------------------------// /*! * Store CoreParams data to the ROOT MC truth output file. @@ -48,10 +25,9 @@ void write_to_root(RunnerInput const& cargs, RootFileManager* root_manager) * other parameters are needed for future debugging/analyses, this function can * easily be expanded. */ -void write_to_root(CoreParams const& core_params, RootFileManager* root_manager) +void write_to_root(ActionRegistry const& action_reg, + RootFileManager* root_manager) { - auto const& action_reg = *core_params.action_reg(); - // Initialize CoreParams TTree auto tree_params = root_manager->make_tree("core_params", "core_params"); @@ -77,5 +53,4 @@ void write_to_root(CoreParams const& core_params, RootFileManager* root_manager) } //---------------------------------------------------------------------------// -} // namespace app } // namespace celeritas diff --git a/app/celer-sim/RootOutput.hh b/src/celeritas/io/RootCoreParamsOutput.hh similarity index 52% rename from app/celer-sim/RootOutput.hh rename to src/celeritas/io/RootCoreParamsOutput.hh index db35450712..98cdb599a1 100644 --- a/app/celer-sim/RootOutput.hh +++ b/src/celeritas/io/RootCoreParamsOutput.hh @@ -2,7 +2,7 @@ // Copyright Celeritas contributors: see top-level COPYRIGHT file for details // SPDX-License-Identifier: (Apache-2.0 OR MIT) //---------------------------------------------------------------------------// -//! \file celer-sim/RootOutput.hh +//! \file celeritas/io/RootCoreParamsOutput.hh //---------------------------------------------------------------------------// #pragma once @@ -12,42 +12,24 @@ namespace celeritas { -//---------------------------------------------------------------------------// -class CoreParams; +class ActionRegistry; class RootFileManager; -//---------------------------------------------------------------------------// -} // namespace celeritas +struct GeantPhysicsOptions; -namespace celeritas -{ -namespace app -{ //---------------------------------------------------------------------------// -struct RunnerInput; -//---------------------------------------------------------------------------// - -// Store RunnerInput to ROOT file when ROOT is available -void write_to_root(RunnerInput const& cargs, RootFileManager* root_manager); - -// Store CoreParams to ROOT file when ROOT is available -void write_to_root(CoreParams const& core_params, +// Store actions to ROOT file +void write_to_root(ActionRegistry const& actions, RootFileManager* root_manager); //---------------------------------------------------------------------------// #if !CELERITAS_USE_ROOT -inline void write_to_root(RunnerInput const&, RootFileManager*) -{ - CELER_NOT_CONFIGURED("ROOT"); -} - -inline void write_to_root(CoreParams const&, RootFileManager*) +inline void write_to_root(ActionRegistry const&, RootFileManager*) { CELER_NOT_CONFIGURED("ROOT"); } #endif //---------------------------------------------------------------------------// -} // namespace app } // namespace celeritas From 3fb329f844daaff5635d725b4b78739f7c4b5e52 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 24 Jan 2025 12:00:25 -0800 Subject: [PATCH 05/30] Split runner functions --- app/celer-sim/Runner.cc | 433 --------------------------------- app/celer-sim/Runner.hh | 9 - app/celer-sim/RunnerInput.cc | 27 +- src/celeritas/setup/Events.cc | 78 ++++++ src/celeritas/setup/Problem.cc | 333 +++++++++++++++++++++++++ 5 files changed, 436 insertions(+), 444 deletions(-) create mode 100644 src/celeritas/setup/Events.cc create mode 100644 src/celeritas/setup/Problem.cc diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index 7da8cb5ef2..f87b3ef143 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -78,43 +78,6 @@ namespace celeritas { namespace app { -namespace -{ -//---------------------------------------------------------------------------// -/*! - * Get the number of streams from the number of OpenMP threads. - * - * The OMP_NUM_THREADS environment variable can be used to control the number - * of threads/streams. The value of OMP_NUM_THREADS should be a list of - * positive integers, each of which sets the number of threads for the parallel - * region at the corresponding nested level. The number of streams is set to - * the first value in the list. If OMP_NUM_THREADS is not set, the value will - * be implementation defined. - */ -size_type calc_num_streams(RunnerInput const& inp, size_type num_events) -{ - size_type num_threads = 1; -#if CELERITAS_OPENMP == CELERITAS_OPENMP_EVENT - if (!inp.merge_events) - { -# pragma omp parallel - { - if (omp_get_thread_num() == 0) - { - num_threads = omp_get_num_threads(); - } - } - } -#else - CELER_DISCARD(inp); -#endif - // Don't create more streams than events - return std::min(num_threads, num_events); -} - -//---------------------------------------------------------------------------// -} // namespace - //---------------------------------------------------------------------------// /*! * Construct on all threads from a JSON input and shared output manager. @@ -130,8 +93,6 @@ Runner::Runner(RunnerInput const& inp) using SPImporter = std::shared_ptr; - this->setup_globals(inp); - // Possible Geant4 world volume so we can reuse geometry G4VPhysicalVolume const* g4world{nullptr}; @@ -157,18 +118,8 @@ Runner::Runner(RunnerInput const& inp) auto const imported = (*import)(); ScopedRootErrorHandler scoped_root_error; - this->build_core_params(inp, g4world, imported); - this->build_diagnostics(inp); - this->build_step_collectors(inp); - this->build_optical_collector(inp, imported); - this->build_transporter_input(inp); use_device_ = inp.use_device; - if (root_manager_) - { - write_to_root(*core_params_, root_manager_.get()); - } - transporters_.resize(this->num_streams()); CELER_ENSURE(core_params_); } @@ -263,215 +214,6 @@ auto Runner::get_action_times() const -> MapStrDouble return result; } -//---------------------------------------------------------------------------// -void Runner::setup_globals(RunnerInput const& inp) const -{ - if (inp.cuda_heap_size != RunnerInput::unspecified) - { - set_cuda_heap_size(inp.cuda_heap_size); - } - if (inp.cuda_stack_size != RunnerInput::unspecified) - { - set_cuda_stack_size(inp.cuda_stack_size); - } - environment().merge(inp.environ); -} - -//---------------------------------------------------------------------------// -/*! - * Construct core parameters. - */ -void Runner::build_core_params(RunnerInput const& inp, - G4VPhysicalVolume const* g4world, - ImportData const& imported) -{ - CELER_LOG(status) << "Loading input and initializing problem data"; - ScopedMem record_mem("Runner.build_core_params"); - ScopedProfiling profile_this{"construct-params"}; - CoreParams::Input params; - - // Create action manager - params.action_reg = std::make_shared(); - params.output_reg = std::make_shared(); - - // Load geometry: use existing world volume or reload from geometry file - params.geometry = [&geo_file = inp.geometry_file, g4world] { - if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) - { - static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; - auto const& filename = celeritas::getenv(fi_hack_envname); - if (!filename.empty()) - { - CELER_LOG(warning) - << "Using a temporary, unsupported, and dangerous hack to " - "override the ORANGE geometry file: " - << fi_hack_envname << "='" << filename << "'"; - return std::make_shared(filename); - } - } - if (g4world) - { - return std::make_shared(g4world); - } - return std::make_shared(geo_file); - }(); - - if (!params.geometry->supports_safety()) - { - CELER_LOG(warning) << "Geometry contains surfaces that are " - "incompatible with the current ORANGE simple " - "safety algorithm: multiple scattering may " - "result in arbitrarily small steps"; - } - - // Load materials - params.material = MaterialParams::from_import(imported); - - // Create geometry/material coupling - params.geomaterial = GeoMaterialParams::from_import( - imported, params.geometry, params.material); - - // Construct particle params - params.particle = ParticleParams::from_import(imported); - - // Construct cutoffs - params.cutoff = CutoffParams::from_import( - imported, params.particle, params.material); - - // Construct shared data for Coulomb scattering - params.wentzel = WentzelOKVIParams::from_import( - imported, params.material, params.particle); - - // Load physics: create individual processes with make_shared - params.physics = [¶ms, &inp, &imported] { - PhysicsParams::Input input; - input.particles = params.particle; - input.materials = params.material; - input.action_registry = params.action_reg.get(); - - // Set physics options - input.options.fixed_step_limiter = inp.step_limiter; - input.options.secondary_stack_factor = inp.secondary_stack_factor; - input.options.spline_eloss_order = inp.spline_eloss_order; - input.options.linear_loss_limit = imported.em_params.linear_loss_limit; - input.options.light.lowest_energy = ParticleOptions::Energy( - imported.em_params.lowest_electron_energy); - input.options.heavy.lowest_energy - = ParticleOptions::Energy(imported.em_params.lowest_muhad_energy); - - // Set multiple scattering options - input.options.light.range_factor = imported.em_params.msc_range_factor; - input.options.heavy.range_factor - = imported.em_params.msc_muhad_range_factor; - input.options.safety_factor = imported.em_params.msc_safety_factor; - input.options.lambda_limit = imported.em_params.msc_lambda_limit; - input.options.light.displaced = imported.em_params.msc_displaced; - input.options.heavy.displaced = imported.em_params.msc_muhad_displaced; - input.options.light.step_limit_algorithm - = imported.em_params.msc_step_algorithm; - input.options.heavy.step_limit_algorithm - = imported.em_params.msc_muhad_step_algorithm; - - // Build processes - input.processes = [¶ms, &inp, &imported] { - std::vector> result; - ProcessBuilder::Options opts; - opts.brem_combined = inp.brem_combined; - opts.brems_selection = inp.physics_options.brems; - - ProcessBuilder build_process( - imported, params.particle, params.material, opts); - for (auto p : - ProcessBuilder::get_all_process_classes(imported.processes)) - { - result.push_back(build_process(p)); - CELER_ASSERT(result.back()); - } - return result; - }(); - - return std::make_shared(std::move(input)); - }(); - - bool eloss = imported.em_params.energy_loss_fluct; - auto msc = UrbanMscParams::from_import( - *params.particle, *params.material, imported); - if (inp.field == RunnerInput::no_field()) - { - // Create along-step action - auto along_step = AlongStepGeneralLinearAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - msc, - eloss); - params.action_reg->insert(along_step); - } - else - { - UniformFieldParams field_params; - field_params.field = inp.field; - field_params.options = inp.field_options; - - // Interpret input in units of Tesla - for (real_type& v : field_params.field) - { - v = native_value_from(units::FieldTesla{v}); - } - - auto along_step = AlongStepUniformMscAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - field_params, - msc, - eloss); - CELER_ASSERT(along_step->field() != RunnerInput::no_field()); - params.action_reg->insert(along_step); - } - - // Construct RNG params - params.rng = std::make_shared(inp.seed); - - // Construct simulation params - params.sim = std::make_shared([&] { - // TODO: use max_steps here instead of as step iteration? - auto input = SimParams::Input::from_import( - imported, params.particle, inp.field_options.max_substeps); - return input; - }()); - - // Get the total number of events - auto num_events = this->build_events(inp, params.particle); - - // Store the number of simultaneous threads/tasks per process - params.max_streams = calc_num_streams(inp, num_events); - CELER_VALIDATE(inp.mctruth_file.empty() || params.max_streams == 1, - << "cannot output MC truth with multiple " - "streams (" - << params.max_streams << " requested)"); - - // Store number of tracks per stream - CELER_VALIDATE(inp.num_track_slots > 0, - << "nonpositive num_track_slots=" << inp.num_track_slots); - params.tracks_per_stream - = ceil_div(inp.num_track_slots, params.max_streams); - - // Construct track initialization params - params.init = [&inp, ¶ms, num_events] { - CELER_VALIDATE(inp.initializer_capacity > 0, - << "nonpositive initializer_capacity=" - << inp.initializer_capacity); - TrackInitParams::Input input; - input.capacity = ceil_div(inp.initializer_capacity, params.max_streams); - input.max_events = num_events; - input.track_order = inp.track_order; - return std::make_shared(std::move(input)); - }(); - - core_params_ = std::make_shared(std::move(params)); -} - //---------------------------------------------------------------------------// /*! * Construct transporter input parameters. @@ -490,181 +232,6 @@ void Runner::build_transporter_input(RunnerInput const& inp) transporter_input_->log_progress = inp.log_progress; } -//---------------------------------------------------------------------------// -/*! - * Read events from a file or build using a primary generator. - * - * This returns the total number of events. - */ -size_type -Runner::build_events(RunnerInput const& inp, SPConstParticles particles) -{ - ScopedMem record_mem("Runner.build_events"); - - if (inp.merge_events) - { - // All events will be transported simultaneously on a single stream - events_.resize(1); - } - - auto read_events = [&](auto&& generate) { - auto event = generate(); - while (!event.empty()) - { - if (inp.merge_events) - { - events_.front().insert( - events_.front().end(), event.begin(), event.end()); - } - else - { - events_.push_back(event); - } - event = generate(); - } - return generate.num_events(); - }; - - if (inp.primary_options) - { - return read_events( - PrimaryGenerator::from_options(particles, inp.primary_options)); - } - else if (ends_with(inp.event_file, ".root")) - { - if (inp.file_sampling_options) - { - // Sampling options are assigned; use ROOT event sampler - return read_events( - RootEventSampler(inp.event_file, - particles, - inp.file_sampling_options.num_events, - inp.file_sampling_options.num_merged, - inp.seed)); - } - else - { - // Use event reader - return read_events(RootEventReader(inp.event_file, particles)); - } - } - else - { - // Assume filename is one of the HepMC3-supported extensions - return read_events(EventReader(inp.event_file, particles)); - } -} - -//---------------------------------------------------------------------------// -/*! - * Construct on all threads from a JSON input and shared output manager. - */ -void Runner::build_step_collectors(RunnerInput const& inp) -{ - StepCollector::VecInterface step_interfaces; - if (!inp.mctruth_file.empty()) - { - // Initialize ROOT file - root_manager_ - = std::make_shared(inp.mctruth_file.c_str()); - - // Create root step writer - step_interfaces.push_back(std::make_shared( - root_manager_, - core_params_->particle(), - StepSelection::all(), - make_write_filter(inp.mctruth_filter))); - } - - if (!inp.simple_calo.empty()) - { - auto simple_calo - = std::make_shared(inp.simple_calo, - *core_params_->geometry(), - core_params_->max_streams()); - - // Add to step interfaces - step_interfaces.push_back(simple_calo); - // Add to output interface - core_params_->output_reg()->insert(simple_calo); - } - - if (!step_interfaces.empty()) - { - step_collector_ = std::make_unique( - core_params_->geometry(), - std::move(step_interfaces), - core_params_->aux_reg().get(), - core_params_->action_reg().get()); - } -} - -//---------------------------------------------------------------------------// -/*! - * Construct optical collector. - * - * \pre Must be called after \c build_core_params . - */ -void Runner::build_optical_collector(RunnerInput const& inp, - ImportData const& imported) -{ - CELER_EXPECT(core_params_); - - using optical::CherenkovParams; - using optical::MaterialParams; - using optical::ScintillationParams; - - //! \todo Update conditionals after implementing CelerOpticalPhysicsList - if (imported.optical_materials.empty()) - { - // No optical materials are present - return; - } - CELER_ASSERT(inp.optical); - - size_type num_streams = core_params_->max_streams(); - - OpticalCollector::Input oc_inp; - oc_inp.material = MaterialParams::from_import( - imported, *core_params_->geomaterial(), *core_params_->material()); - oc_inp.cherenkov = std::make_shared(*oc_inp.material); - oc_inp.scintillation - = ScintillationParams::from_import(imported, core_params_->particle()); - oc_inp.num_track_slots = ceil_div(inp.optical.num_track_slots, num_streams); - oc_inp.buffer_capacity = ceil_div(inp.optical.buffer_capacity, num_streams); - oc_inp.initializer_capacity - = ceil_div(inp.optical.initializer_capacity, num_streams); - oc_inp.auto_flush = ceil_div(inp.optical.auto_flush, num_streams); - - CELER_ASSERT(oc_inp); - optical_collector_ - = std::make_shared(*core_params_, std::move(oc_inp)); -} - -//---------------------------------------------------------------------------// -/*! - * Construct diagnostic actions/outputs. - */ -void Runner::build_diagnostics(RunnerInput const& inp) -{ - if (inp.action_diagnostic) - { - ActionDiagnostic::make_and_insert(*core_params_); - } - - if (inp.step_diagnostic) - { - StepDiagnostic::make_and_insert(*core_params_, - inp.step_diagnostic_bins); - } - - if (!inp.slot_diagnostic_prefix.empty()) - { - SlotDiagnostic::make_and_insert(*core_params_, - inp.slot_diagnostic_prefix); - } -} - //---------------------------------------------------------------------------// /*! * Get the transporter for the given stream, constructing if necessary. diff --git a/app/celer-sim/Runner.hh b/app/celer-sim/Runner.hh index 3c434ab634..7d9eab8e2e 100644 --- a/app/celer-sim/Runner.hh +++ b/app/celer-sim/Runner.hh @@ -88,7 +88,6 @@ class Runner std::shared_ptr core_params_; std::shared_ptr root_manager_; std::shared_ptr step_collector_; - std::shared_ptr optical_collector_; // Transporter inputs and stream-local transporters bool use_device_{}; @@ -98,15 +97,7 @@ class Runner //// HELPER FUNCTIONS //// - void setup_globals(RunnerInput const&) const; - void build_core_params(RunnerInput const&, - G4VPhysicalVolume const*, - ImportData const&); - void build_step_collectors(RunnerInput const&); - void build_optical_collector(RunnerInput const&, ImportData const&); - void build_diagnostics(RunnerInput const&); void build_transporter_input(RunnerInput const&); - size_type build_events(RunnerInput const&, SPConstParticles); TransporterBase& get_transporter(StreamId); TransporterBase const* get_transporter_ptr(StreamId) const; }; diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 5fdb4abb76..b73b8c5599 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -7,6 +7,9 @@ #include "RunnerInput.hh" #include +#ifdef _OPENMP +# include +#endif #include "celeritas/field/FieldDriverOptions.hh" #include "celeritas/inp/Import.hh" @@ -109,8 +112,28 @@ inp::Problem load_problem(RunnerInput const& ri) p.control.warm_up = ri.warm_up; p.control.seed = ri.seed; - // TODO: set number of streams - p.control.num_streams = 1; +/*! + * Get the number of streams from the number of OpenMP threads. + * + * The OMP_NUM_THREADS environment variable can be used to control the number + * of threads/streams. The value of OMP_NUM_THREADS should be a list of + * positive integers, each of which sets the number of threads for the parallel + * region at the corresponding nested level. The number of streams is set to + * the first value in the list. If OMP_NUM_THREADS is not set, the value will + * be implementation defined. + */ +#if CELERITAS_OPENMP == CELERITAS_OPENMP_EVENT + if (!ri.merge_events) + { +# pragma omp parallel + { + if (omp_get_thread_num() == 0) + { + p.control.num_streams = omp_get_num_threads(); + } + } + } +#endif if (ri.use_device) { diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc new file mode 100644 index 0000000000..ee5033f822 --- /dev/null +++ b/src/celeritas/setup/Events.cc @@ -0,0 +1,78 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/Events.cc +//---------------------------------------------------------------------------// + +namespace celeritas +{ +namespace setup +{ +//---------------------------------------------------------------------------// +/*! + * Read events from a file or build using a primary generator. + * + * This returns the total number of events. + */ +size_type +Runner::build_events(RunnerInput const& inp, SPConstParticles particles) +{ + ScopedMem record_mem("Runner.build_events"); + + if (inp.merge_events) + { + // All events will be transported simultaneously on a single stream + events_.resize(1); + } + + auto read_events = [&](auto&& generate) { + auto event = generate(); + while (!event.empty()) + { + if (inp.merge_events) + { + events_.front().insert( + events_.front().end(), event.begin(), event.end()); + } + else + { + events_.push_back(event); + } + event = generate(); + } + return generate.num_events(); + }; + + if (inp.primary_options) + { + return read_events( + PrimaryGenerator::from_options(particles, inp.primary_options)); + } + else if (ends_with(inp.event_file, ".root")) + { + if (inp.file_sampling_options) + { + // Sampling options are assigned; use ROOT event sampler + return read_events( + RootEventSampler(inp.event_file, + particles, + inp.file_sampling_options.num_events, + inp.file_sampling_options.num_merged, + inp.seed)); + } + else + { + // Use event reader + return read_events(RootEventReader(inp.event_file, particles)); + } + } + else + { + // Assume filename is one of the HepMC3-supported extensions + return read_events(EventReader(inp.event_file, particles)); + } +} + +} // namespace setup +} // namespace celeritas diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc new file mode 100644 index 0000000000..d091373e4c --- /dev/null +++ b/src/celeritas/setup/Problem.cc @@ -0,0 +1,333 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/Problem.cc +//---------------------------------------------------------------------------// + +namespace celeritas +{ +namespace setup +{ +//---------------------------------------------------------------------------// +void Runner::setup_globals(RunnerInput const& inp) const +{ + if (inp.cuda_heap_size != RunnerInput::unspecified) + { + set_cuda_heap_size(inp.cuda_heap_size); + } + if (inp.cuda_stack_size != RunnerInput::unspecified) + { + set_cuda_stack_size(inp.cuda_stack_size); + } + environment().merge(inp.environ); +} + +//---------------------------------------------------------------------------// +/*! + * Construct core parameters. + */ +void Runner::build_core_params(RunnerInput const& inp, + G4VPhysicalVolume const* g4world, + ImportData const& imported) +{ + CELER_LOG(status) << "Loading input and initializing problem data"; + ScopedMem record_mem("Runner.build_core_params"); + ScopedProfiling profile_this{"construct-params"}; + CoreParams::Input params; + + // Create action manager + params.action_reg = std::make_shared(); + params.output_reg = std::make_shared(); + + // Load geometry: use existing world volume or reload from geometry file + params.geometry = [&geo_file = inp.geometry_file, g4world] { + if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) + { + static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; + auto const& filename = celeritas::getenv(fi_hack_envname); + if (!filename.empty()) + { + CELER_LOG(warning) + << "Using a temporary, unsupported, and dangerous hack to " + "override the ORANGE geometry file: " + << fi_hack_envname << "='" << filename << "'"; + return std::make_shared(filename); + } + } + if (g4world) + { + return std::make_shared(g4world); + } + return std::make_shared(geo_file); + }(); + + if (!params.geometry->supports_safety()) + { + CELER_LOG(warning) << "Geometry contains surfaces that are " + "incompatible with the current ORANGE simple " + "safety algorithm: multiple scattering may " + "result in arbitrarily small steps"; + } + + // Load materials + params.material = MaterialParams::from_import(imported); + + // Create geometry/material coupling + params.geomaterial = GeoMaterialParams::from_import( + imported, params.geometry, params.material); + + // Construct particle params + params.particle = ParticleParams::from_import(imported); + + // Construct cutoffs + params.cutoff = CutoffParams::from_import( + imported, params.particle, params.material); + + // Construct shared data for Coulomb scattering + params.wentzel = WentzelOKVIParams::from_import( + imported, params.material, params.particle); + + // Load physics: create individual processes with make_shared + params.physics = [¶ms, &inp, &imported] { + PhysicsParams::Input input; + input.particles = params.particle; + input.materials = params.material; + input.action_registry = params.action_reg.get(); + + // Set physics options + input.options.fixed_step_limiter = inp.step_limiter; + input.options.secondary_stack_factor = inp.secondary_stack_factor; + input.options.spline_eloss_order = inp.spline_eloss_order; + input.options.linear_loss_limit = imported.em_params.linear_loss_limit; + input.options.light.lowest_energy = ParticleOptions::Energy( + imported.em_params.lowest_electron_energy); + input.options.heavy.lowest_energy + = ParticleOptions::Energy(imported.em_params.lowest_muhad_energy); + + // Set multiple scattering options + input.options.light.range_factor = imported.em_params.msc_range_factor; + input.options.heavy.range_factor + = imported.em_params.msc_muhad_range_factor; + input.options.safety_factor = imported.em_params.msc_safety_factor; + input.options.lambda_limit = imported.em_params.msc_lambda_limit; + input.options.light.displaced = imported.em_params.msc_displaced; + input.options.heavy.displaced = imported.em_params.msc_muhad_displaced; + input.options.light.step_limit_algorithm + = imported.em_params.msc_step_algorithm; + input.options.heavy.step_limit_algorithm + = imported.em_params.msc_muhad_step_algorithm; + + // Build processes + input.processes = [¶ms, &inp, &imported] { + std::vector> result; + ProcessBuilder::Options opts; + opts.brem_combined = inp.brem_combined; + opts.brems_selection = inp.physics_options.brems; + + ProcessBuilder build_process( + imported, params.particle, params.material, opts); + for (auto p : + ProcessBuilder::get_all_process_classes(imported.processes)) + { + result.push_back(build_process(p)); + CELER_ASSERT(result.back()); + } + return result; + }(); + + return std::make_shared(std::move(input)); + }(); + + bool eloss = imported.em_params.energy_loss_fluct; + auto msc = UrbanMscParams::from_import( + *params.particle, *params.material, imported); + if (inp.field == RunnerInput::no_field()) + { + // Create along-step action + auto along_step = AlongStepGeneralLinearAction::from_params( + params.action_reg->next_id(), + *params.material, + *params.particle, + msc, + eloss); + params.action_reg->insert(along_step); + } + else + { + UniformFieldParams field_params; + field_params.field = inp.field; + field_params.options = inp.field_options; + + // Interpret input in units of Tesla + for (real_type& v : field_params.field) + { + v = native_value_from(units::FieldTesla{v}); + } + + auto along_step = AlongStepUniformMscAction::from_params( + params.action_reg->next_id(), + *params.material, + *params.particle, + field_params, + msc, + eloss); + CELER_ASSERT(along_step->field() != RunnerInput::no_field()); + params.action_reg->insert(along_step); + } + + // Construct RNG params + params.rng = std::make_shared(inp.seed); + + // Construct simulation params + params.sim = std::make_shared([&] { + // TODO: use max_steps here instead of as step iteration? + auto input = SimParams::Input::from_import( + imported, params.particle, inp.field_options.max_substeps); + return input; + }()); + + // Get the total number of events + auto num_events = this->build_events(inp, params.particle); + + // Store the number of simultaneous threads/tasks per process + params.max_streams = calc_num_streams(inp, num_events); + CELER_VALIDATE(inp.mctruth_file.empty() || params.max_streams == 1, + << "cannot output MC truth with multiple " + "streams (" + << params.max_streams << " requested)"); + + // Store number of tracks per stream + CELER_VALIDATE(inp.num_track_slots > 0, + << "nonpositive num_track_slots=" << inp.num_track_slots); + params.tracks_per_stream + = ceil_div(inp.num_track_slots, params.max_streams); + + // Construct track initialization params + params.init = [&inp, ¶ms, num_events] { + CELER_VALIDATE(inp.initializer_capacity > 0, + << "nonpositive initializer_capacity=" + << inp.initializer_capacity); + TrackInitParams::Input input; + input.capacity = ceil_div(inp.initializer_capacity, params.max_streams); + input.max_events = num_events; + input.track_order = inp.track_order; + return std::make_shared(std::move(input)); + }(); + + core_params_ = std::make_shared(std::move(params)); +} + +//---------------------------------------------------------------------------// +/*! + * Construct on all threads from a JSON input and shared output manager. + */ +void Runner::build_step_collectors(RunnerInput const& inp) +{ + StepCollector::VecInterface step_interfaces; + if (!inp.mctruth_file.empty()) + { + // Initialize ROOT file + root_manager_ + = std::make_shared(inp.mctruth_file.c_str()); + + // Create root step writer + step_interfaces.push_back(std::make_shared( + root_manager_, + core_params_->particle(), + StepSelection::all(), + make_write_filter(inp.mctruth_filter))); + } + + if (!inp.simple_calo.empty()) + { + auto simple_calo + = std::make_shared(inp.simple_calo, + *core_params_->geometry(), + core_params_->max_streams()); + + // Add to step interfaces + step_interfaces.push_back(simple_calo); + // Add to output interface + core_params_->output_reg()->insert(simple_calo); + } + + if (!step_interfaces.empty()) + { + step_collector_ = std::make_unique( + core_params_->geometry(), + std::move(step_interfaces), + core_params_->aux_reg().get(), + core_params_->action_reg().get()); + } +} + +//---------------------------------------------------------------------------// +/*! + * Construct optical collector. + * + * \pre Must be called after \c build_core_params . + */ +void Runner::build_optical_collector(RunnerInput const& inp, + ImportData const& imported) +{ + CELER_EXPECT(core_params_); + + using optical::CherenkovParams; + using optical::MaterialParams; + using optical::ScintillationParams; + + //! \todo Update conditionals after implementing CelerOpticalPhysicsList + if (imported.optical_materials.empty()) + { + // No optical materials are present + return; + } + CELER_ASSERT(inp.optical); + + size_type num_streams = core_params_->max_streams(); + + OpticalCollector::Input oc_inp; + oc_inp.material = MaterialParams::from_import( + imported, *core_params_->geomaterial(), *core_params_->material()); + oc_inp.cherenkov = std::make_shared(*oc_inp.material); + oc_inp.scintillation + = ScintillationParams::from_import(imported, core_params_->particle()); + oc_inp.num_track_slots = ceil_div(inp.optical.num_track_slots, num_streams); + oc_inp.buffer_capacity = ceil_div(inp.optical.buffer_capacity, num_streams); + oc_inp.initializer_capacity + = ceil_div(inp.optical.initializer_capacity, num_streams); + oc_inp.auto_flush = ceil_div(inp.optical.auto_flush, num_streams); + + CELER_ASSERT(oc_inp); + optical_collector_ + = std::make_shared(*core_params_, std::move(oc_inp)); +} + +//---------------------------------------------------------------------------// +/*! + * Construct diagnostic actions/outputs. + */ +void Runner::build_diagnostics(RunnerInput const& inp) +{ + if (inp.action_diagnostic) + { + ActionDiagnostic::make_and_insert(*core_params_); + } + + if (inp.step_diagnostic) + { + StepDiagnostic::make_and_insert(*core_params_, + inp.step_diagnostic_bins); + } + + if (!inp.slot_diagnostic_prefix.empty()) + { + SlotDiagnostic::make_and_insert(*core_params_, + inp.slot_diagnostic_prefix); + } +} + +//---------------------------------------------------------------------------// +} // namespace setup +} // namespace celeritas From 540534a2ed1dd0b6698d184b63ad93374a37e0ce Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 15 Jan 2025 14:55:31 -0500 Subject: [PATCH 06/30] Core params construction compiles --- src/celeritas/CMakeLists.txt | 2 + src/celeritas/setup/Events.cc | 119 ++++---- src/celeritas/setup/Events.hh | 28 ++ src/celeritas/setup/Problem.cc | 480 ++++++++++++++++++++------------- src/celeritas/setup/Problem.hh | 31 +++ 5 files changed, 414 insertions(+), 246 deletions(-) create mode 100644 src/celeritas/setup/Events.hh create mode 100644 src/celeritas/setup/Problem.hh diff --git a/src/celeritas/CMakeLists.txt b/src/celeritas/CMakeLists.txt index 6e51fe4d91..7e5eb73d98 100644 --- a/src/celeritas/CMakeLists.txt +++ b/src/celeritas/CMakeLists.txt @@ -108,7 +108,9 @@ list(APPEND SOURCES random/CuHipRngParams.cc random/XorwowRngData.cc random/XorwowRngParams.cc + setup/Events.cc setup/Import.cc + setup/Problem.cc setup/System.cc track/SimParams.cc track/SortTracksAction.cc diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc index ee5033f822..ba0584dfcc 100644 --- a/src/celeritas/setup/Events.cc +++ b/src/celeritas/setup/Events.cc @@ -4,75 +4,80 @@ //---------------------------------------------------------------------------// //! \file celeritas/setup/Events.cc //---------------------------------------------------------------------------// +#include "Events.hh" + +#include + +#include "corecel/cont/VariantUtils.hh" +#include "corecel/io/StringUtils.hh" +#include "corecel/sys/ScopedMem.hh" +#include "celeritas/io/EventReader.hh" +#include "celeritas/io/RootEventReader.hh" +#include "celeritas/phys/PrimaryGenerator.hh" +#include "celeritas/phys/RootEventSampler.hh" namespace celeritas { namespace setup { +namespace +{ //---------------------------------------------------------------------------// -/*! - * Read events from a file or build using a primary generator. - * - * This returns the total number of events. - */ -size_type -Runner::build_events(RunnerInput const& inp, SPConstParticles particles) +auto read_events(EventReaderInterface&& generate) { - ScopedMem record_mem("Runner.build_events"); - - if (inp.merge_events) + std::vector> result; + auto event = generate(); + while (!event.empty()) { - // All events will be transported simultaneously on a single stream - events_.resize(1); + result.push_back(event); + event = generate(); } + return result; +} - auto read_events = [&](auto&& generate) { - auto event = generate(); - while (!event.empty()) - { - if (inp.merge_events) - { - events_.front().insert( - events_.front().end(), event.begin(), event.end()); - } - else - { - events_.push_back(event); - } - event = generate(); - } - return generate.num_events(); - }; +//---------------------------------------------------------------------------// +} // namespace - if (inp.primary_options) - { - return read_events( - PrimaryGenerator::from_options(particles, inp.primary_options)); - } - else if (ends_with(inp.event_file, ".root")) - { - if (inp.file_sampling_options) - { - // Sampling options are assigned; use ROOT event sampler - return read_events( - RootEventSampler(inp.event_file, - particles, - inp.file_sampling_options.num_events, - inp.file_sampling_options.num_merged, - inp.seed)); - } - else - { - // Use event reader - return read_events(RootEventReader(inp.event_file, particles)); - } - } - else - { - // Assume filename is one of the HepMC3-supported extensions - return read_events(EventReader(inp.event_file, particles)); - } +//---------------------------------------------------------------------------// +/*! + * Load events from a file. + */ +std::vector> +events(inp::Events const& e, + std::shared_ptr const& particles) +{ + CELER_EXPECT(particles); + ScopedMem record_mem("Runner.build_events"); + + return std::visit( + Overload{ + [&particles](inp::PrimaryGenerator const& pg) { + return read_events(PrimaryGenerator{pg, *particles}); + }, + [&particles](inp::SampleFileEvents const& sfe) { + return read_events(RootEventSampler{sfe.event_file, + particles, + sfe.num_events, + sfe.num_merged, + sfe.seed}); + }, + [&particles](inp::ReadFileEvents const& rfe) { + if (ends_with(rfe.event_file, ".root")) + { + return read_events( + RootEventReader{rfe.event_file, particles}); + } + else + { + // Assume filename is one of the HepMC3-supported + // extensions + return read_events(EventReader{rfe.event_file, particles}); + } + }, + }, + e); } +//---------------------------------------------------------------------------// } // namespace setup } // namespace celeritas diff --git a/src/celeritas/setup/Events.hh b/src/celeritas/setup/Events.hh new file mode 100644 index 0000000000..47da78fb78 --- /dev/null +++ b/src/celeritas/setup/Events.hh @@ -0,0 +1,28 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/Events.hh +//---------------------------------------------------------------------------// +#pragma once + +#include + +#include "celeritas/inp/Events.hh" + +namespace celeritas +{ +struct Primary; +class ParticleParams; + +namespace setup +{ +//---------------------------------------------------------------------------// +// Load events +std::vector> +events(inp::Events const& inp, + std::shared_ptr const& particles); + +//---------------------------------------------------------------------------// +} // namespace setup +} // namespace celeritas diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index d091373e4c..64bb396fcf 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -4,36 +4,114 @@ //---------------------------------------------------------------------------// //! \file celeritas/setup/Problem.cc //---------------------------------------------------------------------------// - +#include "Problem.hh" + +#include "corecel/Assert.hh" +#include "corecel/cont/VariantUtils.hh" +#include "corecel/io/Logger.hh" +#include "corecel/io/OutputRegistry.hh" +#include "corecel/math/Algorithms.hh" +#include "corecel/sys/ActionRegistry.hh" +#include "corecel/sys/Environment.hh" +#include "corecel/sys/ScopedMem.hh" +#include "corecel/sys/ScopedProfiling.hh" +#include "celeritas/Quantities.hh" +#include "celeritas/Types.hh" +#include "celeritas/alongstep/AlongStepGeneralLinearAction.hh" +#include "celeritas/alongstep/AlongStepUniformMscAction.hh" +#include "celeritas/em/params/UrbanMscParams.hh" +#include "celeritas/em/params/WentzelOKVIParams.hh" +#include "celeritas/ext/GeantImporter.hh" +#include "celeritas/ext/GeantSetup.hh" +#include "celeritas/ext/RootFileManager.hh" +#include "celeritas/field/FieldDriverOptions.hh" +#include "celeritas/field/UniformFieldData.hh" +#include "celeritas/geo/GeoMaterialParams.hh" +#include "celeritas/geo/GeoParams.hh" // IWYU pragma: keep +#include "celeritas/global/CoreParams.hh" +#include "celeritas/inp/Model.hh" +#include "celeritas/inp/Problem.hh" +#include "celeritas/io/RootCoreParamsOutput.hh" +#include "celeritas/mat/MaterialParams.hh" +#include "celeritas/optical/CherenkovParams.hh" +#include "celeritas/optical/MaterialParams.hh" +#include "celeritas/optical/OpticalCollector.hh" +#include "celeritas/optical/ScintillationParams.hh" +#include "celeritas/phys/CutoffParams.hh" +#include "celeritas/phys/ParticleParams.hh" +#include "celeritas/phys/PhysicsParams.hh" +#include "celeritas/phys/Process.hh" +#include "celeritas/phys/ProcessBuilder.hh" +#include "celeritas/random/RngParams.hh" +#include "celeritas/track/SimParams.hh" +#include "celeritas/track/TrackInitParams.hh" +#include "celeritas/user/ActionDiagnostic.hh" +#include "celeritas/user/RootStepWriter.hh" +#include "celeritas/user/SimpleCalo.hh" +#include "celeritas/user/SlotDiagnostic.hh" +#include "celeritas/user/StepCollector.hh" +#include "celeritas/user/StepData.hh" +#include "celeritas/user/StepDiagnostic.hh" namespace celeritas { namespace setup { +namespace +{ //---------------------------------------------------------------------------// -void Runner::setup_globals(RunnerInput const& inp) const +std::shared_ptr build_geometry(inp::Model const& m) { - if (inp.cuda_heap_size != RunnerInput::unspecified) - { - set_cuda_heap_size(inp.cuda_heap_size); - } - if (inp.cuda_stack_size != RunnerInput::unspecified) - { - set_cuda_stack_size(inp.cuda_stack_size); - } - environment().merge(inp.environ); + auto build_from_filename + = [](std::string const& filename) -> std::shared_ptr { + CELER_VALIDATE(!filename.empty(), + << "empty filename in problem.model.geometry"); + return std::make_shared(filename); + }; + auto build_from_geant + = [&build_from_filename](G4VPhysicalVolume const* world) { + if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) + { + static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; + auto const& filename = celeritas::getenv(fi_hack_envname); + if (!filename.empty()) + { + CELER_LOG(warning) + << "Using a temporary, unsupported, and dangerous " + "hack to override the ORANGE geometry file: " + << fi_hack_envname << "='" << filename << "'"; + return build_from_filename(filename); + } + } + CELER_VALIDATE( + world, << "null world pointer in problem.model.geometry"); + return std::make_shared(world); + }; + + return std::visit(Overload{build_from_filename, build_from_geant}, + m.geometry); } +//---------------------------------------------------------------------------// +} // namespace + //---------------------------------------------------------------------------// /*! - * Construct core parameters. + * Create "core params" from a problem definition and import data. + * + * Conceivably we could rename "core params" someday. + * + * \todo Consolidate import data into the problem definition. + * \todo Migrate the class "Input"/"Option" code into the class itself, using + * the \c inp namespace definition. */ -void Runner::build_core_params(RunnerInput const& inp, - G4VPhysicalVolume const* g4world, - ImportData const& imported) +std::shared_ptr +problem(inp::Problem const& p, ImportData const& imported) { CELER_LOG(status) << "Loading input and initializing problem data"; + ScopedMem record_mem("Runner.build_core_params"); ScopedProfiling profile_this{"construct-params"}; + CoreParams::Input params; // Create action manager @@ -41,33 +119,15 @@ void Runner::build_core_params(RunnerInput const& inp, params.output_reg = std::make_shared(); // Load geometry: use existing world volume or reload from geometry file - params.geometry = [&geo_file = inp.geometry_file, g4world] { - if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) - { - static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; - auto const& filename = celeritas::getenv(fi_hack_envname); - if (!filename.empty()) - { - CELER_LOG(warning) - << "Using a temporary, unsupported, and dangerous hack to " - "override the ORANGE geometry file: " - << fi_hack_envname << "='" << filename << "'"; - return std::make_shared(filename); - } - } - if (g4world) - { - return std::make_shared(g4world); - } - return std::make_shared(geo_file); - }(); + params.geometry = build_geometry(p.model); if (!params.geometry->supports_safety()) { - CELER_LOG(warning) << "Geometry contains surfaces that are " - "incompatible with the current ORANGE simple " - "safety algorithm: multiple scattering may " - "result in arbitrarily small steps"; + CELER_LOG(warning) + << "Geometry contains surfaces that are " + "incompatible with the current ORANGE simple " + "safety algorithm: multiple scattering may " + "result in arbitrarily small steps without displacement"; } // Load materials @@ -89,16 +149,25 @@ void Runner::build_core_params(RunnerInput const& inp, imported, params.material, params.particle); // Load physics: create individual processes with make_shared - params.physics = [¶ms, &inp, &imported] { + params.physics = [¶ms, p, &imported] { PhysicsParams::Input input; input.particles = params.particle; input.materials = params.material; input.action_registry = params.action_reg.get(); // Set physics options - input.options.fixed_step_limiter = inp.step_limiter; - input.options.secondary_stack_factor = inp.secondary_stack_factor; - input.options.spline_eloss_order = inp.spline_eloss_order; + input.options.fixed_step_limiter = p.tracking.force_step_limit; + if (p.control.capacity.secondaries) + { + input.options.secondary_stack_factor + = *p.control.capacity.secondaries; + } + else + { + // Default: twice the number of track slots + input.options.secondary_stack_factor = 2.0; + } + input.options.spline_eloss_order = p.physics.em->eloss_spline ? 2 : 1; input.options.linear_loss_limit = imported.em_params.linear_loss_limit; input.options.light.lowest_energy = ParticleOptions::Energy( imported.em_params.lowest_electron_energy); @@ -119,18 +188,34 @@ void Runner::build_core_params(RunnerInput const& inp, = imported.em_params.msc_muhad_step_algorithm; // Build processes - input.processes = [¶ms, &inp, &imported] { + CELER_ASSERT(p.physics.em); + input.processes = [¶ms, &em = *p.physics.em, &imported] { + // TODO: process builder should be deleted; instead it should get + // p.physics.em or whatever std::vector> result; ProcessBuilder::Options opts; - opts.brem_combined = inp.brem_combined; - opts.brems_selection = inp.physics_options.brems; + if (em.brems) + { + opts.brem_combined = em.brems->combined_model; + opts.brems_selection = [&brems = *em.brems] { + if (brems.rel && brems.sb) + return BremsModelSelection::all; + else if (brems.rel) + return BremsModelSelection::relativistic; + else if (brems.sb) + return BremsModelSelection::seltzer_berger; + else + return BremsModelSelection::none; + }(); + } + // TODO: add callback for user processes ProcessBuilder build_process( imported, params.particle, params.material, opts); - for (auto p : + for (auto pc : ProcessBuilder::get_all_process_classes(imported.processes)) { - result.push_back(build_process(p)); + result.push_back(build_process(pc)); CELER_ASSERT(result.back()); } return result; @@ -139,193 +224,210 @@ void Runner::build_core_params(RunnerInput const& inp, return std::make_shared(std::move(input)); }(); - bool eloss = imported.em_params.energy_loss_fluct; + bool const eloss = imported.em_params.energy_loss_fluct; auto msc = UrbanMscParams::from_import( *params.particle, *params.material, imported); - if (inp.field == RunnerInput::no_field()) - { - // Create along-step action - auto along_step = AlongStepGeneralLinearAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - msc, - eloss); - params.action_reg->insert(along_step); - } - else - { - UniformFieldParams field_params; - field_params.field = inp.field; - field_params.options = inp.field_options; - - // Interpret input in units of Tesla - for (real_type& v : field_params.field) - { - v = native_value_from(units::FieldTesla{v}); - } - auto along_step = AlongStepUniformMscAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - field_params, - msc, - eloss); - CELER_ASSERT(along_step->field() != RunnerInput::no_field()); - params.action_reg->insert(along_step); - } + CELER_ASSUME(!p.field.valueless_by_exception()); + params.action_reg->insert(std::visit( + return_as>(Overload{ + [&](inp::NoField const&) { + return AlongStepGeneralLinearAction::from_params( + params.action_reg->next_id(), + *params.material, + *params.particle, + msc, + eloss); + }, + [&](inp::UniformField const& field) { + UniformFieldParams field_params; + + if (field.units != UnitSystem::si) + { + CELER_NOT_IMPLEMENTED("field units in other unit systems"); + } + field_params.field = field.strength; + field_params.options = field.driver_options; + + // Interpret input in units of Tesla + for (real_type& v : field_params.field) + { + v = native_value_from(units::FieldTesla{v}); + } + + return AlongStepUniformMscAction::from_params( + params.action_reg->next_id(), + *params.material, + *params.particle, + field_params, + msc, + eloss); + }, + [](inp::RZMapField const&) + -> std::shared_ptr { + CELER_NOT_IMPLEMENTED("building RZ map field through input"); + }, + }), + p.field)); // Construct RNG params - params.rng = std::make_shared(inp.seed); + params.rng = std::make_shared(p.control.seed); // Construct simulation params params.sim = std::make_shared([&] { - // TODO: use max_steps here instead of as step iteration? auto input = SimParams::Input::from_import( - imported, params.particle, inp.field_options.max_substeps); + imported, params.particle, p.control.capacity.events); return input; }()); - // Get the total number of events - auto num_events = this->build_events(inp, params.particle); - - // Store the number of simultaneous threads/tasks per process - params.max_streams = calc_num_streams(inp, num_events); - CELER_VALIDATE(inp.mctruth_file.empty() || params.max_streams == 1, - << "cannot output MC truth with multiple " - "streams (" - << params.max_streams << " requested)"); - - // Store number of tracks per stream - CELER_VALIDATE(inp.num_track_slots > 0, - << "nonpositive num_track_slots=" << inp.num_track_slots); - params.tracks_per_stream - = ceil_div(inp.num_track_slots, params.max_streams); + // Number of streams + size_type const num_streams = p.control.num_streams; + CELER_VALIDATE(num_streams > 0, + << "currently p.control.num_streams must be manually set " + "before setup"); + params.max_streams = num_streams; // Construct track initialization params - params.init = [&inp, ¶ms, num_events] { - CELER_VALIDATE(inp.initializer_capacity > 0, + params.init = [&] { + CELER_VALIDATE(p.control.capacity.initializers > 0, << "nonpositive initializer_capacity=" - << inp.initializer_capacity); + << p.control.capacity.initializers); TrackInitParams::Input input; - input.capacity = ceil_div(inp.initializer_capacity, params.max_streams); - input.max_events = num_events; - input.track_order = inp.track_order; + input.capacity = ceil_div(p.control.capacity.initializers, num_streams); + input.max_events = p.control.capacity.events; + if (p.control.track_order) + { + input.track_order = *p.control.track_order; + } + else + { + if (celeritas::device()) + { + input.track_order = TrackOrder::init_charge; + } + else + { + input.track_order = TrackOrder::none; + } + CELER_LOG(debug) + << "Set default track order " << to_cstring(input.track_order); + } + return std::make_shared(std::move(input)); }(); - core_params_ = std::make_shared(std::move(params)); -} + // Number of tracks per stream + auto tracks = p.control.capacity.tracks; + CELER_VALIDATE(tracks > 0, + << "nonpositive control.capacity.tracks=" << tracks); + params.tracks_per_stream = ceil_div(tracks, params.max_streams); + + // Construct core + auto core_params = std::make_shared(std::move(params)); + + //// DIAGNOSTICS //// + + if (p.diagnostics.action) + { + ActionDiagnostic::make_and_insert(*core_params); + } + + if (p.diagnostics.step) + { + StepDiagnostic::make_and_insert(*core_params, p.diagnostics.step->bins); + } + + if (p.diagnostics.slot) + { + SlotDiagnostic::make_and_insert(*core_params, + p.diagnostics.slot->basename); + } + + //// STEP COLLECTORS //// -//---------------------------------------------------------------------------// -/*! - * Construct on all threads from a JSON input and shared output manager. - */ -void Runner::build_step_collectors(RunnerInput const& inp) -{ StepCollector::VecInterface step_interfaces; - if (!inp.mctruth_file.empty()) + std::shared_ptr root_manager; + if (p.diagnostics.mctruth) { + CELER_VALIDATE(num_streams == 1, + << "cannot output MC truth with multiple streams (" + << num_streams << " requested)"); + // Initialize ROOT file - root_manager_ - = std::make_shared(inp.mctruth_file.c_str()); + root_manager = std::make_shared( + p.diagnostics.mctruth->output_file.c_str()); // Create root step writer step_interfaces.push_back(std::make_shared( - root_manager_, - core_params_->particle(), + root_manager, + core_params->particle(), StepSelection::all(), - make_write_filter(inp.mctruth_filter))); + make_write_filter(p.diagnostics.mctruth->filter))); } - if (!inp.simple_calo.empty()) + if (p.scoring.simple_calo) { auto simple_calo - = std::make_shared(inp.simple_calo, - *core_params_->geometry(), - core_params_->max_streams()); + = std::make_shared(p.scoring.simple_calo->volumes, + *core_params->geometry(), + num_streams); // Add to step interfaces step_interfaces.push_back(simple_calo); // Add to output interface - core_params_->output_reg()->insert(simple_calo); + core_params->output_reg()->insert(simple_calo); } if (!step_interfaces.empty()) { - step_collector_ = std::make_unique( - core_params_->geometry(), - std::move(step_interfaces), - core_params_->aux_reg().get(), - core_params_->action_reg().get()); - } -} - -//---------------------------------------------------------------------------// -/*! - * Construct optical collector. - * - * \pre Must be called after \c build_core_params . - */ -void Runner::build_optical_collector(RunnerInput const& inp, - ImportData const& imported) -{ - CELER_EXPECT(core_params_); - - using optical::CherenkovParams; - using optical::MaterialParams; - using optical::ScintillationParams; - - //! \todo Update conditionals after implementing CelerOpticalPhysicsList - if (imported.optical_materials.empty()) - { - // No optical materials are present - return; - } - CELER_ASSERT(inp.optical); - - size_type num_streams = core_params_->max_streams(); - - OpticalCollector::Input oc_inp; - oc_inp.material = MaterialParams::from_import( - imported, *core_params_->geomaterial(), *core_params_->material()); - oc_inp.cherenkov = std::make_shared(*oc_inp.material); - oc_inp.scintillation - = ScintillationParams::from_import(imported, core_params_->particle()); - oc_inp.num_track_slots = ceil_div(inp.optical.num_track_slots, num_streams); - oc_inp.buffer_capacity = ceil_div(inp.optical.buffer_capacity, num_streams); - oc_inp.initializer_capacity - = ceil_div(inp.optical.initializer_capacity, num_streams); - oc_inp.auto_flush = ceil_div(inp.optical.auto_flush, num_streams); - - CELER_ASSERT(oc_inp); - optical_collector_ - = std::make_shared(*core_params_, std::move(oc_inp)); -} - -//---------------------------------------------------------------------------// -/*! - * Construct diagnostic actions/outputs. - */ -void Runner::build_diagnostics(RunnerInput const& inp) -{ - if (inp.action_diagnostic) - { - ActionDiagnostic::make_and_insert(*core_params_); + // TODO: step collector really just *builds* the actions: it's ok that + // it immediately goes out of scope + StepCollector(core_params->geometry(), + std::move(step_interfaces), + core_params->aux_reg().get(), + core_params->action_reg().get()); } - if (inp.step_diagnostic) + if (p.control.optical_capacity) { - StepDiagnostic::make_and_insert(*core_params_, - inp.step_diagnostic_bins); + CELER_EXPECT(core_params); + + using optical::CherenkovParams; + using optical::MaterialParams; + using optical::ScintillationParams; + + CELER_VALIDATE(!imported.optical_materials.empty(), + << "an optical tracking loop was requested but no " + "optical materials are present"); + + OpticalCollector::Input oc_inp; + oc_inp.material = MaterialParams::from_import( + imported, *core_params->geomaterial(), *core_params->material()); + oc_inp.cherenkov = std::make_shared(*oc_inp.material); + oc_inp.scintillation = ScintillationParams::from_import( + imported, core_params->particle()); + + // Map from optical capacity + auto const& optical_capacity = *p.control.optical_capacity; + oc_inp.num_track_slots = ceil_div(optical_capacity.tracks, num_streams); + oc_inp.buffer_capacity + = ceil_div(optical_capacity.initializers, num_streams); + oc_inp.initializer_capacity + = ceil_div(optical_capacity.initializers, num_streams); + oc_inp.auto_flush = ceil_div(optical_capacity.primaries, num_streams); + + CELER_ASSERT(oc_inp); + + // TODO: optical collector really just *builds* the optical setup: it's + // ok that it immediately goes out of scope + OpticalCollector(*core_params, std::move(oc_inp)); } - if (!inp.slot_diagnostic_prefix.empty()) + if (root_manager) { - SlotDiagnostic::make_and_insert(*core_params_, - inp.slot_diagnostic_prefix); + write_to_root(*core_params->action_reg(), root_manager.get()); } + return core_params; } //---------------------------------------------------------------------------// diff --git a/src/celeritas/setup/Problem.hh b/src/celeritas/setup/Problem.hh new file mode 100644 index 0000000000..1bf4a1e814 --- /dev/null +++ b/src/celeritas/setup/Problem.hh @@ -0,0 +1,31 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/Problem.hh +//---------------------------------------------------------------------------// +#pragma once + +#include + +namespace celeritas +{ +//---------------------------------------------------------------------------// +class CoreParams; + +namespace inp +{ +struct Problem; +} +struct ImportData; + +namespace setup +{ +//---------------------------------------------------------------------------// +// Set up the problem +std::shared_ptr +problem(inp::Problem const& p, ImportData const& imported); + +//---------------------------------------------------------------------------// +} // namespace setup +} // namespace celeritas From e35e7b30c5ecf621ef3269aa41dccb4b8f5f7d9d Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 24 Jan 2025 12:03:04 -0800 Subject: [PATCH 07/30] Build Standalone input --- src/celeritas/CMakeLists.txt | 1 + src/celeritas/inp/Control.hh | 2 +- src/celeritas/setup/StandaloneInput.cc | 92 ++++++++++++++++++++++++++ src/celeritas/setup/StandaloneInput.hh | 39 +++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/celeritas/setup/StandaloneInput.cc create mode 100644 src/celeritas/setup/StandaloneInput.hh diff --git a/src/celeritas/CMakeLists.txt b/src/celeritas/CMakeLists.txt index 7e5eb73d98..21c74fc853 100644 --- a/src/celeritas/CMakeLists.txt +++ b/src/celeritas/CMakeLists.txt @@ -111,6 +111,7 @@ list(APPEND SOURCES setup/Events.cc setup/Import.cc setup/Problem.cc + setup/StandaloneInput.cc setup/System.cc track/SimParams.cc track/SortTracksAction.cc diff --git a/src/celeritas/inp/Control.hh b/src/celeritas/inp/Control.hh index 50e4e46386..fd47bcfac5 100644 --- a/src/celeritas/inp/Control.hh +++ b/src/celeritas/inp/Control.hh @@ -48,7 +48,7 @@ namespace inp * as "per stream" whereas \c celer-sim used "per process". * * Defaults: - * - \c secondary: twice the number of track slots. + * - \c secondaries: twice the number of track slots. * * \todo Split this into "core" state capacity and "optical" state capacity? * Core contains \c events and \c secondaries . diff --git a/src/celeritas/setup/StandaloneInput.cc b/src/celeritas/setup/StandaloneInput.cc new file mode 100644 index 0000000000..ca4da8f6c4 --- /dev/null +++ b/src/celeritas/setup/StandaloneInput.cc @@ -0,0 +1,92 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/StandaloneInput.cc +//---------------------------------------------------------------------------// +#include "StandaloneInput.hh" + +#include "corecel/cont/VariantUtils.hh" +#include "celeritas/ext/GeantSetup.hh" +#include "celeritas/ext/RootImporter.hh" +#include "celeritas/global/CoreParams.hh" +#include "celeritas/inp/StandaloneInput.hh" +#include "celeritas/setup/Problem.hh" + +#include "Events.hh" +#include "System.hh" + +namespace celeritas +{ +namespace setup +{ +//---------------------------------------------------------------------------// +/*! + * Completely set up a Celeritas problem from a standalone input. + */ +StandaloneLoaded standalone_input(inp::StandaloneInput& si) +{ + // Set up system + setup::system(si.system); + + // Load problem + auto* problem = std::get_if(&si.problem); + if (!problem) + { + // TODO: load from serialized JSON/ROOT file + CELER_NOT_IMPLEMENTED("importing input data from an external file"); + } + + // Set up Geant4 + std::optional geant_setup; + if (si.geant_setup) + { + // Take file name from problem and physics options from the arguments, + // and set up Geant4 + CELER_ASSUME( + std::holds_alternative(problem->model.geometry)); + geant_setup.emplace(std::get(problem->model.geometry), + *si.geant_setup); + + // Replace world geometry with Geant4 world pointer + problem->model.geometry = geant_setup->world(); + } + + // Import physics data + ImportData imported = std::visit( + Overload{ + [](inp::FileImport const& fi) { + // Import physics data from ROOT file + return RootImporter(fi.input)(); + }, + [&geo = problem->model.geometry](inp::GeantImport const& gi) { + // For standalone, no processes should need to be ignored + CELER_ASSERT(gi.ignore_processes.empty()); + CELER_ASSUME( + std::holds_alternative(geo)); + + // Don't capture the setup; leave Geant4 alive for now + GeantImporter import{std::get(geo)}; + return import(gi.data_selection); + }, + }, + si.physics_import); + + StandaloneLoaded result; + + // Set up core params + result.core_params = setup::problem(*problem, imported); + + // Load events + result.events = events(si.events, result.core_params->particle()); + if (problem->control.capacity.events != 0) + { + // TODO: merge events? or let celer-sim do that? + } + + return result; +} + +//---------------------------------------------------------------------------// +} // namespace setup +} // namespace celeritas diff --git a/src/celeritas/setup/StandaloneInput.hh b/src/celeritas/setup/StandaloneInput.hh new file mode 100644 index 0000000000..026f22be74 --- /dev/null +++ b/src/celeritas/setup/StandaloneInput.hh @@ -0,0 +1,39 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/setup/StandaloneInput.hh +//---------------------------------------------------------------------------// +#pragma once + +#include + +#include "celeritas/phys/Primary.hh" + +namespace celeritas +{ +class CoreParams; + +namespace inp +{ +struct StandaloneInput; +} +namespace setup +{ +//---------------------------------------------------------------------------// +struct StandaloneLoaded +{ + using VecPrimary = std::vector; + using VecEvent = std::vector; + + std::shared_ptr core_params; + VecEvent events; +}; + +//---------------------------------------------------------------------------// +// Completely set up a Celeritas problem from a standalone input +StandaloneLoaded standalone_input(inp::StandaloneInput& si); + +//---------------------------------------------------------------------------// +} // namespace setup +} // namespace celeritas From 8c194be7eee521ef3265c1846bcfe331976c14ce Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Fri, 24 Jan 2025 15:17:47 -0800 Subject: [PATCH 08/30] IWYU --- app/celer-g4/GlobalSetup.cc | 10 ++--- app/celer-g4/GlobalSetup.hh | 4 ++ app/celer-g4/RunInput.cc | 18 +++++++++ app/celer-g4/RunInput.hh | 1 + app/celer-sim/Runner.cc | 51 ++++---------------------- app/celer-sim/Runner.hh | 2 + app/celer-sim/RunnerInput.cc | 17 +++++++++ app/celer-sim/RunnerInput.hh | 5 +++ src/celeritas/setup/Events.cc | 4 ++ src/celeritas/setup/Events.hh | 1 + src/celeritas/setup/Problem.cc | 25 ++++++++++++- src/celeritas/setup/StandaloneInput.cc | 11 ++++++ src/celeritas/setup/StandaloneInput.hh | 1 + src/celeritas/setup/System.cc | 3 ++ 14 files changed, 101 insertions(+), 52 deletions(-) diff --git a/app/celer-g4/GlobalSetup.cc b/app/celer-g4/GlobalSetup.cc index 014d2f0d8f..3a63abb4c4 100644 --- a/app/celer-g4/GlobalSetup.cc +++ b/app/celer-g4/GlobalSetup.cc @@ -7,24 +7,22 @@ #include "GlobalSetup.hh" #include +#include #include #include #include #include +#include "corecel/Config.hh" + #include "corecel/Assert.hh" #include "corecel/io/Logger.hh" #include "corecel/io/StringUtils.hh" -#include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" #include "celeritas/ext/RootFileManager.hh" -#include "celeritas/field/RZMapFieldInput.hh" -#include "accel/ExceptionConverter.hh" -#include "accel/HepMC3PrimaryGenerator.hh" +#include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "accel/SetupOptionsMessenger.hh" -#include "HepMC3PrimaryGeneratorAction.hh" -#include "RootIO.hh" #include "RunInputIO.json.hh" namespace celeritas diff --git a/app/celer-g4/GlobalSetup.hh b/app/celer-g4/GlobalSetup.hh index a1fdac6b24..4a15b557c5 100644 --- a/app/celer-g4/GlobalSetup.hh +++ b/app/celer-g4/GlobalSetup.hh @@ -9,11 +9,15 @@ #include #include #include +#include #include #include #include "corecel/sys/Stopwatch.hh" #include "geocel/g4/Convert.hh" +#include "celeritas/Types.hh" +#include "celeritas/ext/GeantPhysicsOptions.hh" +#include "celeritas/field/FieldDriverOptions.hh" #include "accel/SetupOptions.hh" #include "RunInput.hh" diff --git a/app/celer-g4/RunInput.cc b/app/celer-g4/RunInput.cc index 45b9ffb00d..4e600d221d 100644 --- a/app/celer-g4/RunInput.cc +++ b/app/celer-g4/RunInput.cc @@ -7,13 +7,31 @@ #include "RunInput.hh" #include +#include +#include +#include +#include +#include #include "corecel/Config.hh" +#include "corecel/Types.hh" #include "corecel/io/EnumStringMapper.hh" #include "corecel/io/Logger.hh" #include "corecel/math/ArrayUtils.hh" +#include "celeritas/field/RZMapFieldInput.hh" +#include "celeritas/inp/Control.hh" +#include "celeritas/inp/Diagnostics.hh" +#include "celeritas/inp/Events.hh" +#include "celeritas/inp/Field.hh" +#include "celeritas/inp/Import.hh" +#include "celeritas/inp/Model.hh" +#include "celeritas/inp/Physics.hh" +#include "celeritas/inp/Problem.hh" +#include "celeritas/inp/Scoring.hh" #include "celeritas/inp/StandaloneInput.hh" +#include "celeritas/inp/System.hh" +#include "celeritas/inp/Tracking.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "accel/SharedParams.hh" diff --git a/app/celer-g4/RunInput.hh b/app/celer-g4/RunInput.hh index 71c7307493..a29aaeb3b1 100644 --- a/app/celer-g4/RunInput.hh +++ b/app/celer-g4/RunInput.hh @@ -12,6 +12,7 @@ #include "corecel/cont/Array.hh" #include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" +#include "celeritas/Types.hh" #include "celeritas/ext/GeantPhysicsOptions.hh" #include "celeritas/field/FieldDriverOptions.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index f87b3ef143..ebf9870db9 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -6,70 +6,33 @@ //---------------------------------------------------------------------------// #include "Runner.hh" -#include #include -#include -#include #include #include +#include "corecel/Types.hh" +#include "corecel/cont/Range.hh" +#include "corecel/sys/ThreadId.hh" +#include "celeritas/io/ImportData.hh" +#include "celeritas/io/ImporterInterface.hh" +#include "celeritas/user/RootStepWriterInput.hh" + #ifdef _OPENMP # include #endif #include "corecel/cont/Span.hh" -#include "corecel/io/Logger.hh" -#include "corecel/io/OutputRegistry.hh" #include "corecel/io/StringUtils.hh" -#include "corecel/math/Algorithms.hh" -#include "corecel/sys/ActionRegistry.hh" #include "corecel/sys/Device.hh" -#include "corecel/sys/Environment.hh" -#include "corecel/sys/ScopedMem.hh" -#include "corecel/sys/ScopedProfiling.hh" #include "celeritas/Types.hh" -#include "celeritas/Units.hh" -#include "celeritas/alongstep/AlongStepGeneralLinearAction.hh" -#include "celeritas/alongstep/AlongStepUniformMscAction.hh" -#include "celeritas/em/params/UrbanMscParams.hh" -#include "celeritas/em/params/WentzelOKVIParams.hh" #include "celeritas/ext/GeantImporter.hh" #include "celeritas/ext/GeantSetup.hh" -#include "celeritas/ext/RootFileManager.hh" #include "celeritas/ext/RootImporter.hh" #include "celeritas/ext/ScopedRootErrorHandler.hh" -#include "celeritas/field/FieldDriverOptions.hh" -#include "celeritas/field/UniformFieldData.hh" -#include "celeritas/geo/GeoMaterialParams.hh" #include "celeritas/geo/GeoParams.hh" // IWYU pragma: keep #include "celeritas/global/CoreParams.hh" -#include "celeritas/io/EventReader.hh" -#include "celeritas/io/RootCoreParamsOutput.hh" -#include "celeritas/io/RootEventReader.hh" -#include "celeritas/mat/MaterialParams.hh" -#include "celeritas/optical/CherenkovParams.hh" -#include "celeritas/optical/MaterialParams.hh" -#include "celeritas/optical/OpticalCollector.hh" -#include "celeritas/optical/ScintillationParams.hh" -#include "celeritas/phys/CutoffParams.hh" -#include "celeritas/phys/ParticleParams.hh" -#include "celeritas/phys/PhysicsParams.hh" -#include "celeritas/phys/Primary.hh" -#include "celeritas/phys/PrimaryGenerator.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "celeritas/phys/Process.hh" -#include "celeritas/phys/ProcessBuilder.hh" -#include "celeritas/phys/RootEventSampler.hh" -#include "celeritas/random/RngParams.hh" -#include "celeritas/track/SimParams.hh" -#include "celeritas/track/TrackInitParams.hh" -#include "celeritas/user/ActionDiagnostic.hh" -#include "celeritas/user/RootStepWriter.hh" -#include "celeritas/user/SimpleCalo.hh" -#include "celeritas/user/SlotDiagnostic.hh" -#include "celeritas/user/StepCollector.hh" -#include "celeritas/user/StepData.hh" -#include "celeritas/user/StepDiagnostic.hh" #include "RunnerInput.hh" #include "Transporter.hh" diff --git a/app/celer-sim/Runner.hh b/app/celer-sim/Runner.hh index 7d9eab8e2e..2b00c65f56 100644 --- a/app/celer-sim/Runner.hh +++ b/app/celer-sim/Runner.hh @@ -7,12 +7,14 @@ #pragma once #include +#include #include #include #include #include "corecel/Types.hh" #include "corecel/sys/ThreadId.hh" +#include "celeritas/Types.hh" #include "celeritas/io/ImportData.hh" #include "celeritas/phys/Primary.hh" diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index b73b8c5599..33a75843f2 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -7,6 +7,23 @@ #include "RunnerInput.hh" #include +#include +#include +#include + +#include "corecel/Config.hh" + +#include "corecel/Types.hh" +#include "celeritas/inp/Control.hh" +#include "celeritas/inp/Diagnostics.hh" +#include "celeritas/inp/Events.hh" +#include "celeritas/inp/Field.hh" +#include "celeritas/inp/Model.hh" +#include "celeritas/inp/Physics.hh" +#include "celeritas/inp/PhysicsProcess.hh" +#include "celeritas/inp/Scoring.hh" +#include "celeritas/inp/System.hh" +#include "celeritas/inp/Tracking.hh" #ifdef _OPENMP # include #endif diff --git a/app/celer-sim/RunnerInput.hh b/app/celer-sim/RunnerInput.hh index 18be89b1fe..fa0ce927f7 100644 --- a/app/celer-sim/RunnerInput.hh +++ b/app/celer-sim/RunnerInput.hh @@ -6,10 +6,14 @@ //---------------------------------------------------------------------------// #pragma once +#include +#include + #include "corecel/Config.hh" #include "corecel/Macros.hh" #include "corecel/Types.hh" +#include "corecel/cont/Array.hh" #include "corecel/io/Label.hh" #include "corecel/sys/Environment.hh" #include "celeritas/Types.hh" @@ -18,6 +22,7 @@ #include "celeritas/field/FieldDriverOptions.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "celeritas/user/RootStepWriter.hh" +#include "celeritas/user/RootStepWriterInput.hh" #ifdef _WIN32 # include diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc index ba0584dfcc..ec77fbc180 100644 --- a/src/celeritas/setup/Events.cc +++ b/src/celeritas/setup/Events.cc @@ -6,13 +6,17 @@ //---------------------------------------------------------------------------// #include "Events.hh" +#include #include +#include "corecel/Assert.hh" #include "corecel/cont/VariantUtils.hh" #include "corecel/io/StringUtils.hh" #include "corecel/sys/ScopedMem.hh" +#include "celeritas/io/EventIOInterface.hh" #include "celeritas/io/EventReader.hh" #include "celeritas/io/RootEventReader.hh" +#include "celeritas/phys/Primary.hh" #include "celeritas/phys/PrimaryGenerator.hh" #include "celeritas/phys/RootEventSampler.hh" diff --git a/src/celeritas/setup/Events.hh b/src/celeritas/setup/Events.hh index 47da78fb78..5ab872becf 100644 --- a/src/celeritas/setup/Events.hh +++ b/src/celeritas/setup/Events.hh @@ -6,6 +6,7 @@ //---------------------------------------------------------------------------// #pragma once +#include #include #include "celeritas/inp/Events.hh" diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 64bb396fcf..de0cd8dda8 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -6,12 +6,22 @@ //---------------------------------------------------------------------------// #include "Problem.hh" -#include "corecel/Assert.hh" +#include +#include +#include +#include +#include + +#include "corecel/Config.hh" + #include "corecel/cont/VariantUtils.hh" +#include "corecel/cont/detail/VariantUtilsImpl.hh" #include "corecel/io/Logger.hh" #include "corecel/io/OutputRegistry.hh" #include "corecel/math/Algorithms.hh" +#include "corecel/math/Constant.hh" #include "corecel/sys/ActionRegistry.hh" +#include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" #include "corecel/sys/ScopedMem.hh" #include "corecel/sys/ScopedProfiling.hh" @@ -21,16 +31,26 @@ #include "celeritas/alongstep/AlongStepUniformMscAction.hh" #include "celeritas/em/params/UrbanMscParams.hh" #include "celeritas/em/params/WentzelOKVIParams.hh" -#include "celeritas/ext/GeantImporter.hh" +#include "celeritas/ext/GeantPhysicsOptions.hh" #include "celeritas/ext/GeantSetup.hh" #include "celeritas/ext/RootFileManager.hh" #include "celeritas/field/FieldDriverOptions.hh" #include "celeritas/field/UniformFieldData.hh" #include "celeritas/geo/GeoMaterialParams.hh" #include "celeritas/geo/GeoParams.hh" // IWYU pragma: keep +#include "celeritas/global/ActionInterface.hh" #include "celeritas/global/CoreParams.hh" +#include "celeritas/inp/Control.hh" +#include "celeritas/inp/Diagnostics.hh" +#include "celeritas/inp/Field.hh" #include "celeritas/inp/Model.hh" +#include "celeritas/inp/Physics.hh" +#include "celeritas/inp/PhysicsModel.hh" +#include "celeritas/inp/PhysicsProcess.hh" #include "celeritas/inp/Problem.hh" +#include "celeritas/inp/Scoring.hh" +#include "celeritas/inp/Tracking.hh" +#include "celeritas/io/ImportData.hh" #include "celeritas/io/RootCoreParamsOutput.hh" #include "celeritas/mat/MaterialParams.hh" #include "celeritas/optical/CherenkovParams.hh" @@ -52,6 +72,7 @@ #include "celeritas/user/StepCollector.hh" #include "celeritas/user/StepData.hh" #include "celeritas/user/StepDiagnostic.hh" + namespace celeritas { namespace setup diff --git a/src/celeritas/setup/StandaloneInput.cc b/src/celeritas/setup/StandaloneInput.cc index ca4da8f6c4..550bda68d5 100644 --- a/src/celeritas/setup/StandaloneInput.cc +++ b/src/celeritas/setup/StandaloneInput.cc @@ -6,11 +6,22 @@ //---------------------------------------------------------------------------// #include "StandaloneInput.hh" +#include +#include +#include + +#include "corecel/Assert.hh" #include "corecel/cont/VariantUtils.hh" +#include "celeritas/ext/GeantImporter.hh" #include "celeritas/ext/GeantSetup.hh" #include "celeritas/ext/RootImporter.hh" #include "celeritas/global/CoreParams.hh" +#include "celeritas/inp/Control.hh" +#include "celeritas/inp/Import.hh" +#include "celeritas/inp/Model.hh" +#include "celeritas/inp/Problem.hh" #include "celeritas/inp/StandaloneInput.hh" +#include "celeritas/io/ImportData.hh" #include "celeritas/setup/Problem.hh" #include "Events.hh" diff --git a/src/celeritas/setup/StandaloneInput.hh b/src/celeritas/setup/StandaloneInput.hh index 026f22be74..2dce75e2c4 100644 --- a/src/celeritas/setup/StandaloneInput.hh +++ b/src/celeritas/setup/StandaloneInput.hh @@ -7,6 +7,7 @@ #pragma once #include +#include #include "celeritas/phys/Primary.hh" diff --git a/src/celeritas/setup/System.cc b/src/celeritas/setup/System.cc index 2393c88dfd..1f5f017b87 100644 --- a/src/celeritas/setup/System.cc +++ b/src/celeritas/setup/System.cc @@ -6,6 +6,9 @@ //---------------------------------------------------------------------------// #include "System.hh" +#include +#include + #include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" #include "celeritas/inp/System.hh" From 349babb59f91ee2ac1d208ff11824e235e23b23d Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Sat, 25 Jan 2025 19:51:06 -0700 Subject: [PATCH 09/30] Fix some compatibility failures --- app/celer-sim/Runner.cc | 64 ++++++++++++-------------- app/celer-sim/RunnerInput.cc | 28 +++++++++-- app/celer-sim/simple-driver.py | 9 ++-- src/celeritas/inp/Physics.hh | 7 ++- src/celeritas/io/EventReader.cc | 4 +- src/celeritas/io/RootEventReader.cc | 1 + src/celeritas/setup/Problem.cc | 9 ++-- src/celeritas/setup/StandaloneInput.cc | 6 +-- 8 files changed, 72 insertions(+), 56 deletions(-) diff --git a/app/celer-sim/Runner.cc b/app/celer-sim/Runner.cc index ebf9870db9..b071ae6f59 100644 --- a/app/celer-sim/Runner.cc +++ b/app/celer-sim/Runner.cc @@ -28,11 +28,11 @@ #include "celeritas/ext/GeantImporter.hh" #include "celeritas/ext/GeantSetup.hh" #include "celeritas/ext/RootImporter.hh" -#include "celeritas/ext/ScopedRootErrorHandler.hh" -#include "celeritas/geo/GeoParams.hh" // IWYU pragma: keep #include "celeritas/global/CoreParams.hh" +#include "celeritas/inp/StandaloneInput.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "celeritas/phys/Process.hh" +#include "celeritas/setup/StandaloneInput.hh" #include "RunnerInput.hh" #include "Transporter.hh" @@ -45,45 +45,39 @@ namespace app /*! * Construct on all threads from a JSON input and shared output manager. */ -Runner::Runner(RunnerInput const& inp) +Runner::Runner(RunnerInput const& old_inp) { - CELER_VALIDATE(inp.event_file.empty() != !inp.primary_options, - << "either a event filename or options to generate " - "primaries must be provided (but not both)"); - CELER_VALIDATE(!inp.mctruth_filter || !inp.mctruth_file.empty(), - << "'mctruth_filter' cannot be specified without providing " - "'mctruth_file'"); - - using SPImporter = std::shared_ptr; - - // Possible Geant4 world volume so we can reuse geometry - G4VPhysicalVolume const* g4world{nullptr}; - - // Import data and load geometry - // If Geant4 is initialized, its data is scoped by the GeantImporter - auto import = [&inp, &g4world]() -> SPImporter { - if (ends_with(inp.physics_file, ".root")) - { - // Load from ROOT file - return std::make_shared(inp.physics_file); - } - - std::string const& filename - = !inp.physics_file.empty() ? inp.physics_file : inp.geometry_file; + // Convert to new format and set up problem + inp::StandaloneInput si = to_input(old_inp); + auto loaded = setup::standalone_input(si); + core_params_ = std::move(loaded.core_params); + CELER_ASSERT(core_params_); + events_ = std::move(loaded.events); + + if (old_inp.merge_events) + { + // Merge all events into a single one + VecPrimary merged; - // Load Geant4 and retain to use geometry - GeantSetup setup(filename, inp.physics_options); - g4world = setup.world(); - return std::make_shared(std::move(setup)); - }(); + // Reserve space in the merged vector + merged.reserve(std::accumulate( + events_.begin(), + events_.end(), + std::size_t{0}, + [](std::size_t sum, auto const& v) { return sum + v.size(); })); - // Import physics - auto const imported = (*import)(); + for (auto const& v : events_) + { + merged.insert(merged.end(), v.begin(), v.end()); + } + events_ = {std::move(merged)}; + } - ScopedRootErrorHandler scoped_root_error; - use_device_ = inp.use_device; + use_device_ = old_inp.use_device; + this->build_transporter_input(old_inp); transporters_.resize(this->num_streams()); + CELER_ENSURE(core_params_); } diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 33a75843f2..7fac5694bd 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -14,6 +14,8 @@ #include "corecel/Config.hh" #include "corecel/Types.hh" +#include "corecel/cont/VariantUtils.hh" +#include "corecel/io/StringUtils.hh" #include "celeritas/inp/Control.hh" #include "celeritas/inp/Diagnostics.hh" #include "celeritas/inp/Events.hh" @@ -24,6 +26,8 @@ #include "celeritas/inp/Scoring.hh" #include "celeritas/inp/System.hh" #include "celeritas/inp/Tracking.hh" +#include "celeritas/io/EventReader.hh" +#include "celeritas/io/RootEventReader.hh" #ifdef _OPENMP # include #endif @@ -139,6 +143,7 @@ inp::Problem load_problem(RunnerInput const& ri) * the first value in the list. If OMP_NUM_THREADS is not set, the value will * be implementation defined. */ + p.control.num_streams = 1; #if CELERITAS_OPENMP == CELERITAS_OPENMP_EVENT if (!ri.merge_events) { @@ -173,10 +178,7 @@ inp::Problem load_problem(RunnerInput const& ri) em.brems->combined_model = ri.brem_combined; // Spline energy loss order - CELER_VALIDATE(ri.spline_eloss_order == 1 || ri.spline_eloss_order == 3, - << "unsupported energy loss spline order " - << ri.spline_eloss_order); - em.eloss_spline = (ri.spline_eloss_order == 3); + em.eloss_spline_order = ri.spline_eloss_order; } // Tracking @@ -247,6 +249,9 @@ inp::StandaloneInput to_input(RunnerInput const& ri) si.problem = load_problem(ri); if (!ri.physics_file.empty()) { + CELER_VALIDATE( + ends_with(ri.physics_file, ".root"), + << R"(physics_file must be a ROOT input: use GDML for geometry_file and if forcing an ORANGE geometry, use the `ORANGE_FORCE_INPUT` environment variable)"); // Read ROOT input si.physics_import = inp::FileImport{ri.physics_file}; } @@ -259,6 +264,21 @@ inp::StandaloneInput to_input(RunnerInput const& ri) si.geant_data = inp::GeantDataImport{}; si.events = load_events(ri); + std::get(si.problem).control.capacity.events = std::visit( + Overload{ + [](inp::PrimaryGenerator const& pg) { return pg.num_events; }, + [](inp::SampleFileEvents const& sfe) { return sfe.num_events; }, + [](inp::ReadFileEvents const& rfe) { + if (ends_with(rfe.event_file, ".root")) + { + return RootEventReader{rfe.event_file, nullptr}.num_events(); + } + + return EventReader{rfe.event_file, nullptr}.num_events(); + }, + }, + si.events); + return si; } diff --git a/app/celer-sim/simple-driver.py b/app/celer-sim/simple-driver.py index 16c5df7585..61d38b0772 100755 --- a/app/celer-sim/simple-driver.py +++ b/app/celer-sim/simple-driver.py @@ -49,6 +49,7 @@ def strtobool(text): 'lpm': True, } +physics_filename = None if geant_exp_exe: physics_filename = run_name + ".root" inp_file = f'{run_name}.geant.json' @@ -65,13 +66,10 @@ def strtobool(text): if result_ge.returncode: print(f"fatal: {geant_exp_exe} failed with error {result_ge.returncode}") exit(result_ge.returncode) -else: - # Load directly from Geant4 rather than ROOT file - physics_filename = geometry_filename if core_geo == "orange-json": - print("Replacing .gdml extension since VecGeom is disabled", file=stderr) - geometry_filename = re.sub(r"\.gdml$", ".org.json", geometry_filename) + print("Replacing .gdml extension since VecGeom and Geant4 conversion are disabled", file=stderr) + env['ORANGE_FORCE_INPUT'] = re.sub(r"\.gdml$", ".org.json", geometry_filename) simple_calo = [] if not rootout_filename and "cms" in geometry_filename: @@ -90,7 +88,6 @@ def strtobool(text): inp = { 'use_device': use_device, 'geometry_file': geometry_filename, - 'physics_file': physics_filename, 'event_file': event_filename, 'mctruth_file': rootout_filename, 'seed': 12345, diff --git a/src/celeritas/inp/Physics.hh b/src/celeritas/inp/Physics.hh index 250b26ff86..f136d9def2 100644 --- a/src/celeritas/inp/Physics.hh +++ b/src/celeritas/inp/Physics.hh @@ -34,8 +34,11 @@ struct EmPhysics //!@{ //! \name Energy loss and slowing down - //! Use cubic spline interpolation for energy loss - bool eloss_spline{false}; + //! Use spline interpolation for energy loss + size_type eloss_spline_order{1}; + + // TODO: currently eloss fluctuations are set up via geant importer, then + // read into ImportEmParams #if 0 //! Energy loss fluctuations bool eloss_fluct{true}; diff --git a/src/celeritas/io/EventReader.cc b/src/celeritas/io/EventReader.cc index be4cc52081..e0410283cd 100644 --- a/src/celeritas/io/EventReader.cc +++ b/src/celeritas/io/EventReader.cc @@ -33,8 +33,6 @@ EventReader::EventReader(std::string const& filename, SPConstParticles particles) : particles_(std::move(particles)) { - CELER_EXPECT(particles_); - // Fetch total number of events by opening a temporary reader num_events_ = [&filename] { SPReader temp_reader = open_hepmc3(filename); @@ -87,6 +85,8 @@ EventReader::EventReader(std::string const& filename, */ auto EventReader::operator()() -> result_type { + CELER_EXPECT(particles_); + // Parse the next event from the record HepMC3::GenEvent evt; { diff --git a/src/celeritas/io/RootEventReader.cc b/src/celeritas/io/RootEventReader.cc index 30c085f80b..44f2dc617c 100644 --- a/src/celeritas/io/RootEventReader.cc +++ b/src/celeritas/io/RootEventReader.cc @@ -54,6 +54,7 @@ RootEventReader::RootEventReader(std::string const& filename, auto RootEventReader::operator()(EventId event_id) -> result_type { CELER_EXPECT(event_id < num_events_); + CELER_EXPECT(params_); if (event_id < event_to_entry_.size()) { diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index de0cd8dda8..1404a25508 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -188,7 +188,7 @@ problem(inp::Problem const& p, ImportData const& imported) // Default: twice the number of track slots input.options.secondary_stack_factor = 2.0; } - input.options.spline_eloss_order = p.physics.em->eloss_spline ? 2 : 1; + input.options.spline_eloss_order = p.physics.em->eloss_spline_order; input.options.linear_loss_limit = imported.em_params.linear_loss_limit; input.options.light.lowest_energy = ParticleOptions::Energy( imported.em_params.lowest_electron_energy); @@ -297,7 +297,7 @@ problem(inp::Problem const& p, ImportData const& imported) // Construct simulation params params.sim = std::make_shared([&] { auto input = SimParams::Input::from_import( - imported, params.particle, p.control.capacity.events); + imported, params.particle, p.tracking.limits.field_substeps); return input; }()); @@ -311,8 +311,11 @@ problem(inp::Problem const& p, ImportData const& imported) // Construct track initialization params params.init = [&] { CELER_VALIDATE(p.control.capacity.initializers > 0, - << "nonpositive initializer_capacity=" + << "nonpositive capacity.initializers=" << p.control.capacity.initializers); + CELER_VALIDATE(p.control.capacity.events > 0, + << "nonpositive capacity.events=" + << p.control.capacity.events); TrackInitParams::Input input; input.capacity = ceil_div(p.control.capacity.initializers, num_streams); input.max_events = p.control.capacity.events; diff --git a/src/celeritas/setup/StandaloneInput.cc b/src/celeritas/setup/StandaloneInput.cc index 550bda68d5..bd8da59891 100644 --- a/src/celeritas/setup/StandaloneInput.cc +++ b/src/celeritas/setup/StandaloneInput.cc @@ -67,6 +67,8 @@ StandaloneLoaded standalone_input(inp::StandaloneInput& si) ImportData imported = std::visit( Overload{ [](inp::FileImport const& fi) { + CELER_VALIDATE(!fi.input.empty(), + << "no file import specified"); // Import physics data from ROOT file return RootImporter(fi.input)(); }, @@ -90,10 +92,6 @@ StandaloneLoaded standalone_input(inp::StandaloneInput& si) // Load events result.events = events(si.events, result.core_params->particle()); - if (problem->control.capacity.events != 0) - { - // TODO: merge events? or let celer-sim do that? - } return result; } From 45dc2043ce8046a16f4e3d0339f61a8a0578305b Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 27 Jan 2025 07:47:35 -0500 Subject: [PATCH 10/30] Update scoped messages and don't write empty optical loop --- src/celeritas/setup/Events.cc | 6 +++++- src/celeritas/setup/Problem.cc | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc index ec77fbc180..bc092ae401 100644 --- a/src/celeritas/setup/Events.cc +++ b/src/celeritas/setup/Events.cc @@ -13,6 +13,7 @@ #include "corecel/cont/VariantUtils.hh" #include "corecel/io/StringUtils.hh" #include "corecel/sys/ScopedMem.hh" +#include "corecel/sys/ScopedProfiling.hh" #include "celeritas/io/EventIOInterface.hh" #include "celeritas/io/EventReader.hh" #include "celeritas/io/RootEventReader.hh" @@ -51,7 +52,10 @@ events(inp::Events const& e, std::shared_ptr const& particles) { CELER_EXPECT(particles); - ScopedMem record_mem("Runner.build_events"); + + CELER_LOG(status) << "Loading events"; + ScopedMem record_mem("setup::events"); + ScopedProfiling profile_this{"setup::events"}; return std::visit( Overload{ diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 1404a25508..d428ec6685 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -128,10 +128,10 @@ std::shared_ptr build_geometry(inp::Model const& m) std::shared_ptr problem(inp::Problem const& p, ImportData const& imported) { - CELER_LOG(status) << "Loading input and initializing problem data"; + CELER_LOG(status) << "Initializing problem"; - ScopedMem record_mem("Runner.build_core_params"); - ScopedProfiling profile_this{"construct-params"}; + ScopedMem record_mem("setup::problem"); + ScopedProfiling profile_this{"setup::problem"}; CoreParams::Input params; @@ -420,9 +420,9 @@ problem(inp::Problem const& p, ImportData const& imported) using optical::MaterialParams; using optical::ScintillationParams; - CELER_VALIDATE(!imported.optical_materials.empty(), - << "an optical tracking loop was requested but no " - "optical materials are present"); + CELER_VALIDATE( + !imported.optical_materials.empty(), + << R"(an optical tracking loop was requested but no optical materials are present)"); OpticalCollector::Input oc_inp; oc_inp.material = MaterialParams::from_import( From 82930b4354deecfe28a08b61e3a91dc2e372e7c7 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 27 Jan 2025 09:01:02 -0500 Subject: [PATCH 11/30] Fix optical photon buffer count --- app/celer-g4/RunInput.cc | 2 +- app/celer-sim/RunnerInput.cc | 12 +++++----- src/accel/SetupOptions.cc | 2 +- src/celeritas/inp/Control.hh | 41 ++++++++++++++++++++++++++-------- src/celeritas/setup/Problem.cc | 2 +- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/app/celer-g4/RunInput.cc b/app/celer-g4/RunInput.cc index 4e600d221d..565854f57f 100644 --- a/app/celer-g4/RunInput.cc +++ b/app/celer-g4/RunInput.cc @@ -69,7 +69,7 @@ inp::Problem load_problem(RunInput const& ri) // Control p.control.capacity = [&ri] { - inp::StateCapacity capacity; + inp::CoreStateCapacity capacity; capacity.tracks = ri.num_track_slots; capacity.initializers = ri.initializer_capacity; capacity.secondaries = static_cast(ri.secondary_stack_factor diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 7fac5694bd..97c1f3958f 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -118,9 +118,10 @@ inp::Problem load_problem(RunnerInput const& ri) // Control { - inp::StateCapacity capacity; - capacity.tracks = ri.num_track_slots; + inp::CoreStateCapacity capacity; + capacity.primaries = 0; // Immediately generate initializers capacity.initializers = ri.initializer_capacity; + capacity.tracks = ri.num_track_slots; capacity.secondaries = static_cast(ri.secondary_stack_factor * ri.num_track_slots); @@ -189,10 +190,11 @@ inp::Problem load_problem(RunnerInput const& ri) if (ri.optical) { p.control.optical_capacity = [&ri] { - inp::StateCapacity sc; - sc.tracks = ri.optical.num_track_slots; - sc.initializers = ri.optical.initializer_capacity; + inp::OpticalStateCapacity sc; sc.primaries = ri.optical.auto_flush; + sc.initializers = ri.optical.initializer_capacity; + sc.tracks = ri.optical.num_track_slots; + sc.generators = ri.optical.buffer_capacity; return sc; }(); } diff --git a/src/accel/SetupOptions.cc b/src/accel/SetupOptions.cc index da6f233c52..8e2fd2ac05 100644 --- a/src/accel/SetupOptions.cc +++ b/src/accel/SetupOptions.cc @@ -96,7 +96,7 @@ void ProblemSetup::operator()(inp::Problem& p) const p.control.num_streams = so.get_num_streams(); p.control.capacity = [this, num_streams = p.control.num_streams] { - inp::StateCapacity c; + inp::CoreStateCapacity c; c.tracks = so.max_num_tracks * num_streams; c.initializers = so.initializer_capacity * num_streams; c.secondaries diff --git a/src/celeritas/inp/Control.hh b/src/celeritas/inp/Control.hh index fd47bcfac5..00bd778238 100644 --- a/src/celeritas/inp/Control.hh +++ b/src/celeritas/inp/Control.hh @@ -47,13 +47,6 @@ namespace inp * \note Previously, \c SetupOptions and \c celer-g4 treated these quantities * as "per stream" whereas \c celer-sim used "per process". * - * Defaults: - * - \c secondaries: twice the number of track slots. - * - * \todo Split this into "core" state capacity and "optical" state capacity? - * Core contains \c events and \c secondaries . - * \todo Instead of a special value \c events=0, make a variant or something - * more descriptive? * \todo Some of these parameters will be more automated in the future. */ struct StateCapacity @@ -64,6 +57,24 @@ struct StateCapacity size_type initializers{}; //! Maximum number of track slots to be simultaneously stepped size_type tracks{}; +}; + +//---------------------------------------------------------------------------// +/*! + * Set up per-process state/buffer capacities for the main tracking loop. + * + * \note The \c primaries was previously named \c auto_flush . + * \note Previously, \c SetupOptions and \c celer-g4 treated these quantities + * as "per stream" whereas \c celer-sim used "per process". + * + * Defaults: + * - \c secondaries: twice the number of track slots. + * + * \todo Instead of a special value \c events=0, make a variant or something + * more descriptive? + */ +struct CoreStateCapacity : StateCapacity +{ //! Maximum number of secondaries created per step std::optional secondaries; @@ -71,6 +82,18 @@ struct StateCapacity size_type events{0}; }; +//---------------------------------------------------------------------------// +/*! + * Set up per-process state/buffer capacities for the optical tracking loop. + * + * \note \c generators was previously named \c buffer_capacity . + */ +struct OpticalStateCapacity : StateCapacity +{ + //! Maximum number of queued photon-generating steps + size_type generators{}; +}; + //---------------------------------------------------------------------------// /*! * When using GPU, change execution options that make it easier to debug. @@ -98,10 +121,10 @@ struct DeviceDebug struct Control { //! Per-process state sizes - StateCapacity capacity; + CoreStateCapacity capacity; //! Per-process state sizes for *optical* tracking loop - std::optional optical_capacity; + std::optional optical_capacity; //! Number of streams size_type num_streams{}; diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index d428ec6685..6d871347b3 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -435,7 +435,7 @@ problem(inp::Problem const& p, ImportData const& imported) auto const& optical_capacity = *p.control.optical_capacity; oc_inp.num_track_slots = ceil_div(optical_capacity.tracks, num_streams); oc_inp.buffer_capacity - = ceil_div(optical_capacity.initializers, num_streams); + = ceil_div(optical_capacity.generators, num_streams); oc_inp.initializer_capacity = ceil_div(optical_capacity.initializers, num_streams); oc_inp.auto_flush = ceil_div(optical_capacity.primaries, num_streams); From 1b8e0ab5682c3c3d529619b3ece460e692722007 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 27 Jan 2025 09:09:40 -0500 Subject: [PATCH 12/30] Make max_events optional --- app/celer-sim/RunnerInput.cc | 4 +++- src/accel/SharedParams.cc | 1 - src/celeritas/inp/Control.hh | 2 +- src/celeritas/setup/Problem.cc | 32 ++++++++++++++++++++++---------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 97c1f3958f..2bf7e2c5ec 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -125,7 +125,7 @@ inp::Problem load_problem(RunnerInput const& ri) capacity.secondaries = static_cast(ri.secondary_stack_factor * ri.num_track_slots); - // TODO: replace "max" with # events during construction? + // TODO: replace "max" with # events during construction using LimitsT = std::numeric_limits; capacity.events = ri.merge_events ? LimitsT::max() : 0; @@ -266,6 +266,8 @@ inp::StandaloneInput to_input(RunnerInput const& ri) si.geant_data = inp::GeantDataImport{}; si.events = load_events(ri); + // Load actual number of events, needed to contruct core state before + // loading events std::get(si.problem).control.capacity.events = std::visit( Overload{ [](inp::PrimaryGenerator const& pg) { return pg.num_events; }, diff --git a/src/accel/SharedParams.cc b/src/accel/SharedParams.cc index 4cf0780ccb..0a2e8e9939 100644 --- a/src/accel/SharedParams.cc +++ b/src/accel/SharedParams.cc @@ -579,7 +579,6 @@ void SharedParams::initialize_core(SetupOptions const& options) params.init = [&options] { TrackInitParams::Input input; input.capacity = options.initializer_capacity; - input.max_events = 1; // TODO: use special "max events" case input.track_order = options.track_order; if (input.track_order == TrackOrder::size_) { diff --git a/src/celeritas/inp/Control.hh b/src/celeritas/inp/Control.hh index 00bd778238..a57e3e79ec 100644 --- a/src/celeritas/inp/Control.hh +++ b/src/celeritas/inp/Control.hh @@ -79,7 +79,7 @@ struct CoreStateCapacity : StateCapacity std::optional secondaries; //! Maximum number of simultaneous events (zero for Geant4 integration) - size_type events{0}; + std::optional events; }; //---------------------------------------------------------------------------// diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 6d871347b3..837809fb73 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -309,19 +309,31 @@ problem(inp::Problem const& p, ImportData const& imported) params.max_streams = num_streams; // Construct track initialization params - params.init = [&] { - CELER_VALIDATE(p.control.capacity.initializers > 0, + params.init = [&c = p.control, num_streams] { + CELER_VALIDATE(c.capacity.initializers > 0, << "nonpositive capacity.initializers=" - << p.control.capacity.initializers); - CELER_VALIDATE(p.control.capacity.events > 0, - << "nonpositive capacity.events=" - << p.control.capacity.events); + << c.capacity.initializers); + CELER_VALIDATE(!c.capacity.events || c.capacity.events > 0, + << "nonpositive capacity.events=" << *c.capacity.events); + // NOTE: if the following assertion fails, a placeholder "event + // count" should have been changed elsewhere + CELER_EXPECT( + c.capacity.events + != std::numeric_limits::max()); TrackInitParams::Input input; - input.capacity = ceil_div(p.control.capacity.initializers, num_streams); - input.max_events = p.control.capacity.events; - if (p.control.track_order) + input.capacity = ceil_div(c.capacity.initializers, num_streams); + if (c.capacity.events) { - input.track_order = *p.control.track_order; + input.max_events = *c.capacity.events; + } + else + { + // Geant4 integration (TODO: make this a special case) + input.max_events = 1; + } + if (c.track_order) + { + input.track_order = *c.track_order; } else { From c82c9d85639f071363017e60f243d28a4571a8a4 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Mon, 27 Jan 2025 17:47:40 -0500 Subject: [PATCH 13/30] Add note about streams --- app/celer-sim/RunnerInput.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 2bf7e2c5ec..e1cce2d662 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -118,6 +118,7 @@ inp::Problem load_problem(RunnerInput const& ri) // Control { + // NOTE: old celer-sim input is *integrated* over streams inp::CoreStateCapacity capacity; capacity.primaries = 0; // Immediately generate initializers capacity.initializers = ri.initializer_capacity; From 43512d2361c28feb6e08afc54c2633ad9ae4eee3 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 09:11:02 -0500 Subject: [PATCH 14/30] REVERTME: unrelated celer-g4 changes --- app/celer-g4/GlobalSetup.cc | 15 ++++++--------- app/celer-g4/GlobalSetup.hh | 4 ---- app/celer-g4/RunInput.cc | 18 ------------------ app/celer-g4/RunInput.hh | 1 - app/celer-g4/RunInputIO.json.cc | 21 +++++++++++++-------- 5 files changed, 19 insertions(+), 40 deletions(-) diff --git a/app/celer-g4/GlobalSetup.cc b/app/celer-g4/GlobalSetup.cc index 3a63abb4c4..6ea8e6a3c9 100644 --- a/app/celer-g4/GlobalSetup.cc +++ b/app/celer-g4/GlobalSetup.cc @@ -7,22 +7,24 @@ #include "GlobalSetup.hh" #include -#include #include #include #include #include -#include "corecel/Config.hh" - #include "corecel/Assert.hh" #include "corecel/io/Logger.hh" #include "corecel/io/StringUtils.hh" +#include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" #include "celeritas/ext/RootFileManager.hh" -#include "celeritas/phys/PrimaryGeneratorOptions.hh" +#include "celeritas/field/RZMapFieldInput.hh" +#include "accel/ExceptionConverter.hh" +#include "accel/HepMC3PrimaryGenerator.hh" #include "accel/SetupOptionsMessenger.hh" +#include "HepMC3PrimaryGeneratorAction.hh" +#include "RootIO.hh" #include "RunInputIO.json.hh" namespace celeritas @@ -130,11 +132,6 @@ void GlobalSetup::ReadInput(std::string const& filename) CELER_ASSERT(instream); nlohmann::json::parse(*instream).get_to(input_); - CELER_VALIDATE(input_.event_file.empty() - == static_cast(input_.primary_options), - << "either a HepMC3 filename or options to generate " - "primaries must be provided (but not both)"); - if (input_.cuda_stack_size != RunInput::unspecified) { options_->cuda_stack_size = input_.cuda_stack_size; diff --git a/app/celer-g4/GlobalSetup.hh b/app/celer-g4/GlobalSetup.hh index 4a15b557c5..a1fdac6b24 100644 --- a/app/celer-g4/GlobalSetup.hh +++ b/app/celer-g4/GlobalSetup.hh @@ -9,15 +9,11 @@ #include #include #include -#include #include #include #include "corecel/sys/Stopwatch.hh" #include "geocel/g4/Convert.hh" -#include "celeritas/Types.hh" -#include "celeritas/ext/GeantPhysicsOptions.hh" -#include "celeritas/field/FieldDriverOptions.hh" #include "accel/SetupOptions.hh" #include "RunInput.hh" diff --git a/app/celer-g4/RunInput.cc b/app/celer-g4/RunInput.cc index 565854f57f..ff0ecace23 100644 --- a/app/celer-g4/RunInput.cc +++ b/app/celer-g4/RunInput.cc @@ -7,31 +7,13 @@ #include "RunInput.hh" #include -#include -#include -#include -#include -#include #include "corecel/Config.hh" -#include "corecel/Types.hh" #include "corecel/io/EnumStringMapper.hh" #include "corecel/io/Logger.hh" #include "corecel/math/ArrayUtils.hh" -#include "celeritas/field/RZMapFieldInput.hh" -#include "celeritas/inp/Control.hh" -#include "celeritas/inp/Diagnostics.hh" -#include "celeritas/inp/Events.hh" -#include "celeritas/inp/Field.hh" -#include "celeritas/inp/Import.hh" -#include "celeritas/inp/Model.hh" -#include "celeritas/inp/Physics.hh" -#include "celeritas/inp/Problem.hh" -#include "celeritas/inp/Scoring.hh" #include "celeritas/inp/StandaloneInput.hh" -#include "celeritas/inp/System.hh" -#include "celeritas/inp/Tracking.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" #include "accel/SharedParams.hh" diff --git a/app/celer-g4/RunInput.hh b/app/celer-g4/RunInput.hh index a29aaeb3b1..71c7307493 100644 --- a/app/celer-g4/RunInput.hh +++ b/app/celer-g4/RunInput.hh @@ -12,7 +12,6 @@ #include "corecel/cont/Array.hh" #include "corecel/sys/Device.hh" #include "corecel/sys/Environment.hh" -#include "celeritas/Types.hh" #include "celeritas/ext/GeantPhysicsOptions.hh" #include "celeritas/field/FieldDriverOptions.hh" #include "celeritas/phys/PrimaryGeneratorOptions.hh" diff --git a/app/celer-g4/RunInputIO.json.cc b/app/celer-g4/RunInputIO.json.cc index 0cf64790b3..4bf4c3eabc 100644 --- a/app/celer-g4/RunInputIO.json.cc +++ b/app/celer-g4/RunInputIO.json.cc @@ -144,14 +144,19 @@ void from_json(nlohmann::json const& j, RunInput& v) #undef RI_LOAD_OPTION #undef RI_LOAD_REQUIRED - CELER_VALIDATE( - v.physics_list != PhysicsListSelection::ftfp_bert - || !j.contains("physics_options"), - << R"('physics_options' can only be specified for 'celer_ftfp_bert' or 'celer_em')"); - CELER_VALIDATE( - (v.field != RunInput::no_field() || v.field_type == "rzmap") - || !j.contains("field_options"), - << R"('field_options' cannot be specified without providing 'field')"); + + // TODO: move these validation checks to GlobalSetup + CELER_VALIDATE(v.event_file.empty() == static_cast(v.primary_options), + << "either a HepMC3 filename or options to generate " + "primaries must be provided (but not both)"); + CELER_VALIDATE(v.physics_list != PhysicsListSelection::ftfp_bert + || !j.contains("physics_options"), + << "'physics_options' can only be specified for " + "'celer_ftfp_bert' or 'celer_em'"); + CELER_VALIDATE((v.field != RunInput::no_field() || v.field_type == "rzmap") + || !j.contains("field_options"), + << "'field_options' cannot be specified without providing " + "'field'"); } //---------------------------------------------------------------------------// From c031b40e698fbd4fe9d2bc1f7643eeaad49ab724 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 09:13:56 -0500 Subject: [PATCH 15/30] Add capacity documentation --- doc/usage/input/control.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/usage/input/control.rst b/doc/usage/input/control.rst index 64b3da9a9f..54c5e05ecb 100644 --- a/doc/usage/input/control.rst +++ b/doc/usage/input/control.rst @@ -21,3 +21,10 @@ parameters that affect the simulation results without changing the physics. :members: :no-link: +.. doxygenstruct:: celeritas::inp::CoreStateCapacity + :members: + :no-link: + +.. doxygenstruct:: celeritas::inp::OpticalStateCapacity + :members: + :no-link: From d0c0f1fbf6fad8f8520c570e8dea639672e07daf Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 09:35:44 -0500 Subject: [PATCH 16/30] Fix build error and capacity size --- src/celeritas/CMakeLists.txt | 1 + src/celeritas/io/RootCoreParamsOutput.cc | 4 +- src/celeritas/setup/Problem.cc | 421 +++++++++++++---------- 3 files changed, 233 insertions(+), 193 deletions(-) diff --git a/src/celeritas/CMakeLists.txt b/src/celeritas/CMakeLists.txt index 21c74fc853..9edb9d84d8 100644 --- a/src/celeritas/CMakeLists.txt +++ b/src/celeritas/CMakeLists.txt @@ -227,6 +227,7 @@ if(CELERITAS_USE_ROOT) ext/ScopedRootErrorHandler.cc ext/RootUniquePtr.root.cc ext/RootFileManager.cc + io/RootCoreParamsOutput.cc io/RootEventReader.cc io/RootEventWriter.cc phys/RootEventSampler.cc diff --git a/src/celeritas/io/RootCoreParamsOutput.cc b/src/celeritas/io/RootCoreParamsOutput.cc index 90f5569da2..7a351e3c58 100644 --- a/src/celeritas/io/RootCoreParamsOutput.cc +++ b/src/celeritas/io/RootCoreParamsOutput.cc @@ -10,9 +10,9 @@ #include #include +#include "corecel/cont/Range.hh" #include "corecel/sys/ActionRegistry.hh" - -#include "RootFileManager.hh" +#include "celeritas/ext/RootFileManager.hh" namespace celeritas { diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 837809fb73..c026891934 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -112,6 +112,231 @@ std::shared_ptr build_geometry(inp::Model const& m) m.geometry); } +//---------------------------------------------------------------------------// +/*! + * Construct physics processes. + */ +auto build_physics_processes(inp::EmPhysics const& em, + CoreParams::Input const& params, + ImportData const& imported) +{ + // TODO: process builder should be deleted; instead it should get + // p.physics.em or whatever + std::vector> result; + ProcessBuilder::Options opts; + if (em.brems) + { + opts.brem_combined = em.brems->combined_model; + opts.brems_selection = [&brems = *em.brems] { + if (brems.rel && brems.sb) + return BremsModelSelection::all; + else if (brems.rel) + return BremsModelSelection::relativistic; + else if (brems.sb) + return BremsModelSelection::seltzer_berger; + else + return BremsModelSelection::none; + }(); + } + + // TODO: add callback for user processes + ProcessBuilder build_process( + imported, params.particle, params.material, opts); + for (auto pc : ProcessBuilder::get_all_process_classes(imported.processes)) + { + result.push_back(build_process(pc)); + CELER_ASSERT(result.back()); + } + return result; +} + +//---------------------------------------------------------------------------// +/*! + * Construct physics. + */ +auto build_physics(inp::Problem const& p, + CoreParams::Input const& params, + ImportData const& imported) +{ + PhysicsParams::Input input; + input.particles = params.particle; + input.materials = params.material; + input.action_registry = params.action_reg.get(); + + // Set physics options + input.options.fixed_step_limiter = p.tracking.force_step_limit; + if (p.control.capacity.secondaries) + { + input.options.secondary_stack_factor = *p.control.capacity.secondaries + / p.control.capacity.tracks; + } + else + { + // Default: twice the number of track slots + input.options.secondary_stack_factor = 2.0; + } + input.options.spline_eloss_order = p.physics.em->eloss_spline_order; + input.options.linear_loss_limit = imported.em_params.linear_loss_limit; + input.options.light.lowest_energy + = ParticleOptions::Energy(imported.em_params.lowest_electron_energy); + input.options.heavy.lowest_energy + = ParticleOptions::Energy(imported.em_params.lowest_muhad_energy); + + // Set multiple scattering options + input.options.light.range_factor = imported.em_params.msc_range_factor; + input.options.heavy.range_factor + = imported.em_params.msc_muhad_range_factor; + input.options.safety_factor = imported.em_params.msc_safety_factor; + input.options.lambda_limit = imported.em_params.msc_lambda_limit; + input.options.light.displaced = imported.em_params.msc_displaced; + input.options.heavy.displaced = imported.em_params.msc_muhad_displaced; + input.options.light.step_limit_algorithm + = imported.em_params.msc_step_algorithm; + input.options.heavy.step_limit_algorithm + = imported.em_params.msc_muhad_step_algorithm; + + // Build processes + CELER_ASSERT(p.physics.em); + input.processes = build_physics_processes(*p.physics.em, params, imported); + + return std::make_shared(std::move(input)); +} + +//---------------------------------------------------------------------------// +/*! + * Construct track initialization params. + */ +auto build_track_init(inp::Control const& c, size_type num_streams) +{ + CELER_VALIDATE(c.capacity.initializers > 0, + << "nonpositive capacity.initializers=" + << c.capacity.initializers); + CELER_VALIDATE(!c.capacity.events || c.capacity.events > 0, + << "nonpositive capacity.events=" << *c.capacity.events); + // NOTE: if the following assertion fails, a placeholder "event + // count" should have been changed elsewhere + CELER_EXPECT(c.capacity.events + != std::numeric_limits::max()); + TrackInitParams::Input input; + input.capacity = ceil_div(c.capacity.initializers, num_streams); + if (c.capacity.events) + { + input.max_events = *c.capacity.events; + } + else + { + // Geant4 integration (TODO: make this a special case) + input.max_events = 1; + } + if (c.track_order) + { + input.track_order = *c.track_order; + } + else + { + if (celeritas::device()) + { + input.track_order = TrackOrder::init_charge; + } + else + { + input.track_order = TrackOrder::none; + } + CELER_LOG(debug) << "Set default track order " + << to_cstring(input.track_order); + } + + return std::make_shared(std::move(input)); +} + +//---------------------------------------------------------------------------// +/*! + * Construct magnetic field from variant input. + */ +auto build_along_step(inp::Field const& var_field, + CoreParams::Input const& params, + ImportData const& imported) +{ + bool const eloss = imported.em_params.energy_loss_fluct; + auto msc = UrbanMscParams::from_import( + *params.particle, *params.material, imported); + + CELER_ASSUME(!var_field.valueless_by_exception()); + auto next_id = params.action_reg->next_id(); + return std::visit( + return_as>(Overload{ + [&](inp::NoField const&) { + return AlongStepGeneralLinearAction::from_params( + next_id, *params.material, *params.particle, msc, eloss); + }, + [&](inp::UniformField const& field) { + UniformFieldParams field_params; + + if (field.units != UnitSystem::si) + { + CELER_NOT_IMPLEMENTED("field units in other unit systems"); + } + field_params.field = field.strength; + field_params.options = field.driver_options; + + // Interpret input in units of Tesla + for (real_type& v : field_params.field) + { + v = native_value_from(units::FieldTesla{v}); + } + + return AlongStepUniformMscAction::from_params( + params.action_reg->next_id(), + *params.material, + *params.particle, + field_params, + msc, + eloss); + }, + [](inp::RZMapField const&) + -> std::shared_ptr { + CELER_NOT_IMPLEMENTED("building RZ map field through input"); + }, + }), + var_field); +} + +//---------------------------------------------------------------------------// +/*! + * Costruct magnetic field from variant input. + */ +auto build_optical_offload(inp::OpticalStateCapacity const& cap, + CoreParams& params, + ImportData const& imported) +{ + using optical::CherenkovParams; + using optical::MaterialParams; + using optical::ScintillationParams; + + CELER_VALIDATE( + !imported.optical_materials.empty(), + << R"(an optical tracking loop was requested but no optical materials are present)"); + + OpticalCollector::Input oc_inp; + oc_inp.material = MaterialParams::from_import( + imported, *params.geomaterial(), *params.material()); + oc_inp.cherenkov = std::make_shared(*oc_inp.material); + oc_inp.scintillation + = ScintillationParams::from_import(imported, params.particle()); + + // Map from optical capacity + auto num_streams = params.max_streams(); + oc_inp.num_track_slots = ceil_div(cap.tracks, num_streams); + oc_inp.buffer_capacity = ceil_div(cap.generators, num_streams); + oc_inp.initializer_capacity = ceil_div(cap.initializers, num_streams); + oc_inp.auto_flush = ceil_div(cap.primaries, num_streams); + CELER_ASSERT(oc_inp); + + // TODO: optical collector really just *builds* the optical setup: it's + // ok that it immediately goes out of scope + OpticalCollector(params, std::move(oc_inp)); +} + //---------------------------------------------------------------------------// } // namespace @@ -170,126 +395,10 @@ problem(inp::Problem const& p, ImportData const& imported) imported, params.material, params.particle); // Load physics: create individual processes with make_shared - params.physics = [¶ms, p, &imported] { - PhysicsParams::Input input; - input.particles = params.particle; - input.materials = params.material; - input.action_registry = params.action_reg.get(); - - // Set physics options - input.options.fixed_step_limiter = p.tracking.force_step_limit; - if (p.control.capacity.secondaries) - { - input.options.secondary_stack_factor - = *p.control.capacity.secondaries; - } - else - { - // Default: twice the number of track slots - input.options.secondary_stack_factor = 2.0; - } - input.options.spline_eloss_order = p.physics.em->eloss_spline_order; - input.options.linear_loss_limit = imported.em_params.linear_loss_limit; - input.options.light.lowest_energy = ParticleOptions::Energy( - imported.em_params.lowest_electron_energy); - input.options.heavy.lowest_energy - = ParticleOptions::Energy(imported.em_params.lowest_muhad_energy); - - // Set multiple scattering options - input.options.light.range_factor = imported.em_params.msc_range_factor; - input.options.heavy.range_factor - = imported.em_params.msc_muhad_range_factor; - input.options.safety_factor = imported.em_params.msc_safety_factor; - input.options.lambda_limit = imported.em_params.msc_lambda_limit; - input.options.light.displaced = imported.em_params.msc_displaced; - input.options.heavy.displaced = imported.em_params.msc_muhad_displaced; - input.options.light.step_limit_algorithm - = imported.em_params.msc_step_algorithm; - input.options.heavy.step_limit_algorithm - = imported.em_params.msc_muhad_step_algorithm; - - // Build processes - CELER_ASSERT(p.physics.em); - input.processes = [¶ms, &em = *p.physics.em, &imported] { - // TODO: process builder should be deleted; instead it should get - // p.physics.em or whatever - std::vector> result; - ProcessBuilder::Options opts; - if (em.brems) - { - opts.brem_combined = em.brems->combined_model; - opts.brems_selection = [&brems = *em.brems] { - if (brems.rel && brems.sb) - return BremsModelSelection::all; - else if (brems.rel) - return BremsModelSelection::relativistic; - else if (brems.sb) - return BremsModelSelection::seltzer_berger; - else - return BremsModelSelection::none; - }(); - } - - // TODO: add callback for user processes - ProcessBuilder build_process( - imported, params.particle, params.material, opts); - for (auto pc : - ProcessBuilder::get_all_process_classes(imported.processes)) - { - result.push_back(build_process(pc)); - CELER_ASSERT(result.back()); - } - return result; - }(); - - return std::make_shared(std::move(input)); - }(); - - bool const eloss = imported.em_params.energy_loss_fluct; - auto msc = UrbanMscParams::from_import( - *params.particle, *params.material, imported); + params.physics = build_physics(p, params, imported); CELER_ASSUME(!p.field.valueless_by_exception()); - params.action_reg->insert(std::visit( - return_as>(Overload{ - [&](inp::NoField const&) { - return AlongStepGeneralLinearAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - msc, - eloss); - }, - [&](inp::UniformField const& field) { - UniformFieldParams field_params; - - if (field.units != UnitSystem::si) - { - CELER_NOT_IMPLEMENTED("field units in other unit systems"); - } - field_params.field = field.strength; - field_params.options = field.driver_options; - - // Interpret input in units of Tesla - for (real_type& v : field_params.field) - { - v = native_value_from(units::FieldTesla{v}); - } - - return AlongStepUniformMscAction::from_params( - params.action_reg->next_id(), - *params.material, - *params.particle, - field_params, - msc, - eloss); - }, - [](inp::RZMapField const&) - -> std::shared_ptr { - CELER_NOT_IMPLEMENTED("building RZ map field through input"); - }, - }), - p.field)); + params.action_reg->insert(build_along_step(p.field, params, imported)); // Construct RNG params params.rng = std::make_shared(p.control.seed); @@ -309,48 +418,7 @@ problem(inp::Problem const& p, ImportData const& imported) params.max_streams = num_streams; // Construct track initialization params - params.init = [&c = p.control, num_streams] { - CELER_VALIDATE(c.capacity.initializers > 0, - << "nonpositive capacity.initializers=" - << c.capacity.initializers); - CELER_VALIDATE(!c.capacity.events || c.capacity.events > 0, - << "nonpositive capacity.events=" << *c.capacity.events); - // NOTE: if the following assertion fails, a placeholder "event - // count" should have been changed elsewhere - CELER_EXPECT( - c.capacity.events - != std::numeric_limits::max()); - TrackInitParams::Input input; - input.capacity = ceil_div(c.capacity.initializers, num_streams); - if (c.capacity.events) - { - input.max_events = *c.capacity.events; - } - else - { - // Geant4 integration (TODO: make this a special case) - input.max_events = 1; - } - if (c.track_order) - { - input.track_order = *c.track_order; - } - else - { - if (celeritas::device()) - { - input.track_order = TrackOrder::init_charge; - } - else - { - input.track_order = TrackOrder::none; - } - CELER_LOG(debug) - << "Set default track order " << to_cstring(input.track_order); - } - - return std::make_shared(std::move(input)); - }(); + params.init = build_track_init(p.control, num_streams); // Number of tracks per stream auto tracks = p.control.capacity.tracks; @@ -426,37 +494,8 @@ problem(inp::Problem const& p, ImportData const& imported) if (p.control.optical_capacity) { - CELER_EXPECT(core_params); - - using optical::CherenkovParams; - using optical::MaterialParams; - using optical::ScintillationParams; - - CELER_VALIDATE( - !imported.optical_materials.empty(), - << R"(an optical tracking loop was requested but no optical materials are present)"); - - OpticalCollector::Input oc_inp; - oc_inp.material = MaterialParams::from_import( - imported, *core_params->geomaterial(), *core_params->material()); - oc_inp.cherenkov = std::make_shared(*oc_inp.material); - oc_inp.scintillation = ScintillationParams::from_import( - imported, core_params->particle()); - - // Map from optical capacity - auto const& optical_capacity = *p.control.optical_capacity; - oc_inp.num_track_slots = ceil_div(optical_capacity.tracks, num_streams); - oc_inp.buffer_capacity - = ceil_div(optical_capacity.generators, num_streams); - oc_inp.initializer_capacity - = ceil_div(optical_capacity.initializers, num_streams); - oc_inp.auto_flush = ceil_div(optical_capacity.primaries, num_streams); - - CELER_ASSERT(oc_inp); - - // TODO: optical collector really just *builds* the optical setup: it's - // ok that it immediately goes out of scope - OpticalCollector(*core_params, std::move(oc_inp)); + build_optical_offload( + *p.control.optical_capacity, *core_params, imported); } if (root_manager) From a21b8b2824a06553f77a481a6e82c54276ea70ed Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 11:17:58 -0500 Subject: [PATCH 17/30] Add explicit cast for stack factor --- src/celeritas/setup/Problem.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index c026891934..4a9ca154db 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -167,8 +167,9 @@ auto build_physics(inp::Problem const& p, input.options.fixed_step_limiter = p.tracking.force_step_limit; if (p.control.capacity.secondaries) { - input.options.secondary_stack_factor = *p.control.capacity.secondaries - / p.control.capacity.tracks; + input.options.secondary_stack_factor + = static_cast(*p.control.capacity.secondaries) + / static_cast(p.control.capacity.tracks); } else { From 2d4550de401b7037824dd9b86072c0782b4c8b47 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 13:35:03 -0500 Subject: [PATCH 18/30] Fix accidental change to shared params --- src/accel/SharedParams.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/accel/SharedParams.cc b/src/accel/SharedParams.cc index 0a2e8e9939..ce0eea1fb7 100644 --- a/src/accel/SharedParams.cc +++ b/src/accel/SharedParams.cc @@ -291,8 +291,8 @@ SharedParams::SharedParams(std::string output_filename) { CELER_EXPECT(!output_filename_.empty()); - CELER_LOG_LOCAL(debug) << "Constructing output registry for no-offload " - "run"; + CELER_LOG_LOCAL(debug) + << R"(Constructing output registry for no-offload run)"; output_reg_ = std::make_shared(); CELER_ENSURE(output_reg_); @@ -579,6 +579,7 @@ void SharedParams::initialize_core(SetupOptions const& options) params.init = [&options] { TrackInitParams::Input input; input.capacity = options.initializer_capacity; + input.max_events = 1; // TODO: use special "max events" case input.track_order = options.track_order; if (input.track_order == TrackOrder::size_) { From 63bf44d37d9312bb1696545b86cc13a9d8d6e805 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 13:36:05 -0500 Subject: [PATCH 19/30] Fix unused warning on clang 18 --- src/celeritas/setup/Problem.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 4a9ca154db..777df1b016 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -103,6 +103,11 @@ std::shared_ptr build_geometry(inp::Model const& m) return build_from_filename(filename); } } + else + { + // Avoid warnings from clang with vecgeom + CELER_DISCARD(&build_from_filename); + } CELER_VALIDATE( world, << "null world pointer in problem.model.geometry"); return std::make_shared(world); From b5c0dc62f0ac4931e13f95b58d6c6c14260f113f Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 13:36:37 -0500 Subject: [PATCH 20/30] Fix crash in celer-g4 when SharedParams construction fails --- app/celer-g4/celer-g4.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/celer-g4/celer-g4.cc b/app/celer-g4/celer-g4.cc index 8a1087c774..db97e0630c 100644 --- a/app/celer-g4/celer-g4.cc +++ b/app/celer-g4/celer-g4.cc @@ -276,8 +276,8 @@ int main(int argc, char* argv[]) } // Create params, which need to be shared with detectors as well as - // initialization, and can be written for output - auto params = std::make_shared(); + // initialization, and can be written for output (default to stdout) + auto params = std::make_shared("-"); try { From 3007998304e74ddb78a499a2fefced127f989054 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 29 Jan 2025 15:07:32 -0500 Subject: [PATCH 21/30] Use struct to shut clang the hell up --- src/celeritas/setup/Problem.cc | 64 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 777df1b016..7e004b4a61 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -80,41 +80,43 @@ namespace setup namespace { //---------------------------------------------------------------------------// -std::shared_ptr build_geometry(inp::Model const& m) +struct GeoBuilder { - auto build_from_filename - = [](std::string const& filename) -> std::shared_ptr { + using result_type = std::shared_ptr; + + //! Build from filename + result_type operator()(std::string const& filename) + { CELER_VALIDATE(!filename.empty(), << "empty filename in problem.model.geometry"); return std::make_shared(filename); - }; - auto build_from_geant - = [&build_from_filename](G4VPhysicalVolume const* world) { - if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) - { - static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; - auto const& filename = celeritas::getenv(fi_hack_envname); - if (!filename.empty()) - { - CELER_LOG(warning) - << "Using a temporary, unsupported, and dangerous " - "hack to override the ORANGE geometry file: " - << fi_hack_envname << "='" << filename << "'"; - return build_from_filename(filename); - } - } - else - { - // Avoid warnings from clang with vecgeom - CELER_DISCARD(&build_from_filename); - } - CELER_VALIDATE( - world, << "null world pointer in problem.model.geometry"); - return std::make_shared(world); - }; - - return std::visit(Overload{build_from_filename, build_from_geant}, - m.geometry); + } + + //! Build from Geant4 + result_type operator()(G4VPhysicalVolume const* world) + { + if constexpr (CELERITAS_CORE_GEO == CELERITAS_CORE_GEO_ORANGE) + { + static char const fi_hack_envname[] = "ORANGE_FORCE_INPUT"; + auto const& filename = celeritas::getenv(fi_hack_envname); + if (!filename.empty()) + { + CELER_LOG(warning) + << "Using a temporary, unsupported, and dangerous " + "hack to override the ORANGE geometry file: " + << fi_hack_envname << "='" << filename << "'"; + return (*this)(filename); + } + } + CELER_VALIDATE(world, + << "null world pointer in problem.model.geometry"); + return std::make_shared(world); + } +}; + +auto build_geometry(inp::Model const& m) +{ + return std::visit(GeoBuilder{}, m.geometry); } //---------------------------------------------------------------------------// From 06f4ff8476e7965e0c05b5918576cccf94f1de9d Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Thu, 30 Jan 2025 07:44:50 -0500 Subject: [PATCH 22/30] Tidy up the nursery --- src/celeritas/setup/Events.cc | 2 +- src/celeritas/setup/Problem.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc index bc092ae401..03abce2070 100644 --- a/src/celeritas/setup/Events.cc +++ b/src/celeritas/setup/Events.cc @@ -28,7 +28,7 @@ namespace setup namespace { //---------------------------------------------------------------------------// -auto read_events(EventReaderInterface&& generate) +auto read_events(EventReaderInterface& generate) { std::vector> result; auto event = generate(); diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 7e004b4a61..89449c724a 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -165,6 +165,8 @@ auto build_physics(inp::Problem const& p, CoreParams::Input const& params, ImportData const& imported) { + CELER_ASSUME(p.physics.em); + PhysicsParams::Input input; input.particles = params.particle; input.materials = params.material; @@ -204,7 +206,6 @@ auto build_physics(inp::Problem const& p, = imported.em_params.msc_muhad_step_algorithm; // Build processes - CELER_ASSERT(p.physics.em); input.processes = build_physics_processes(*p.physics.em, params, imported); return std::make_shared(std::move(input)); From ce17b5e68c968b03ca58127f3b3d79ecfa5fdf0f Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Thu, 30 Jan 2025 10:34:58 -0500 Subject: [PATCH 23/30] Untidy to fix it --- src/celeritas/setup/Events.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/celeritas/setup/Events.cc b/src/celeritas/setup/Events.cc index 03abce2070..c6ffb39ac8 100644 --- a/src/celeritas/setup/Events.cc +++ b/src/celeritas/setup/Events.cc @@ -28,7 +28,8 @@ namespace setup namespace { //---------------------------------------------------------------------------// -auto read_events(EventReaderInterface& generate) +// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) +auto read_events(EventReaderInterface&& generate) { std::vector> result; auto event = generate(); From ff4f3bf8d33a17e07be05bbe879e34fb6aaf8b62 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 4 Feb 2025 16:25:00 -0500 Subject: [PATCH 24/30] Fix device initialization order --- app/celer-sim/celer-sim.cc | 12 ++++++++++-- src/celeritas/setup/System.cc | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/celer-sim/celer-sim.cc b/app/celer-sim/celer-sim.cc index aa98a8a4dc..9bbd2ee557 100644 --- a/app/celer-sim/celer-sim.cc +++ b/app/celer-sim/celer-sim.cc @@ -227,10 +227,10 @@ int main(int argc, char* argv[]) } // Initialize GPU - celeritas::activate_device(); - if (filename == "--device"sv) { + celeritas::activate_device(); + if (celeritas::Device::num_devices() == 0) { CELER_LOG(critical) << "No GPUs were detected"; @@ -287,5 +287,13 @@ int main(int argc, char* argv[]) output->output(&cout); cout << endl; + // Delete streams before end of program (TODO: this is because of a static + // initialization order issue; CUDA can be deactivated before the global + // celeritas::device is reset) + if (celeritas::device()) + { + celeritas::device().create_streams(0); + } + return return_code; } diff --git a/src/celeritas/setup/System.cc b/src/celeritas/setup/System.cc index 1f5f017b87..f7b308ecc3 100644 --- a/src/celeritas/setup/System.cc +++ b/src/celeritas/setup/System.cc @@ -39,6 +39,10 @@ void system(inp::System const& sys) { // TODO: if using MPI, use communicator activate_device(); + // NOTE: if CELER_DISABLE_DEVICE is set, device may be false + CELER_VALIDATE( + device(), + << R"(failed to activate device when `sys.device` was set)"); if (auto size = sys.device->stack_size) { From 870a8ecd992932df1988734f596ff315be2c2718 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Tue, 4 Feb 2025 16:46:23 -0500 Subject: [PATCH 25/30] Output if param initialization goes wrong --- app/celer-g4/celer-g4.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/celer-g4/celer-g4.cc b/app/celer-g4/celer-g4.cc index db97e0630c..6a28556b38 100644 --- a/app/celer-g4/celer-g4.cc +++ b/app/celer-g4/celer-g4.cc @@ -277,7 +277,7 @@ int main(int argc, char* argv[]) // Create params, which need to be shared with detectors as well as // initialization, and can be written for output (default to stdout) - auto params = std::make_shared("-"); + auto params = std::make_shared(); try { @@ -286,10 +286,19 @@ int main(int argc, char* argv[]) catch (std::exception const& e) { CELER_LOG(critical) << "While running " << argv[1] << ": " << e.what(); - params->output_reg()->insert( - std::make_shared( - std::current_exception())); - params->Finalize(); + auto e_output = std::make_shared( + std::current_exception()); + if (*params) + { + params->output_reg()->insert(e_output); + params->Finalize(); + } + else + { + celeritas::OutputRegistry reg; + reg.insert(e_output); + reg.output(&std::cout); + } return EXIT_FAILURE; } From 3379e1dc0746edad3508626ac93637c35cf33b97 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 5 Feb 2025 10:49:10 -0500 Subject: [PATCH 26/30] Set num threads when running GPU as well --- app/celer-sim/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/celer-sim/CMakeLists.txt b/app/celer-sim/CMakeLists.txt index a7d2dd1c6b..6e55e8776b 100644 --- a/app/celer-sim/CMakeLists.txt +++ b/app/celer-sim/CMakeLists.txt @@ -78,7 +78,7 @@ function(celer_sim_test test_ext gdml_inp_name hepmc3_inp_name mctruth_name) "${_driver}" "${_gdml_inp}" "${_hepmc3_inp}" "${_mctruth_out}" ) set_tests_properties("${_name}" PROPERTIES - ENVIRONMENT "${_env};${CELER_G4ENV}" + ENVIRONMENT "${_env};${CELER_G4ENV};${CELER_OMP_ENV}" RESOURCE_LOCK gpu REQUIRED_FILES "${_driver};${_gdml_inp};${_hepmc3_inp}" LABELS "app;nomemcheck;gpu" From a9873ed05992d853bedacf4644584584d7ee1a47 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 5 Feb 2025 10:59:45 -0500 Subject: [PATCH 27/30] Fix/warn about stream sizing --- app/celer-sim/RunnerInput.cc | 61 +++++++++++++++----------- app/celer-sim/simple-driver.py | 38 +++++++++++----- src/celeritas/inp/Control.hh | 9 ++-- src/celeritas/setup/StandaloneInput.cc | 10 +++++ 4 files changed, 75 insertions(+), 43 deletions(-) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index e1cce2d662..478230a219 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -63,6 +63,35 @@ inp::System load_system(RunnerInput const& ri) return s; } +//---------------------------------------------------------------------------// +/*! + * Get the number of streams from the number of OpenMP threads. + * + * The OMP_NUM_THREADS environment variable can be used to control the number + * of threads/streams. The value of OMP_NUM_THREADS should be a list of + * positive integers, each of which sets the number of threads for the parallel + * region at the corresponding nested level. The number of streams is set to + * the first value in the list. If OMP_NUM_THREADS is not set, the value will + * be implementation defined. + */ +size_type get_num_streams(bool merge_events) +{ + size_type result = 1; +#if CELERITAS_OPENMP == CELERITAS_OPENMP_EVENT + if (!merge_events) + { +# pragma omp parallel + if (omp_get_thread_num() == 0) + { + result = omp_get_num_threads(); + } +#endif + } + // TODO: Don't create more streams than events + // return std::min(result, num_events); + return result; +} + //---------------------------------------------------------------------------// inp::Problem load_problem(RunnerInput const& ri) { @@ -127,37 +156,17 @@ inp::Problem load_problem(RunnerInput const& ri) * ri.num_track_slots); // TODO: replace "max" with # events during construction - using LimitsT = std::numeric_limits; - capacity.events = ri.merge_events ? LimitsT::max() : 0; + if (ri.merge_events) + { + using LimitsT = std::numeric_limits; + capacity.events = LimitsT::max(); + } p.control.capacity = capacity; p.control.warm_up = ri.warm_up; p.control.seed = ri.seed; - -/*! - * Get the number of streams from the number of OpenMP threads. - * - * The OMP_NUM_THREADS environment variable can be used to control the number - * of threads/streams. The value of OMP_NUM_THREADS should be a list of - * positive integers, each of which sets the number of threads for the parallel - * region at the corresponding nested level. The number of streams is set to - * the first value in the list. If OMP_NUM_THREADS is not set, the value will - * be implementation defined. - */ - p.control.num_streams = 1; -#if CELERITAS_OPENMP == CELERITAS_OPENMP_EVENT - if (!ri.merge_events) - { -# pragma omp parallel - { - if (omp_get_thread_num() == 0) - { - p.control.num_streams = omp_get_num_threads(); - } - } - } -#endif + p.control.num_streams = get_num_streams(ri.merge_events); if (ri.use_device) { diff --git a/app/celer-sim/simple-driver.py b/app/celer-sim/simple-driver.py index 61d38b0772..b91064cd0d 100755 --- a/app/celer-sim/simple-driver.py +++ b/app/celer-sim/simple-driver.py @@ -118,6 +118,9 @@ def strtobool(text): 'auto_flush': 2**31, # Large enough to never launch optical loop } +if "simple-cms" in geometry_filename: + inp['merge_events'] = True + if physics_filename: inp['physics_file'] = physics_filename @@ -172,25 +175,36 @@ def strtobool(text): assert steps is None, steps internal = j["internal"] -if "lar" in geometry_filename and not use_device: - core_sizes = internal["core-sizes"].copy() - num_streams = internal["core-sizes"].pop("streams") - if "openmp" not in j["system"]["build"]["config"]["use"]: - assert num_streams == 1 - assert internal["core-sizes"] == { +core_sizes = internal["core-sizes"].copy() +num_streams = core_sizes.pop("streams") +if "openmp" not in j["system"]["build"]["config"]["use"]: + assert num_streams == 1 +if inp["merge_events"]: + assert num_streams == 1 + +expected_core_sizes = None +expected_opt_sizes = None +if not use_device: + expected_core_sizes = { "events": 4, "initializers": 3200, "processes": 1, "secondaries": 96, "tracks": 32 - }, core_sizes - - opt_sizes = internal["optical-sizes"].copy() - assert num_streams == opt_sizes.pop("streams") - assert opt_sizes == { + } +if not use_device and "lar" in geometry_filename: + expected_opt_sizes = { "generators": 24576, "initializers": 32, "tracks": 32 - }, opt_sizes + } + + +if expected_core_sizes: + assert core_sizes == expected_core_sizes, core_sizes +if expected_opt_sizes: + opt_sizes = internal["optical-sizes"].copy() + assert num_streams == opt_sizes.pop("streams") + assert opt_sizes == expected_opt_sizes, opt_sizes print(json.dumps(time, indent=1)) diff --git a/src/celeritas/inp/Control.hh b/src/celeritas/inp/Control.hh index a57e3e79ec..2d05c437ee 100644 --- a/src/celeritas/inp/Control.hh +++ b/src/celeritas/inp/Control.hh @@ -68,17 +68,16 @@ struct StateCapacity * as "per stream" whereas \c celer-sim used "per process". * * Defaults: - * - \c secondaries: twice the number of track slots. - * - * \todo Instead of a special value \c events=0, make a variant or something - * more descriptive? + * - \c secondaries: twice the number of track slots + * - \c events: single event runs at a time */ struct CoreStateCapacity : StateCapacity { //! Maximum number of secondaries created per step std::optional secondaries; - //! Maximum number of simultaneous events (zero for Geant4 integration) + //! Maximum number of simultaneous events (zero for doing one event at a + //! time) std::optional events; }; diff --git a/src/celeritas/setup/StandaloneInput.cc b/src/celeritas/setup/StandaloneInput.cc index bd8da59891..8eaf304d64 100644 --- a/src/celeritas/setup/StandaloneInput.cc +++ b/src/celeritas/setup/StandaloneInput.cc @@ -12,6 +12,7 @@ #include "corecel/Assert.hh" #include "corecel/cont/VariantUtils.hh" +#include "corecel/io/Logger.hh" #include "celeritas/ext/GeantImporter.hh" #include "celeritas/ext/GeantSetup.hh" #include "celeritas/ext/RootImporter.hh" @@ -93,6 +94,15 @@ StandaloneLoaded standalone_input(inp::StandaloneInput& si) // Load events result.events = events(si.events, result.core_params->particle()); + auto const& ctl = problem->control; + if (ctl.capacity.events && ctl.num_streams > result.events.size()) + { + CELER_LOG(warning) + << "Configured number of streams (" << ctl.num_streams + << ") exceeds number of loaded events (" << result.events.size() + << ")"; + } + return result; } From 2e90f8fd1901174c0d433543f83034d331db7c15 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 5 Feb 2025 12:22:46 -0500 Subject: [PATCH 28/30] Fix omp pragma --- app/celer-sim/RunnerInput.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index 478230a219..dff143b75f 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -81,14 +81,16 @@ size_type get_num_streams(bool merge_events) if (!merge_events) { # pragma omp parallel - if (omp_get_thread_num() == 0) { - result = omp_get_num_threads(); + if (omp_get_thread_num() == 0) + { + result = omp_get_num_threads(); + } } #endif } + // TODO: Don't create more streams than events - // return std::min(result, num_events); return result; } From 404f471ef5554ac2160c62bfb0d63005ebb5ad98 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Wed, 5 Feb 2025 12:54:16 -0500 Subject: [PATCH 29/30] Fucking braces --- app/celer-sim/RunnerInput.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index dff143b75f..eb307f9040 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -87,8 +87,8 @@ size_type get_num_streams(bool merge_events) result = omp_get_num_threads(); } } -#endif } +#endif // TODO: Don't create more streams than events return result; From b41023b7048e7cc77f60304fd9b531ae18e78122 Mon Sep 17 00:00:00 2001 From: Seth R Johnson Date: Thu, 6 Feb 2025 08:49:02 -0500 Subject: [PATCH 30/30] Fix unused variable --- app/celer-sim/RunnerInput.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/celer-sim/RunnerInput.cc b/app/celer-sim/RunnerInput.cc index eb307f9040..04006b0cdd 100644 --- a/app/celer-sim/RunnerInput.cc +++ b/app/celer-sim/RunnerInput.cc @@ -88,6 +88,8 @@ size_type get_num_streams(bool merge_events) } } } +#else + CELER_DISCARD(merge_events); #endif // TODO: Don't create more streams than events