Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:11:32

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file celeritas/g4/StateDependent.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <functional>
0010 #include <utility>
0011 #include <G4VStateDependent.hh>
0012 
0013 #include "corecel/Macros.hh"
0014 #include "corecel/sys/ThreadId.hh"
0015 
0016 class G4StateManager;
0017 
0018 namespace celeritas
0019 {
0020 //---------------------------------------------------------------------------//
0021 /*!
0022  * Encode a meaningful Geant4 state transition for user callbacks.
0023  *
0024  * The transitions are encoded as `GeantStateChange` values according to
0025  * the following table (previous -> requested):
0026  *
0027  * | Previous State         | Requested State        | Change          |
0028  * |------------------------|------------------------|-----------------|
0029  * | *none*                 | `G4State_PreInit`      | `begin_program` |
0030  * | `G4State_PreInit`      | `G4State_Init`         | `begin_init`    |
0031  * | `G4State_Idle`         | `G4State_Init`         | `begin_init`    |
0032  * | `G4State_Init`         | `G4State_Init`         | `internal_init` |
0033  * | `G4State_Init`         | `G4State_Idle`         | `end_init`      |
0034  * | `G4State_Idle`         | `G4State_GeomClosed`   | `begin_run`     |
0035  * | `G4State_GeomClosed`   | `G4State_EventProc`    | `begin_event`   |
0036  * | `G4State_EventProc`    | `G4State_GeomClosed`   | `end_event`     |
0037  * | `G4State_GeomClosed`   | `G4State_Idle`         | `end_run`       |
0038  * | *any*                  | `G4State_Quit`         | `end_program`   |
0039  * | *any*                  | `G4State_Abort`        | `end_program`   |
0040  * | *other*                | *other*                | `unknown`       |
0041  *
0042  * \par Notes:
0043  *
0044  * - \c begin_program is called during the \c G4RunManagerKernel constructor,
0045  *   so it will only register if your state dependent is constructed very early
0046  *   and on the main thread.
0047  * - In raw mode, the first \c G4State_Init transition from \c G4State_PreInit
0048  *   emits an extra \c initialize callback before \c begin_init.
0049  * - In MT mode, \c RunManager::Initialize actually calls begin/end run for
0050  *   each thread, including master.
0051  * - \c end_program is called by the G4RunManager and G4RunManagerKernel
0052  *   destructor during normal execution (via \c G4State_Quit).
0053  * - \c end_program is called by \c G4Exception when a fatal error occurred
0054  *   (via \c G4State_Abort).
0055  */
0056 enum class GeantStateChange
0057 {
0058     begin_program,
0059     initialize,
0060     begin_init,
0061     internal_init,
0062     end_init,
0063     begin_run,
0064     begin_event,
0065     end_event,
0066     end_run,
0067     end_program,
0068     unknown,
0069     size_,
0070 };
0071 
0072 // Callback receives a stream id and the encoded `GeantStateChange`.
0073 using LocalGeantStateChangeFunc
0074     = std::function<void(StreamId, GeantStateChange)>;
0075 
0076 //---------------------------------------------------------------------------//
0077 // HELPER FUNCTIONS (HOST)
0078 //---------------------------------------------------------------------------//
0079 
0080 // Get a string corresponding to a Geant4 state change
0081 char const* to_cstring(GeantStateChange);
0082 
0083 //---------------------------------------------------------------------------//
0084 /*!
0085  * Receive notifications when the Geant4 application state changes.
0086  *
0087  * This thread-local wrapper observes Geant4 application state transitions and
0088  * calls a shared user-provided function for the creating stream. Raw mode
0089  * dispatches every encoded state transition; lifecycle mode dispatches the
0090  * filtered run lifecycle used by automatic Celeritas setup.
0091  *
0092  * \warning  The Geant4 memory semantics for this class are unusual.
0093  * - The thread-local \c G4StateManager singleton keeps a pointer (via the \c
0094  *   G4VStateDependent base constructor) to this local instance and calls \c
0095  *   delete on it when it's deleted as the run manager shuts down.
0096  *   Therefore this class \c must be deleted before \c G4StateManager ends.
0097  * - The base class destructor calls the thread-local \c G4StateManager without
0098  *   checking for validity, so the destructor of this class \em after deleting
0099  *   the run manager will also crash the code.
0100  * - The thread-local pointer mapping means that this class \em must be
0101  *   deallocated on the thread in which it's created.
0102  *
0103  * To bypass the first failure path, we use \c Notify to deregister ourselves
0104  * when we see the run manager is about to exit or abort.
0105  *
0106  * The owner must keep the instance on the creating thread and callbacks must
0107  * not delete the active state-dependent object. In lifecycle mode this object
0108  * should be owned explicitly, similarly to Geant4 UI messenger objects.
0109  *
0110  * In \c Mode::lifecycle this class filters raw Geant4 state changes into the
0111  * lifecycle transitions needed by Celeritas automatic setup: \c begin_run,
0112  * \c end_run, and \c end_program.
0113  */
0114 class StateDependent final : public G4VStateDependent
0115 {
0116   public:
0117     //! How to dispatch Geant4 state changes
0118     enum class Mode
0119     {
0120         raw,
0121         lifecycle,
0122     };
0123 
0124     //! Lifecycle cleanup scope owned by this monitor
0125     enum class LifecycleRole
0126     {
0127         global,
0128         local,
0129     };
0130 
0131     // Construct locally with state-change callback, dispatch mode, and
0132     // lifecycle role
0133     StateDependent(
0134         LocalGeantStateChangeFunc cb, Mode mode, LifecycleRole lifecycle_role);
0135 
0136     //! Construct locally in raw mode with a state-change callback
0137     explicit StateDependent(LocalGeantStateChangeFunc cb)
0138         : StateDependent{std::move(cb), Mode::raw, LifecycleRole::global}
0139     {
0140     }
0141 
0142     // Prevent move/copy because the base class registers this object by
0143     // pointer
0144     CELER_DELETE_COPY_MOVE(StateDependent);
0145 
0146     // Handle notification when the Geant4 state changes
0147     G4bool Notify(G4ApplicationState state) final;
0148 
0149     //! Stream that created this state dependent
0150     StreamId local_stream() const { return local_stream_; }
0151 
0152   private:
0153     StreamId local_stream_;
0154     LocalGeantStateChangeFunc cb_;
0155     G4StateManager* manager_{nullptr};
0156     Mode mode_{Mode::raw};
0157     LifecycleRole lifecycle_role_{LifecycleRole::global};
0158 
0159     // Whether this local monitor has emitted a lifecycle begin_run that still
0160     // needs a matching end_run.
0161     bool active_run_{false};
0162 
0163     // Dispatch a filtered lifecycle change
0164     void dispatch_lifecycle_change(GeantStateChange);
0165 };
0166 
0167 //---------------------------------------------------------------------------//
0168 }  // namespace celeritas