Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:03

0001 /**
0002 G4CXApp.h  : Geant4 Application integrated with G4CXOpticks within a single header
0003 =========================================================================================
0004 
0005 This ~300 line header does everything to setup a Geant4 app and integrate G4CXOpticks
0006 plus a U4Recorder instance that collects the details of the Geant4 simulation in Opticks SEvt
0007 format to facilitate comparison of Opticks and Geant4 optical simulations.
0008 
0009 Note that the methods are not inlined, but that does not matter as this should only be included
0010 once into the main. This was initially based upon u4/U4App.h with the addition of G4CXOpticks
0011 
0012 Geometry setup in G4CXApp::Construct is done by U4VolumeMaker::PV which is controlled by the GEOM envvar.
0013 
0014 **/
0015 
0016 #include <csignal>
0017 
0018 #include "G4RunManager.hh"
0019 #include "G4VUserDetectorConstruction.hh"
0020 #include "G4VUserPrimaryGeneratorAction.hh"
0021 #include "G4UserRunAction.hh"
0022 #include "G4UserEventAction.hh"
0023 #include "G4UserTrackingAction.hh"
0024 #include "G4UserSteppingAction.hh"
0025 
0026 #include "G4SystemOfUnits.hh"
0027 #include "G4ParticleTable.hh"
0028 #include "G4ParticleGun.hh"
0029 #include "G4GeometryManager.hh"
0030 
0031 
0032 #include "ssys.h"
0033 #include "sframe.h"
0034 
0035 #include "OPTICKS_LOG.hh"
0036 #include "SEvt.hh"
0037 #include "SSim.hh"
0038 #include "SEventConfig.hh"
0039 #include "SRM.h"
0040 #include "SGenerate.h"
0041 #include "SEvent.hh"
0042 
0043 
0044 #include "U4Material.hh"
0045 #include "U4VolumeMaker.hh"
0046 #include "U4Recorder.hh"
0047 #include "U4Random.hh"
0048 #include "U4Physics.hh"
0049 #include "U4SensitiveDetector.hh"
0050 #include "U4VPrimaryGenerator.h"
0051 
0052 #include "G4CXOpticks.hh"
0053 
0054 
0055 struct G4CXApp
0056     :
0057     public G4UserRunAction,
0058     public G4UserEventAction,
0059     public G4UserTrackingAction,
0060     public G4UserSteppingAction,
0061     public G4VUserPrimaryGeneratorAction,
0062     public G4VUserDetectorConstruction
0063 {
0064     static const plog::Severity LEVEL ;
0065     static std::string Desc();
0066     static G4ParticleGun* InitGun();
0067     static U4SensitiveDetector* InitSensDet();
0068 
0069     G4RunManager*         fRunMgr ;
0070     U4Recorder*           fRecorder ;
0071     G4ParticleGun*        fGun ;
0072     U4SensitiveDetector*  fSensDet ;
0073     G4VPhysicalVolume*    fPV ;
0074 
0075 
0076     G4VPhysicalVolume* Construct();
0077 
0078     void BeginOfRunAction(const G4Run*);
0079     void EndOfRunAction(const G4Run*);
0080 
0081     void GeneratePrimaries(G4Event* evt);
0082     void BeginOfEventAction(const G4Event*);
0083     void EndOfEventAction(const G4Event*);
0084 
0085     void PreUserTrackingAction(const G4Track*);
0086     void PostUserTrackingAction(const G4Track*);
0087 
0088     void UserSteppingAction(const G4Step*);
0089 
0090 
0091     G4CXApp(G4RunManager* runMgr);
0092     static void OpenGeometry() ;
0093     virtual ~G4CXApp();
0094 
0095     static G4RunManager* InitRunManager();
0096     static G4CXApp*        Create();
0097     void                 BeamOn() ;
0098     static int           Main();
0099 
0100 };
0101 
0102 const plog::Severity G4CXApp::LEVEL = info ;   // PLOG logging level control doesnt work in the main
0103 
0104 std::string G4CXApp::Desc() // static
0105 {
0106     std::string phy = U4Physics::Desc() ;
0107     std::string rec = U4Recorder::Desc() ;
0108     std::stringstream ss ;
0109     if(!phy.empty()) ss << phy  ;
0110     if(!rec.empty()) ss << "/" << rec ;
0111     std::string s = ss.str();
0112     return s ;
0113 }
0114 
0115 G4ParticleGun* G4CXApp::InitGun() // static
0116 {
0117     G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
0118     G4ParticleDefinition* particle = particleTable->FindParticle("e+");
0119     LOG(LEVEL) << " particle " << particle ;
0120     G4ParticleGun* gun = new G4ParticleGun(1) ;
0121     gun->SetParticleDefinition(particle);
0122     gun->SetParticleTime(0.0*CLHEP::ns);
0123     gun->SetParticlePosition(G4ThreeVector(0.0*CLHEP::cm,0.0*CLHEP::cm,0.0*CLHEP::cm));
0124     gun->SetParticleMomentumDirection(G4ThreeVector(1.,0.,0.));
0125     gun->SetParticleEnergy(1.0*MeV);
0126     return gun ;
0127 }
0128 
0129 U4SensitiveDetector* G4CXApp::InitSensDet() // static
0130 {
0131     const char* sdn = ssys::getenvvar("G4CXApp__SensDet", "PMTSDMgr" ) ;
0132     U4SensitiveDetector* sd = sdn ? new U4SensitiveDetector(sdn) : nullptr ;
0133     std::cout
0134         << "G4CXApp::InitSensDet"
0135         << " sdn " << ( sdn ? sdn : "-" )
0136         << " sd " << ( sd ? "YES" : "NO " )
0137         << std::endl
0138         << U4SensitiveDetector::Desc()
0139         << std::endl
0140         ;
0141     return sd ;
0142 }
0143 
0144 G4CXApp::G4CXApp(G4RunManager* runMgr)
0145     :
0146     fRunMgr(runMgr),
0147     fRecorder(new U4Recorder),
0148     fGun(SEventConfig::IsRunningModeGun() ? InitGun() : nullptr),
0149     fSensDet(InitSensDet()),
0150     fPV(nullptr)
0151 {
0152     fRunMgr->SetUserInitialization((G4VUserDetectorConstruction*)this);
0153     fRunMgr->SetUserAction((G4VUserPrimaryGeneratorAction*)this);
0154     fRunMgr->SetUserAction((G4UserRunAction*)this);
0155     fRunMgr->SetUserAction((G4UserEventAction*)this);
0156     fRunMgr->SetUserAction((G4UserTrackingAction*)this);
0157     fRunMgr->SetUserAction((G4UserSteppingAction*)this);
0158     fRunMgr->Initialize();
0159 
0160     LOG(info) << std::endl << U4Recorder::Desc() ;
0161 }
0162 
0163 G4VPhysicalVolume* G4CXApp::Construct()
0164 {
0165     LOG(info) << "[" ;
0166     const G4VPhysicalVolume* pv_ = U4VolumeMaker::PV() ;
0167     LOG_IF(fatal, pv_ == nullptr)
0168         << " FAILED TO CREATE PV : CHECK GEOM envvar "
0169         << std::endl
0170         << U4VolumeMaker::Desc()
0171         ;
0172 
0173     if(pv_ == nullptr) std::raise(SIGINT) ;
0174 
0175     G4VPhysicalVolume* pv = const_cast<G4VPhysicalVolume*>(pv_);
0176     fPV = pv ;
0177     LOG(LEVEL) << " fPV " << ( fPV ? fPV->GetName() : "ERR-NO-PV" ) ;
0178 
0179     LOG(info) << "]" ;
0180 
0181     // Collect extra JUNO PMT info only when persisted NPFold exists.
0182     SSim::AddExtraSubfold("jpmt", "$CFBaseFromGEOM/CSGFoundry/SSim/extra/jpmt" );
0183 
0184 
0185     if(SEventConfig::GPU_Simulation())
0186     {
0187         G4CXOpticks::SetGeometry(pv_) ;
0188         G4CXOpticks::SaveGeometry() ;
0189         //fRecorder->setU4Tree(G4CXOpticks::GetU4Tree());
0190         assert( fRecorder->getU4Tree() ); // U4Tree should be set within fRecorder by U4Tree::initRecorder
0191     }
0192     else
0193     {
0194         LOG(LEVEL) << " SEventConfig::GPU_Simulation() false : SKIP G4CXOpticks::SetGeometry " ;
0195     }
0196 
0197     return pv ;
0198 }
0199 
0200 void G4CXApp::BeginOfRunAction(const G4Run* run){ fRecorder->BeginOfRunAction(run);   }
0201 void G4CXApp::EndOfRunAction(const G4Run* run){   fRecorder->EndOfRunAction(run);     }
0202 
0203 
0204 /**
0205 G4CXApp::GeneratePrimaries
0206 ------------------------------------
0207 
0208 Other that for gun running this uses U4VPrimaryGenerator::GeneratePrimaries
0209 which is based on SGenerate::GeneratePhotons
0210 
0211 As U4VPrimaryGenerator::GeneratePrimaries needs the gensteps early
0212 (before U4Recorder::BeginOfEventAction invokes SEvt::beginOfEvent)
0213 to allow Geant4 to use SGenerate::GeneratePhotons it is necessary
0214 to SEvt::addTorchGenstep here.
0215 
0216 But thats means cannot use the normal EGPU pattern of adding gensteps
0217 in the SEvt::beginOfEvent call.
0218 That causes kludgy SEvt::addFrameGenstep
0219 
0220 Torch running assumes comma delimited genstep and photon config
0221 with the same number of entries in each.
0222 
0223 
0224 **/
0225 
0226 void G4CXApp::GeneratePrimaries(G4Event* event)
0227 {
0228     G4int eventID = event->GetEventID();
0229 
0230     LOG(LEVEL) << "[ SEventConfig::RunningModeLabel " << SEventConfig::RunningModeLabel() << " eventID " << eventID ;
0231     SEvt* sev = SEvt::Get_ECPU();
0232     assert(sev);
0233 
0234     if(SEventConfig::IsRunningModeGun())
0235     {
0236         LOG(fatal) << " THIS MODE NEEDS WORK ON U4PHYSICS " ;
0237         std::raise(SIGINT);
0238         fGun->GeneratePrimaryVertex(event) ;
0239     }
0240     else if(SEventConfig::IsRunningModeTorch())
0241     {
0242         int idx_arg = eventID ;
0243         NP* gs = SEvent::MakeTorchGenstep(idx_arg) ;  // idx_arg > -1 implies comma delimited num_gs num_ph envvars
0244         NP* ph = SGenerate::GeneratePhotons(gs);
0245         U4VPrimaryGenerator::GeneratePrimaries_From_Photons(event, ph);
0246         delete ph ;
0247 
0248         SEvent::SetGENSTEP(gs);  // picked up by
0249     }
0250     else if(SEventConfig::IsRunningModeInputPhoton())
0251     {
0252         NP* ph = sev->getInputPhoton();
0253         U4VPrimaryGenerator::GeneratePrimaries_From_Photons(event, ph) ;
0254     }
0255     else if(SEventConfig::IsRunningModeInputGenstep())
0256     {
0257         LOG(fatal) << "General InputGensteps with Geant4 not implemented, use eg cxs_min.sh to do that with Opticks " ;
0258         std::raise(SIGINT);
0259     }
0260     LOG(LEVEL) << "] " << " eventID " << eventID  ;
0261 }
0262 
0263 /**
0264 G4CXApp::BeginOfEventAction
0265 ----------------------------
0266 
0267 Its too late to SEvt::AddTorchGenstep here as GeneratePrimaries already run
0268 
0269 **/
0270 
0271 void G4CXApp::BeginOfEventAction(const G4Event* event)
0272 {
0273     G4int eventID = event->GetEventID();
0274     fRecorder->BeginOfEventAction_(eventID);
0275 }
0276 
0277 /**
0278 G4CXApp::EndOfEventAction
0279 ---------------------------
0280 
0281 ::
0282 
0283      ECPU.begin
0284 
0285 
0286      ECPU.end.HEAD
0287 
0288        G4CXOpticks::simulate
0289 
0290           QSim::simulate.HEAD
0291               EGPU.begin
0292               simulate_launch
0293               EGPU.end
0294           QSim::simulate.TAIL
0295 
0296      ECPU.end.TAIL
0297 
0298 **/
0299 
0300 
0301 void G4CXApp::EndOfEventAction(const G4Event* event)
0302 {
0303     G4int eventID = event->GetEventID();
0304     fRecorder->EndOfEventAction_(eventID);   // saves SEvt::ECPU
0305 
0306     if(SEventConfig::GPU_Simulation())
0307     {
0308         G4CXOpticks* gx = G4CXOpticks::Get() ;
0309         bool end = true ;
0310         gx->simulate(eventID, end ) ;
0311     }
0312 }
0313 
0314 void G4CXApp::PreUserTrackingAction(const G4Track* trk){  fRecorder->PreUserTrackingAction(trk); }
0315 void G4CXApp::PostUserTrackingAction(const G4Track* trk){ fRecorder->PostUserTrackingAction(trk); }
0316 void G4CXApp::UserSteppingAction(const G4Step* step){     fRecorder->UserSteppingAction(step) ; }
0317 
0318 void G4CXApp::OpenGeometry(){  G4GeometryManager::GetInstance()->OpenGeometry(); } // static
0319 G4CXApp::~G4CXApp(){ OpenGeometry(); }
0320 // G4GeometryManager::OpenGeometry is needed to avoid cleanup warning
0321 
0322 
0323 G4RunManager* G4CXApp::InitRunManager()  // static
0324 {
0325     G4VUserPhysicsList* phy = (G4VUserPhysicsList*)new U4Physics ;
0326     G4RunManager* run = new G4RunManager ;
0327     run->SetUserInitialization(phy) ;
0328     return run ;
0329 }
0330 
0331 /**
0332 G4CXApp::Create
0333 ----------------
0334 
0335 Geant4 requires G4RunManager to be instanciated prior to the Actions
0336 
0337 **/
0338 
0339 G4CXApp* G4CXApp::Create()  // static
0340 {
0341     LOG(info) << U4Recorder::Switches() ;
0342 
0343     G4RunManager* run = InitRunManager();
0344     G4CXApp* app = new G4CXApp(run);
0345     return app ;
0346 }
0347 
0348 void G4CXApp::BeamOn()
0349 {
0350     LOG(info) << "[ " << SEventConfig::kNumEvent << "=" << SEventConfig::NumEvent()  ;
0351     fRunMgr->BeamOn(SEventConfig::NumEvent()) ;
0352     LOG(info) << "]" ;
0353 }
0354 
0355 int G4CXApp::Main()  // static
0356 {
0357     G4CXApp* app = G4CXApp::Create() ;
0358     app->BeamOn();
0359     delete app ;  // avoids "Attempt to delete the (physical volume/logical volume/solid/region) store while geometry closed" warnings
0360     return 0 ;
0361 }
0362