Skip to content

Commit

Permalink
Add high-level user/fast sim integration helpers (#1615)
Browse files Browse the repository at this point in the history
* Capture setup options rather than reference
* Rewrite exception handling code
* Add user action integration
* Add docs
* Define integration base class
* Add fast sim integration
* Add docs
* Fix accidental disabling of fastsim
* Add checking of options being set
* Fix missing call to SetOptions and remove deprecated variable usage
* Fix fast simulation model in kill-offload mode and update exception strings
* Update error codes
* Use pi+ instead of neutron in example
* Remove check that is invalid when using 'kill offload' mode
  • Loading branch information
sethrj authored Feb 13, 2025
1 parent 3fbab5e commit 6580368
Show file tree
Hide file tree
Showing 38 changed files with 859 additions and 383 deletions.
6 changes: 3 additions & 3 deletions app/celer-g4/ActionInitialization.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ ActionInitialization::ActionInitialization(SPParams params)
auto const& input = GlobalSetup::Instance()->input();
if (!input.event_file.empty())
{
ExceptionConverter call_g4exception{"celer0007"};
ExceptionConverter call_g4exception{"celer.init.hepmc3"};
CELER_TRY_HANDLE(hepmc_gen_ = std::make_shared<HepMC3PrimaryGenerator>(
input.event_file),
call_g4exception);
Expand Down Expand Up @@ -92,15 +92,15 @@ void ActionInitialization::Build() const
std::unique_ptr<G4VUserPrimaryGeneratorAction> generator_action;
if (hepmc_gen_)
{
ExceptionConverter call_g4exception{"celer0007"};
ExceptionConverter call_g4exception{"celer.init.hepmc3"};
CELER_TRY_HANDLE(
generator_action
= std::make_unique<HepMC3PrimaryGeneratorAction>(hepmc_gen_),
call_g4exception);
}
else
{
ExceptionConverter call_g4exception{"celer0006"};
ExceptionConverter call_g4exception{"celer.init.pgp"};
CELER_TRY_HANDLE(
generator_action = std::make_unique<PGPrimaryGeneratorAction>(
to_input(GlobalSetup::Instance()->input().primary_options)),
Expand Down
4 changes: 2 additions & 2 deletions app/celer-g4/EventAction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void EventAction::BeginOfEventAction(G4Event const* event)
return;

// Set event ID in local transporter and reseed Celerits RNG
ExceptionConverter call_g4exception{"celer0002"};
ExceptionConverter call_g4exception{"celer.event.begin"};
CELER_TRY_HANDLE(transport_->InitializeEvent(event->GetEventID()),
call_g4exception);
}
Expand All @@ -65,7 +65,7 @@ void EventAction::EndOfEventAction(G4Event const* event)
if (params_->mode() == SharedParams::Mode::enabled)
{
// Transport any tracks left in the buffer
ExceptionConverter call_g4exception{"celer0004", params_.get()};
ExceptionConverter call_g4exception{"celer.event.flush", params_.get()};
CELER_TRY_HANDLE(transport_->Flush(), call_g4exception);
}

Expand Down
1 change: 0 additions & 1 deletion app/celer-g4/GlobalSetup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "corecel/sys/Environment.hh"
#include "celeritas/ext/RootFileManager.hh"
#include "celeritas/field/RZMapFieldInput.hh"
#include "accel/ExceptionConverter.hh"
#include "accel/HepMC3PrimaryGenerator.hh"
#include "accel/SetupOptionsMessenger.hh"

Expand Down
3 changes: 1 addition & 2 deletions app/celer-g4/HepMC3PrimaryGeneratorAction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ HepMC3PrimaryGeneratorAction::HepMC3PrimaryGeneratorAction(SPGenerator gen)
*/
void HepMC3PrimaryGeneratorAction::GeneratePrimaries(G4Event* event)
{
ExceptionConverter call_g4exception{"celer0000"};
CELER_TRY_HANDLE(generator_->GeneratePrimaryVertex(event),
call_g4exception);
ExceptionConverter{"celer.event.generate"});
}

//---------------------------------------------------------------------------//
Expand Down
1 change: 0 additions & 1 deletion app/celer-g4/RootIO.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "corecel/io/Logger.hh"
#include "geocel/GeantUtils.hh"
#include "celeritas/ext/RootFileManager.hh"
#include "accel/ExceptionConverter.hh"
#include "accel/SetupOptions.hh"

#include "GlobalSetup.hh"
Expand Down
6 changes: 3 additions & 3 deletions app/celer-g4/RunAction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void RunAction::BeginOfRunAction(G4Run const* run)
{
CELER_EXPECT(run);

ExceptionConverter call_g4exception{"celer0001"};
ExceptionConverter call_g4exception{"celer.init.global"};

if (init_shared_)
{
Expand All @@ -87,7 +87,7 @@ void RunAction::BeginOfRunAction(G4Run const* run)
{
// Allocate data in shared thread-local transporter
CELER_TRY_HANDLE(transport_->Initialize(*options_, *params_),
call_g4exception);
ExceptionConverter{"celer.init.local"});
CELER_ASSERT(*transport_);
}

Expand All @@ -113,7 +113,7 @@ void RunAction::BeginOfRunAction(G4Run const* run)
*/
void RunAction::EndOfRunAction(G4Run const*)
{
ExceptionConverter call_g4exception{"celer0005"};
ExceptionConverter call_g4exception{"celer.finalize"};

if (GlobalSetup::Instance()->root_sd_io())
{
Expand Down
3 changes: 2 additions & 1 deletion app/celer-g4/TrackingAction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ void TrackingAction::PreUserTrackingAction(G4Track const* track)
if (mode == SharedParams::Mode::enabled)
{
// Celeritas is transporting this track
ExceptionConverter call_g4exception{"celer0003", params_.get()};
ExceptionConverter call_g4exception{"celer.track.push",
params_.get()};
CELER_TRY_HANDLE(transport_->Push(*track), call_g4exception);
}
const_cast<G4Track*>(track)->SetTrackStatus(fStopAndKill);
Expand Down
43 changes: 36 additions & 7 deletions doc/implementation/geant4-interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ advanced implementation can be inspected in the :ref:`celer-g4` app.

.. _api_accel_high_level:

High-level interface
--------------------
High level interfaces
---------------------

.. doxygenclass:: celeritas::IntegrationBase
:members:
:no-link:

Tracking manager
^^^^^^^^^^^^^^^^

Using Celeritas to "offload" all electrons, photons, and gammas from Geant4 can
be done using the new-ish Geant4 interface :cpp:class:`G4VTrackingManager`
Expand All @@ -30,15 +37,30 @@ See :ref:`example_template` for a template of adding to a user application.

.. doxygenclass:: celeritas::TrackingManagerIntegration
:members:
:no-link:

Fast simulation
^^^^^^^^^^^^^^^

The :cpp:class:`SetupOptionsMessenger`, instantiated by the Integration helper
classes, provides a Geant4 "UI" macro interface to an app's Celeritas options.
It is currently *not* recommended to offload tracks on a per-region basis, since
tracks exiting that region remain in Celeritas and on GPU.

.. doxygenclass:: celeritas::SetupOptionsMessenger
.. doxygenclass:: celeritas::FastSimulationModel

.. doxygenclass:: celeritas::FastSimulationIntegration
:members:

User action
^^^^^^^^^^^

The :cpp:class:`celeritas::SimpleOffload` class is an extremely easy-to-use
For compatibility with older versions of Geant4, you may use the following
class to integrate Celeritas by manually intercepting tracks with a
``UserTrackingAction``.

.. doxygenclass:: celeritas::UserActionIntegration
:members:


The :cpp:class:`celeritas::SimpleOffload` class is a slightly lower level
interface for
offloading tracks to Celeritas in a multithreaded or serial application. The
class names correspond to user actions and ``ActionInitialization``. It
Expand Down Expand Up @@ -91,6 +113,13 @@ compatible with Celeritas), the Celeritas setup will fail with an error like:

.. doxygenclass:: celeritas::RZMapFieldAlongStepFactory


The :cpp:class:`SetupOptionsMessenger`, instantiated automatically by the
Integration helper classes, provides a Geant4 "UI" macro interface to many of
the options.

.. doxygenclass:: celeritas::SetupOptionsMessenger

Detailed interface
------------------

Expand Down
2 changes: 1 addition & 1 deletion example/accel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ if(Geant4_VERSION VERSION_LESS 11.1)
endif()

add_example(simple-offload)
add_example(fastsim-offload DISABLE)
add_example(fastsim-offload ${_needs_g411})

if(Geant4_VERSION VERSION_GREATER_EQUAL 11.0)
# Requires 11.0 to build
Expand Down
93 changes: 42 additions & 51 deletions example/accel/fastsim-offload.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,34 +35,23 @@
#include <G4VUserDetectorConstruction.hh>
#include <G4VUserPrimaryGeneratorAction.hh>
#include <G4Version.hh>
#if G4VERSION_NUMBER >= 1100
#if G4VERSION_NUMBER >= 1200
# include <G4RunManagerFactory.hh>
#else
# include <G4MTRunManager.hh>
#endif

#include <accel/AlongStepFactory.hh>
#include <accel/FastSimulationIntegration.hh>
#include <accel/FastSimulationModel.hh>
#include <accel/LocalTransporter.hh>
#include <accel/SetupOptions.hh>
#include <accel/SharedParams.hh>
#include <accel/SimpleOffload.hh>
#include <corecel/Macros.hh>
#include <corecel/io/Logger.hh>

using celeritas::FastSimulationIntegration;

namespace
{
//---------------------------------------------------------------------------//
// Global shared setup options
celeritas::SetupOptions setup_options;
// Shared data and GPU setup
celeritas::SharedParams shared_params;
// Thread-local transporter
G4ThreadLocal celeritas::LocalTransporter local_transporter;

// Simple interface to running celeritas
G4ThreadLocal celeritas::SimpleOffload simple_offload;

//---------------------------------------------------------------------------//
class DetectorConstruction final : public G4VUserDetectorConstruction
{
Expand All @@ -71,17 +60,12 @@ class DetectorConstruction final : public G4VUserDetectorConstruction
: aluminum_{new G4Material{
"Aluminium", 13., 26.98 * g / mole, 2.700 * g / cm3}}
{
setup_options.make_along_step = celeritas::UniformAlongStepFactory();

// NOTE: since no SD is enabled, we must manually disable Celeritas hit
// processing
setup_options.sd.enabled = false;
}

G4VPhysicalVolume* Construct() final
{
CELER_LOG_LOCAL(status) << "Setting up geometry";
auto* box = new G4Box("world", 1000 * cm, 1000 * cm, 1000 * cm);
auto* box = new G4Box("world", 100 * cm, 100 * cm, 100 * cm);
auto* lv = new G4LogicalVolume(box, aluminum_, "world");
auto* pv = new G4PVPlacement(
0, G4ThreeVector{}, lv, "world", nullptr, false, 0);
Expand All @@ -96,27 +80,24 @@ class DetectorConstruction final : public G4VUserDetectorConstruction
"DefaultRegionForTheWorld");
// Underlying GVFastSimulationModel constructor handles ownership, so
// we must ignore the returned pointer...
new celeritas::FastSimulationModel("accel::FastSimulationModel",
default_region,
&shared_params,
&local_transporter);
new celeritas::FastSimulationModel(default_region);
}

private:
G4Material* aluminum_;
};

//---------------------------------------------------------------------------//
// Generate 100 MeV neutrons
// Generate 200 MeV pi+
class PrimaryGeneratorAction final : public G4VUserPrimaryGeneratorAction
{
public:
PrimaryGeneratorAction()
{
auto g4particle_def
= G4ParticleTable::GetParticleTable()->FindParticle(2112);
= G4ParticleTable::GetParticleTable()->FindParticle(211);
gun_.SetParticleDefinition(g4particle_def);
gun_.SetParticleEnergy(100 * MeV);
gun_.SetParticleEnergy(200 * MeV);
gun_.SetParticlePosition(G4ThreeVector{0, 0, 0}); // origin
gun_.SetParticleMomentumDirection(G4ThreeVector{1, 0, 0}); // +x
}
Expand All @@ -137,21 +118,11 @@ class RunAction final : public G4UserRunAction
public:
void BeginOfRunAction(G4Run const* run) final
{
simple_offload.BeginOfRunAction(run);
FastSimulationIntegration::Instance().BeginOfRunAction(run);
}
void EndOfRunAction(G4Run const* run) final
{
simple_offload.EndOfRunAction(run);
}
};

//---------------------------------------------------------------------------//
class EventAction final : public G4UserEventAction
{
public:
void BeginOfEventAction(G4Event const* event) final
{
simple_offload.BeginOfEventAction(event);
FastSimulationIntegration::Instance().EndOfRunAction(run);
}
};

Expand All @@ -161,32 +132,57 @@ class ActionInitialization final : public G4VUserActionInitialization
public:
void BuildForMaster() const final
{
simple_offload.BuildForMaster(&setup_options, &shared_params);
FastSimulationIntegration::Instance().BuildForMaster();

CELER_LOG_LOCAL(status) << "Constructing user actions";

this->SetUserAction(new RunAction{});
}
void Build() const final
{
simple_offload.Build(
&setup_options, &shared_params, &local_transporter);
FastSimulationIntegration::Instance().Build();

CELER_LOG_LOCAL(status) << "Constructing user actions";

this->SetUserAction(new PrimaryGeneratorAction{});
this->SetUserAction(new RunAction{});
this->SetUserAction(new EventAction{});
}
};

//---------------------------------------------------------------------------//
/*!
* Construct options for Celeritas.
*/
celeritas::SetupOptions MakeOptions()
{
celeritas::SetupOptions opts;
// NOTE: these numbers are appropriate for CPU execution
opts.max_num_tracks = 2024;
opts.initializer_capacity = 2024 * 128;
// Celeritas does not support EmStandard MSC physics above 200 MeV
opts.ignore_processes = {"CoulombScat"};

// NOTE: since no SD is enabled, we must manually disable Celeritas hit
// processing
opts.sd.enabled = false;

// Use a uniform (zero) magnetic field
opts.make_along_step = celeritas::UniformAlongStepFactory();

// Export a GDML file with the problem setup and SDs
opts.geometry_output_file = "simple-example.gdml";
// Save diagnostic file to a unique name
opts.output_file = "fastsim-offload.out.json";
return opts;
}

//---------------------------------------------------------------------------//
} // namespace

int main()
{
auto run_manager = [] {
#if G4VERSION_NUMBER >= 1100
#if G4VERSION_NUMBER >= 1200
return std::unique_ptr<G4RunManager>{
G4RunManagerFactory::CreateRunManager()};
#else
Expand All @@ -209,12 +205,7 @@ int main()

run_manager->SetUserInitialization(new ActionInitialization());

// NOTE: these numbers are appropriate for CPU execution
setup_options.max_num_tracks = 1024;
setup_options.initializer_capacity = 1024 * 128;
// Celeritas does not support EmStandard MSC physics above 100 MeV
setup_options.ignore_processes = {"CoulombScat"};
setup_options.output_file = "fastsim-offload.out.json";
FastSimulationIntegration::Instance().SetOptions(MakeOptions());

run_manager->Initialize();
run_manager->BeamOn(2);
Expand Down
Loading

0 comments on commit 6580368

Please sign in to comment.