Skip to content

Commit

Permalink
Implement offload to Celeritas from Geant4 using G4VTrackingManager h…
Browse files Browse the repository at this point in the history
…ook (#1050)

* Implement concrete G4VTrackingManager for offload to Celeritas

Interface for offload of tracks to Celeritas via Geant4's G4VTrackingManager
hook introduced in v11.0, complementing existing fast simulation,
tracking action offload strategies.

Implementations of offload and flush largely follow those of
existing fast simulation offload. Build/PreparePhysicsTable are
overidden to ensure Geant4 tables for the particle(s) handled
by the tracking manager are rebuilt and thus available to
Celeritas to build its tables. This follows the Geant4 extended
runAndEvent/RE07 example.

Restrict build of class to Geant4 11.0 and higher as abstract
G4VTrackingManager interface is not available prior to that.

* Minimal example of using TrackingManagerOffload

Largely copy-paste of existing simple/fastsim offload examples, adapted
for new TrackingManagerOffload class. Primary changes are:

* Custom physics constructor inheriting from G4EmStandardPhysics
  * Overrides ConstructProcess, taking base class defaults except for
    constructing a TrackingManagerOffload instance and adding this
    to the electron, positron, and gamma particle definitions
* Replace EM physics in FTFP_BERT physics lists with this new physics
  constructor

* Add basic docs on TrackingManagerOffload

* Remove particle type validation

Prepare/BuildPhysicsTable have to be called before Celeritas'
SharedParams can be constructed, and so the list of offloadable
particles will be empty.

Remove validation check here as it cannot be run at this point.

* Log call to ConstructProcess to clarify use on master/worker

Co-authored-by: Seth R. Johnson <johnsonsr@ornl.gov>

* Add trailing full stop to satisfy Doxygen autobrief

* Test offload examples in each Geant4 threading model

For each offload example, add a test that runs it with each of Geant4's
threading types:

- Serial
- MT (standard C++ threads)
- Tasking (PTL-based tasks+threadpool)

Only enable the latter two if the found Geant4 supports them.

* Clarify implementations of physics table functions

- Use contracts on pointers that require deref
- Follow GeantImporter implementation for loop over processes

A cleaner range-based for over processes isn't possible due to
G4ProcessVector not providing a directly compatible interface.
  • Loading branch information
drbenmorgan committed Dec 7, 2023
1 parent e3610f9 commit 2f17ea0
Show file tree
Hide file tree
Showing 6 changed files with 459 additions and 14 deletions.
7 changes: 7 additions & 0 deletions doc/main/examples/geant4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ or multithreaded environment using:

#. A concrete G4UserTrackingAction user action class
#. A concrete G4VFastSimulationModel
#. A concrete G4VTrackingManager

The :ref:`accel` library is the only part of Celeritas that needs to be understood.
The key components are global SetupOptions and SharedParams, coupled to thread-local
Expand Down Expand Up @@ -46,3 +47,9 @@ Offload using a concrete G4VFastSimulationModel

.. literalinclude:: ../../../example/accel/fastsim-offload.cc
:start-at: #include

Offload using a concrete G4VTrackingManager
--------------------------------------------

.. literalinclude:: ../../../example/accel/trackingmanager-offload.cc
:start-at: #include
57 changes: 43 additions & 14 deletions example/accel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,65 @@ celeritas_target_link_libraries(fastsim-offload
${Geant4_LIBRARIES}
)

if(Geant4_VERSION VERSION_LESS 11.0)
message(WARNING "G4VTrackingManager offload requires Geant4 11.0 or higher")
else()
add_executable(trackingmanager-offload trackingmanager-offload.cc)
celeritas_target_link_libraries(trackingmanager-offload
Celeritas::accel
${Geant4_LIBRARIES}
)
endif()

# END EXAMPLE CODE

#-----------------------------------------------------------------------------#
# Add tests for CI
#-----------------------------------------------------------------------------#

include(CTest)
function(add_example target)
add_test(NAME "${target}" COMMAND "$<TARGET_FILE:${target}>")
endfunction()

set(_test_env)
set(_g4data_env)
foreach(_ds IN LISTS Geant4_DATASETS)
list(APPEND _test_env
list(APPEND _g4data_env
"${Geant4_DATASET_${_ds}_ENVVAR}=${Geant4_DATASET_${_ds}_PATH}")
endforeach()

function(add_example target)
add_example_impl(${target} Serial)
if(Geant4_multithreaded_FOUND)
add_example_impl(${target} MT)
add_example_impl(${target} Tasking)
endif()
endfunction()

function(disable_example target)
set(_tests ${target}-Serial)
if(Geant4_multithreaded_FOUND)
list(APPEND _tests ${target}-MT ${target}-Tasking)
endif()
set_tests_properties(${_tests} PROPERTIES
DISABLED true
)
endfunction()

function(add_example_impl target rmtype)
set(_test_name "${target}-${rmtype}")
add_test(NAME "${_test_name}" COMMAND "$<TARGET_FILE:${target}>")
set_tests_properties(${_test_name} PROPERTIES
ENVIRONMENT "${_g4data_env};G4RUN_MANAGER_TYPE=${rmtype}"
LABELS "app"
)
endfunction()

#-----------------------------------------------------------------------------#

add_example(simple-offload)
add_example(fastsim-offload)

set_tests_properties(simple-offload fastsim-offload PROPERTIES
ENVIRONMENT "${_test_env}"
LABELS "app"
)

if(Geant4_VERSION VERSION_LESS 11.1)
set_tests_properties(fastsim-offload PROPERTIES
DISABLED true
)
disable_example(fastsim-offload)
endif()

if(Geant4_VERSION VERSION_GREATER_EQUAL 11.0)
add_example(trackingmanager-offload)
endif()
210 changes: 210 additions & 0 deletions example/accel/trackingmanager-offload.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file example/accel/trackingmanager-offload.cc
//---------------------------------------------------------------------------//

#include <algorithm>
#include <iterator>
#include <type_traits>
#include <FTFP_BERT.hh>
#include <G4Box.hh>
#include <G4Electron.hh>
#include <G4EmStandardPhysics.hh>
#include <G4Gamma.hh>
#include <G4LogicalVolume.hh>
#include <G4Material.hh>
#include <G4PVPlacement.hh>
#include <G4ParticleDefinition.hh>
#include <G4ParticleGun.hh>
#include <G4ParticleTable.hh>
#include <G4Positron.hh>
#include <G4Region.hh>
#include <G4RegionStore.hh>
#include <G4RunManagerFactory.hh>
#include <G4SystemOfUnits.hh>
#include <G4Threading.hh>
#include <G4ThreeVector.hh>
#include <G4Track.hh>
#include <G4TrackStatus.hh>
#include <G4Types.hh>
#include <G4UserEventAction.hh>
#include <G4UserRunAction.hh>
#include <G4UserTrackingAction.hh>
#include <G4VUserActionInitialization.hh>
#include <G4VUserDetectorConstruction.hh>
#include <G4VUserPrimaryGeneratorAction.hh>
#include <accel/AlongStepFactory.hh>
#include <accel/LocalTransporter.hh>
#include <accel/SetupOptions.hh>
#include <accel/SharedParams.hh>
#include <accel/SimpleOffload.hh>
#include <accel/TrackingManagerOffload.hh>
#include <corecel/Macros.hh>
#include <corecel/io/Logger.hh>

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
{
public:
DetectorConstruction()
: aluminum_{new G4Material{
"Aluminium", 13., 26.98 * g / mole, 2.700 * g / cm3}}
{
setup_options.make_along_step = celeritas::UniformAlongStepFactory();
}

G4VPhysicalVolume* Construct() final
{
CELER_LOG_LOCAL(status) << "Setting up detector";
auto* box = new G4Box("world", 1000 * cm, 1000 * cm, 1000 * cm);
auto* lv = new G4LogicalVolume(box, aluminum_, "world");
auto* pv = new G4PVPlacement(
0, G4ThreeVector{}, lv, "world", nullptr, false, 0);
return pv;
}

private:
G4Material* aluminum_;
};

//---------------------------------------------------------------------------//
class EMPhysicsConstructor final : public G4EmStandardPhysics
{
public:
using G4EmStandardPhysics::G4EmStandardPhysics;

void ConstructProcess() override
{
CELER_LOG_LOCAL(status) << "Setting up tracking manager offload";
G4EmStandardPhysics::ConstructProcess();

// Add Celeritas tracking manager to electron, positron, gamma.
auto* celer_tracking = new celeritas::TrackingManagerOffload(
&shared_params, &local_transporter);
G4Electron::Definition()->SetTrackingManager(celer_tracking);
G4Positron::Definition()->SetTrackingManager(celer_tracking);
G4Gamma::Definition()->SetTrackingManager(celer_tracking);
}
};

//---------------------------------------------------------------------------//
class PrimaryGeneratorAction final : public G4VUserPrimaryGeneratorAction
{
public:
PrimaryGeneratorAction()
{
auto g4particle_def
= G4ParticleTable::GetParticleTable()->FindParticle(2112);
gun_.SetParticleDefinition(g4particle_def);
gun_.SetParticleEnergy(100 * GeV);
gun_.SetParticlePosition(G4ThreeVector{0, 0, 0}); // origin
gun_.SetParticleMomentumDirection(G4ThreeVector{1, 0, 0}); // +x
}

// Generate 100 GeV neutrons
void GeneratePrimaries(G4Event* event) final
{
CELER_LOG_LOCAL(status) << "Generating primaries";
gun_.GeneratePrimaryVertex(event);
}

private:
G4ParticleGun gun_;
};

//---------------------------------------------------------------------------//
class RunAction final : public G4UserRunAction
{
public:
void BeginOfRunAction(G4Run const* run) final
{
simple_offload.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);
}
};

//---------------------------------------------------------------------------//
class ActionInitialization final : public G4VUserActionInitialization
{
public:
void BuildForMaster() const final
{
simple_offload.BuildForMaster(&setup_options, &shared_params);

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

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

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

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

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

int main()
{
std::unique_ptr<G4RunManager> run_manager{
G4RunManagerFactory::CreateRunManager()}; // G4RunManagerType::SerialOnly)};

run_manager->SetUserInitialization(new DetectorConstruction{});

// Use FTFP_BERT, but replace EM constructor with our own that
// overrides ConstructProcess to use Celeritas tracking for e-/e+/g
auto physics_list = new FTFP_BERT{/* verbosity = */ 0};
physics_list->ReplacePhysics(new EMPhysicsConstructor);
run_manager->SetUserInitialization(physics_list);

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;
// This parameter will eventually be removed
setup_options.max_num_events = 1024;
// Celeritas does not support EmStandard MSC physics above 100 MeV
setup_options.ignore_processes = {"CoulombScat"};

run_manager->Initialize();
run_manager->BeamOn(1);

return 0;
}
4 changes: 4 additions & 0 deletions src/accel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ list(APPEND SOURCES

celeritas_polysource(ExceptionConverter)

if(Geant4_VERSION VERSION_GREATER_EQUAL 11.0)
list(APPEND SOURCES TrackingManagerOffload.cc)
endif()

if(CELERITAS_USE_JSON)
list(APPEND PRIVATE_DEPS nlohmann_json::nlohmann_json)
endif()
Expand Down

0 comments on commit 2f17ea0

Please sign in to comment.