File indexing completed on 2026-05-15 07:41:50
0001 #include <filesystem>
0002 #include <fstream>
0003 #include <iostream>
0004
0005 #include "G4AutoLock.hh"
0006 #include "G4BooleanSolid.hh"
0007 #include "G4Cerenkov.hh"
0008 #include "G4Electron.hh"
0009 #include "G4Event.hh"
0010 #include "G4GDMLParser.hh"
0011 #include "G4LogicalVolumeStore.hh"
0012 #include "G4OpBoundaryProcess.hh"
0013 #include "G4OpticalPhoton.hh"
0014 #include "G4PhysicalConstants.hh"
0015 #include "G4PrimaryParticle.hh"
0016 #include "G4PrimaryVertex.hh"
0017 #include "G4RunManager.hh"
0018 #include "G4RunManagerFactory.hh"
0019 #include "G4SDManager.hh"
0020 #include "G4Scintillation.hh"
0021 #include "G4SubtractionSolid.hh"
0022 #include "G4SystemOfUnits.hh"
0023 #include "G4THitsCollection.hh"
0024 #include "G4Threading.hh"
0025 #include "G4ThreeVector.hh"
0026 #include "G4Track.hh"
0027 #include "G4TrackStatus.hh"
0028 #include "G4UserEventAction.hh"
0029 #include "G4UserRunAction.hh"
0030 #include "G4UserSteppingAction.hh"
0031 #include "G4UserTrackingAction.hh"
0032 #include "G4VHit.hh"
0033 #include "G4VPhysicalVolume.hh"
0034 #include "G4VProcess.hh"
0035 #include "G4VUserDetectorConstruction.hh"
0036 #include "G4VUserPrimaryGeneratorAction.hh"
0037 #include "G4VisAttributes.hh"
0038
0039 #include "eic-opticks/g4cx/G4CXOpticks.hh"
0040 #include "eic-opticks/sysrap/NP.hh"
0041 #include "eic-opticks/sysrap/SEvt.hh"
0042 #include "eic-opticks/sysrap/STrackInfo.h"
0043 #include "eic-opticks/sysrap/spho.h"
0044 #include "eic-opticks/sysrap/sphoton.h"
0045 #include "eic-opticks/u4/U4.hh"
0046 #include "eic-opticks/u4/U4Random.hh"
0047 #include "eic-opticks/u4/U4StepPoint.hh"
0048 #include "eic-opticks/u4/U4Touchable.h"
0049 #include "eic-opticks/u4/U4Track.h"
0050
0051 namespace
0052 {
0053 G4Mutex genstep_mutex = G4MUTEX_INITIALIZER;
0054 }
0055
0056 bool IsSubtractionSolid(G4VSolid* solid)
0057 {
0058 if (!solid)
0059 return false;
0060
0061
0062 if (dynamic_cast<G4SubtractionSolid*>(solid))
0063 return true;
0064
0065
0066 G4BooleanSolid* booleanSolid = dynamic_cast<G4BooleanSolid*>(solid);
0067 if (booleanSolid)
0068 {
0069 G4VSolid* solidA = booleanSolid->GetConstituentSolid(0);
0070 G4VSolid* solidB = booleanSolid->GetConstituentSolid(1);
0071
0072
0073 if (IsSubtractionSolid(solidA) || IsSubtractionSolid(solidB))
0074 return true;
0075 }
0076
0077
0078 return false;
0079 }
0080
0081 std::string str_tolower(std::string s)
0082 {
0083 std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
0084 return s;
0085 }
0086
0087 struct PhotonHit : public G4VHit
0088 {
0089 PhotonHit() = default;
0090
0091 PhotonHit(unsigned id, G4double energy, G4double time, G4ThreeVector position, G4ThreeVector direction,
0092 G4ThreeVector polarization) :
0093 fid(id),
0094 fenergy(energy),
0095 ftime(time),
0096 fposition(position),
0097 fdirection(direction),
0098 fpolarization(polarization)
0099 {
0100 }
0101
0102
0103 PhotonHit(const PhotonHit& right) :
0104 G4VHit(right),
0105 fid(right.fid),
0106 fenergy(right.fenergy),
0107 ftime(right.ftime),
0108 fposition(right.fposition),
0109 fdirection(right.fdirection),
0110 fpolarization(right.fpolarization)
0111 {
0112 }
0113
0114
0115 const PhotonHit& operator=(const PhotonHit& right)
0116 {
0117 if (this != &right)
0118 {
0119 G4VHit::operator=(right);
0120 fid = right.fid;
0121 fenergy = right.fenergy;
0122 ftime = right.ftime;
0123 fposition = right.fposition;
0124 fdirection = right.fdirection;
0125 fpolarization = right.fpolarization;
0126 }
0127 return *this;
0128 }
0129
0130
0131 G4bool operator==(const PhotonHit& right) const
0132 {
0133 return (this == &right);
0134 }
0135
0136
0137 void Print() override
0138 {
0139 G4cout << "Detector id: " << fid << " energy: " << fenergy << " nm" << " time: " << ftime << " ns"
0140 << " position: " << fposition << " direction: " << fdirection << " polarization: " << fpolarization
0141 << G4endl;
0142 }
0143
0144
0145 G4int fid{0};
0146 G4double fenergy{0};
0147 G4double ftime{0};
0148 G4ThreeVector fposition{0, 0, 0};
0149 G4ThreeVector fdirection{0, 0, 0};
0150 G4ThreeVector fpolarization{0, 0, 0};
0151 };
0152
0153 using PhotonHitsCollection = G4THitsCollection<PhotonHit>;
0154
0155 struct PhotonSD : public G4VSensitiveDetector
0156 {
0157 PhotonSD(G4String name) :
0158 G4VSensitiveDetector(name),
0159 fHCID(-1)
0160 {
0161 G4String HCname = name + "_HC";
0162 collectionName.insert(HCname);
0163 G4cout << collectionName.size() << " PhotonSD name: " << name << " collection Name: " << HCname << G4endl;
0164 }
0165
0166 void Initialize(G4HCofThisEvent* hce) override
0167 {
0168 fPhotonHitsCollection = new PhotonHitsCollection(SensitiveDetectorName, collectionName[0]);
0169 if (fHCID < 0)
0170 {
0171
0172 fHCID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);
0173 }
0174 hce->AddHitsCollection(fHCID, fPhotonHitsCollection);
0175 }
0176
0177 G4bool ProcessHits(G4Step* aStep, G4TouchableHistory*) override
0178 {
0179 G4Track* theTrack = aStep->GetTrack();
0180 if (theTrack->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition())
0181 return false;
0182
0183 G4double theEnergy = theTrack->GetTotalEnergy() / CLHEP::eV;
0184
0185
0186 PhotonHit* newHit = new PhotonHit(
0187 0,
0188 theEnergy, theTrack->GetGlobalTime(), aStep->GetPostStepPoint()->GetPosition(),
0189 aStep->GetPostStepPoint()->GetMomentumDirection(), aStep->GetPostStepPoint()->GetPolarization());
0190
0191 fPhotonHitsCollection->insert(newHit);
0192 theTrack->SetTrackStatus(fStopAndKill);
0193 return true;
0194 }
0195
0196 void EndOfEvent(G4HCofThisEvent*) override
0197 {
0198 G4int NbHits = fPhotonHitsCollection->entries();
0199 G4cout << "PhotonSD::EndOfEvent Number of PhotonHits: " << NbHits << G4endl;
0200 }
0201
0202 void AddOpticksHits()
0203 {
0204 SEvt* sev = SEvt::Get_EGPU();
0205 unsigned int num_hits = sev->GetNumHit(0);
0206
0207 for (int idx = 0; idx < int(num_hits); idx++)
0208 {
0209 sphoton hit;
0210 sev->getHit(hit, idx);
0211 G4ThreeVector position = G4ThreeVector(hit.pos.x, hit.pos.y, hit.pos.z);
0212 G4ThreeVector direction = G4ThreeVector(hit.mom.x, hit.mom.y, hit.mom.z);
0213 G4ThreeVector polarization = G4ThreeVector(hit.pol.x, hit.pol.y, hit.pol.z);
0214 int theCreationProcessid;
0215 if (OpticksPhoton::HasCerenkovFlag(hit.flagmask))
0216 {
0217 theCreationProcessid = 0;
0218 }
0219 else if (OpticksPhoton::HasScintillationFlag(hit.flagmask))
0220 {
0221 theCreationProcessid = 1;
0222 }
0223 else
0224 {
0225 theCreationProcessid = -1;
0226 }
0227 std::cout << hit.wavelength << " " << position << " " << direction << " " << polarization << std::endl;
0228
0229 PhotonHit* newHit = new PhotonHit(0, hit.wavelength, hit.time, position, direction, polarization);
0230 fPhotonHitsCollection->insert(newHit);
0231 }
0232 }
0233
0234 private:
0235 PhotonHitsCollection* fPhotonHitsCollection{nullptr};
0236 G4int fHCID;
0237 };
0238
0239 struct DetectorConstruction : G4VUserDetectorConstruction
0240 {
0241 DetectorConstruction(std::filesystem::path gdml_file) :
0242 gdml_file_(gdml_file)
0243 {
0244 }
0245
0246 G4VPhysicalVolume* Construct() override
0247 {
0248 parser_.Read(gdml_file_.string(), false);
0249 G4VPhysicalVolume* world = parser_.GetWorldVolume();
0250
0251 G4CXOpticks::SetGeometry(world);
0252 G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
0253
0254 static G4VisAttributes invisibleVisAttr(false);
0255
0256
0257 if (lvStore && !lvStore->empty())
0258 {
0259
0260 for (auto& logicalVolume : *lvStore)
0261 {
0262 G4VSolid* solid = logicalVolume->GetSolid();
0263
0264
0265 if (IsSubtractionSolid(solid))
0266 {
0267
0268 logicalVolume->SetVisAttributes(&invisibleVisAttr);
0269
0270
0271 G4cout << "Hiding logical volume: " << logicalVolume->GetName() << G4endl;
0272 }
0273 }
0274 }
0275
0276 return world;
0277 }
0278
0279 void ConstructSDandField() override
0280 {
0281 G4cout << "ConstructSDandField is called." << G4endl;
0282 G4SDManager* SDman = G4SDManager::GetSDMpointer();
0283
0284 const G4GDMLAuxMapType* auxmap = parser_.GetAuxMap();
0285 for (auto const& [logVol, listType] : *auxmap)
0286 {
0287 for (auto const& auxtype : listType)
0288 {
0289 if (auxtype.type == "SensDet")
0290 {
0291 G4cout << "Attaching sensitive detector to logical volume: " << logVol->GetName() << G4endl;
0292 G4String name = logVol->GetName() + "_PhotonDetector";
0293 PhotonSD* aPhotonSD = new PhotonSD(name);
0294 SDman->AddNewDetector(aPhotonSD);
0295 logVol->SetSensitiveDetector(aPhotonSD);
0296 }
0297 }
0298 }
0299 }
0300
0301 private:
0302 std::filesystem::path gdml_file_;
0303 G4GDMLParser parser_;
0304 };
0305
0306 struct PrimaryGenerator : G4VUserPrimaryGeneratorAction
0307 {
0308 SEvt* sev;
0309
0310 PrimaryGenerator(SEvt* sev) :
0311 sev(sev)
0312 {
0313 }
0314
0315 void GeneratePrimaries(G4Event* event) override
0316 {
0317 G4ThreeVector position_mm(0.0 * m, 0.0 * m, 0.0 * m);
0318 G4double time_ns = 0;
0319 G4ThreeVector direction(0, 0.2, 0.8);
0320 G4double wavelength_nm = 0.1;
0321
0322 G4PrimaryVertex* vertex = new G4PrimaryVertex(position_mm, time_ns);
0323 G4PrimaryParticle* particle = new G4PrimaryParticle(G4Electron::Definition());
0324 particle->SetKineticEnergy(5 * GeV);
0325 particle->SetMomentumDirection(direction);
0326 vertex->SetPrimary(particle);
0327 event->AddPrimaryVertex(vertex);
0328 }
0329 };
0330
0331 struct EventAction : G4UserEventAction
0332 {
0333 SEvt* sev;
0334 G4int fTotalG4Hits{0};
0335
0336 EventAction(SEvt* sev) :
0337 sev(sev)
0338 {
0339 }
0340
0341 void BeginOfEventAction(const G4Event* event) override
0342 {
0343 }
0344
0345 void EndOfEventAction(const G4Event* event) override
0346 {
0347 G4HCofThisEvent* hce = event->GetHCofThisEvent();
0348 if (hce)
0349 {
0350 for (G4int i = 0; i < hce->GetNumberOfCollections(); i++)
0351 {
0352 G4VHitsCollection* hc = hce->GetHC(i);
0353 if (hc)
0354 {
0355 fTotalG4Hits += hc->GetSize();
0356 }
0357 }
0358 }
0359 }
0360
0361 G4int GetTotalG4Hits() const
0362 {
0363 return fTotalG4Hits;
0364 }
0365 };
0366
0367 struct RunAction : G4UserRunAction
0368 {
0369 EventAction* fEventAction;
0370
0371 RunAction(EventAction* eventAction) :
0372 fEventAction(eventAction)
0373 {
0374 }
0375
0376 void BeginOfRunAction(const G4Run* run) override
0377 {
0378 }
0379
0380 void EndOfRunAction(const G4Run* run) override
0381 {
0382 if (G4Threading::IsMasterThread())
0383 {
0384 G4CXOpticks* gx = G4CXOpticks::Get();
0385
0386 auto start = std::chrono::high_resolution_clock::now();
0387 gx->simulate(0, false);
0388 cudaDeviceSynchronize();
0389 auto end = std::chrono::high_resolution_clock::now();
0390
0391 std::chrono::duration<double> elapsed = end - start;
0392 std::cout << "Simulation time: " << elapsed.count() << " seconds" << std::endl;
0393
0394
0395 SEvt* sev = SEvt::Get_EGPU();
0396 unsigned int num_hits = sev->GetNumHit(0);
0397
0398 std::cout << "Opticks: NumCollected: " << sev->GetNumGenstepFromGenstep(0) << std::endl;
0399 std::cout << "Opticks: NumCollected: " << sev->GetNumPhotonCollected(0) << std::endl;
0400 std::cout << "Opticks: NumHits: " << num_hits << std::endl;
0401 std::cout << "Geant4: NumHits: " << fEventAction->GetTotalG4Hits() << std::endl;
0402 std::ofstream outFile("opticks_hits_output.txt");
0403 if (!outFile.is_open())
0404 {
0405 std::cerr << "Error opening output file!" << std::endl;
0406 return;
0407 }
0408
0409 const bool emit_trackid = getenv("OPTICKS_MC_TRUTH") != nullptr;
0410
0411
0412
0413
0414
0415
0416 if (getenv("OPTICKS_MC_TRUTH_BENCH"))
0417 {
0418 volatile uint64_t sink = 0;
0419 const NP* hit_np = sev->getHit();
0420 const sphoton* hits = reinterpret_cast<const sphoton*>(hit_np->bytes());
0421 const int M = int(sev->gs.size());
0422 auto bt0 = std::chrono::high_resolution_clock::now();
0423 for (int idx = 0; idx < int(num_hits); idx++)
0424 {
0425 sink ^= hits[idx].index;
0426 }
0427 auto bt1 = std::chrono::high_resolution_clock::now();
0428 int g = 0;
0429 for (int idx = 0; idx < int(num_hits); idx++)
0430 {
0431 const int64_t pidx = hits[idx].index;
0432 while (g + 1 < M && pidx >= sev->gs[g + 1].offset)
0433 ++g;
0434 int tid = pidx < sev->gs[g].offset + sev->gs[g].photons ? int(sev->genstep[g].trackid()) : -1;
0435 sink ^= hits[idx].index ^ unsigned(tid);
0436 }
0437 auto bt2 = std::chrono::high_resolution_clock::now();
0438 std::chrono::duration<double> base_t = bt1 - bt0;
0439 std::chrono::duration<double> mc_t = bt2 - bt1;
0440 double base_ns = num_hits > 0 ? 1e9 * base_t.count() / num_hits : 0.0;
0441 double mc_ns = num_hits > 0 ? 1e9 * mc_t.count() / num_hits : 0.0;
0442 std::cout << "Bench baseline: " << base_t.count() << " s (" << base_ns << " ns/hit)" << std::endl;
0443 std::cout << "Bench mctruth: " << mc_t.count() << " s (" << mc_ns << " ns/hit)" << std::endl;
0444 std::cout << "Bench delta: " << (mc_t.count() - base_t.count()) << " s (" << (mc_ns - base_ns)
0445 << " ns/hit) [sink=" << sink << "]" << std::endl;
0446 }
0447
0448 auto hit_loop_start = std::chrono::high_resolution_clock::now();
0449 const NP* hit_np_main = sev->getHit();
0450 const sphoton* hits_main = reinterpret_cast<const sphoton*>(hit_np_main->bytes());
0451 const int M_gs = int(sev->gs.size());
0452 int g_cur = 0;
0453 for (int idx = 0; idx < int(num_hits); idx++)
0454 {
0455 const sphoton& hit = hits_main[idx];
0456 G4ThreeVector position = G4ThreeVector(hit.pos.x, hit.pos.y, hit.pos.z);
0457 G4ThreeVector direction = G4ThreeVector(hit.mom.x, hit.mom.y, hit.mom.z);
0458 G4ThreeVector polarization = G4ThreeVector(hit.pol.x, hit.pol.y, hit.pol.z);
0459 int theCreationProcessid;
0460 if (OpticksPhoton::HasCerenkovFlag(hit.flagmask))
0461 {
0462 theCreationProcessid = 0;
0463 }
0464 else if (OpticksPhoton::HasScintillationFlag(hit.flagmask))
0465 {
0466 theCreationProcessid = 1;
0467 }
0468 else
0469 {
0470 theCreationProcessid = -1;
0471 }
0472
0473
0474
0475
0476 outFile << hit.time << " " << hit.wavelength << " " << "(" << position.x() << ", " << position.y()
0477 << ", " << position.z() << ") " << "(" << direction.x() << ", " << direction.y() << ", "
0478 << direction.z() << ") " << "(" << polarization.x() << ", " << polarization.y() << ", "
0479 << polarization.z() << ") " << "CreationProcessID=" << theCreationProcessid;
0480 if (emit_trackid)
0481 {
0482 const int64_t pidx = hit.index;
0483 while (g_cur + 1 < M_gs && pidx >= sev->gs[g_cur + 1].offset)
0484 ++g_cur;
0485 int trackID =
0486 pidx < sev->gs[g_cur].offset + sev->gs[g_cur].photons ? int(sev->genstep[g_cur].trackid()) : -1;
0487 outFile << " TrackID=" << trackID;
0488 }
0489 outFile << std::endl;
0490 }
0491 auto hit_loop_end = std::chrono::high_resolution_clock::now();
0492 std::chrono::duration<double> hit_loop_elapsed = hit_loop_end - hit_loop_start;
0493 std::cout << "Hit-write loop time: " << hit_loop_elapsed.count() << " seconds"
0494 << " (emit_trackid=" << (emit_trackid ? "1" : "0") << ", num_hits=" << num_hits << ")"
0495 << std::endl;
0496
0497 outFile.close();
0498 }
0499 }
0500 };
0501
0502 struct SteppingAction : G4UserSteppingAction
0503 {
0504 SEvt* sev;
0505
0506 SteppingAction(SEvt* sev) :
0507 sev(sev)
0508 {
0509 }
0510
0511 void UserSteppingAction(const G4Step* aStep)
0512 {
0513 G4Track* aTrack;
0514 G4int fNumPhotons = 0;
0515
0516 G4StepPoint* preStep = aStep->GetPostStepPoint();
0517 G4VPhysicalVolume* volume = preStep->GetPhysicalVolume();
0518
0519 if (aStep->GetTrack()->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition())
0520 {
0521
0522 if (aStep->GetTrack()->GetCurrentStepNumber() > 10000)
0523 {
0524 aStep->GetTrack()->SetTrackStatus(fStopAndKill);
0525 }
0526 }
0527
0528 if (volume && volume->GetName() == "MirrorPyramid")
0529 {
0530 aTrack = aStep->GetTrack();
0531 if (aTrack->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition())
0532 {
0533 aTrack->SetTrackStatus(fStopAndKill);
0534 }
0535 }
0536
0537 G4SteppingManager* fpSteppingManager =
0538 G4EventManager::GetEventManager()->GetTrackingManager()->GetSteppingManager();
0539 G4StepStatus stepStatus = fpSteppingManager->GetfStepStatus();
0540
0541 if (stepStatus != fAtRestDoItProc)
0542 {
0543 G4ProcessVector* procPost = fpSteppingManager->GetfPostStepDoItVector();
0544 size_t MAXofPostStepLoops = fpSteppingManager->GetMAXofPostStepLoops();
0545 for (size_t i3 = 0; i3 < MAXofPostStepLoops; i3++)
0546 {
0547 if ((*procPost)[i3]->GetProcessName() == "Cerenkov")
0548 {
0549 aTrack = aStep->GetTrack();
0550 const G4DynamicParticle* aParticle = aTrack->GetDynamicParticle();
0551 G4double charge = aParticle->GetDefinition()->GetPDGCharge();
0552 const G4Material* aMaterial = aTrack->GetMaterial();
0553 G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
0554
0555 G4MaterialPropertyVector* Rindex = MPT->GetProperty(kRINDEX);
0556 if (!Rindex || Rindex->GetVectorLength() == 0)
0557 {
0558 G4cout << "WARNING: Material has no valid RINDEX data. Skipping Cerenkov calculation."
0559 << G4endl;
0560 return;
0561 }
0562
0563 G4Cerenkov* proc = (G4Cerenkov*)(*procPost)[i3];
0564 fNumPhotons = proc->GetNumPhotons();
0565
0566 G4AutoLock lock(&genstep_mutex);
0567
0568 if (fNumPhotons > 0)
0569 {
0570 G4double Pmin = Rindex->Energy(0);
0571 G4double Pmax = Rindex->GetMaxEnergy();
0572 G4double nMax = Rindex->GetMaxValue();
0573 G4double beta1 = aStep->GetPreStepPoint()->GetBeta();
0574 G4double beta2 = aStep->GetPostStepPoint()->GetBeta();
0575 G4double beta = (beta1 + beta2) * 0.5;
0576 G4double BetaInverse = 1. / beta;
0577 G4double maxCos = BetaInverse / nMax;
0578 G4double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
0579 G4double MeanNumberOfPhotons1 =
0580 proc->GetAverageNumberOfPhotons(charge, beta1, aMaterial, Rindex);
0581 G4double MeanNumberOfPhotons2 =
0582 proc->GetAverageNumberOfPhotons(charge, beta2, aMaterial, Rindex);
0583
0584 U4::CollectGenstep_G4Cerenkov_modified(aTrack, aStep, fNumPhotons, BetaInverse, Pmin, Pmax,
0585 maxCos, maxSin2, MeanNumberOfPhotons1,
0586 MeanNumberOfPhotons2);
0587 }
0588 }
0589 if ((*procPost)[i3]->GetProcessName() == "Scintillation")
0590 {
0591 G4Scintillation* proc1 = (G4Scintillation*)(*procPost)[i3];
0592 fNumPhotons = proc1->GetNumPhotons();
0593 if (fNumPhotons > 0)
0594 {
0595 aTrack = aStep->GetTrack();
0596 const G4Material* aMaterial = aTrack->GetMaterial();
0597 G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
0598 if (!MPT || !MPT->ConstPropertyExists(kSCINTILLATIONTIMECONSTANT1))
0599 {
0600 G4cout << "WARNING: Material has no valid SCINTILLATIONTIMECONSTANT1 data. Skipping "
0601 "Scintillation calculation."
0602 << G4endl;
0603 return;
0604 }
0605 G4double SCINTILLATIONTIMECONSTANT1 = MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
0606
0607 U4::CollectGenstep_DsG4Scintillation_r4695(aTrack, aStep, fNumPhotons, 1,
0608 SCINTILLATIONTIMECONSTANT1);
0609 }
0610 }
0611 }
0612 }
0613 }
0614 };
0615
0616 struct TrackingAction : G4UserTrackingAction
0617 {
0618 const G4Track* transient_fSuspend_track = nullptr;
0619 SEvt* sev;
0620
0621 TrackingAction(SEvt* sev) :
0622 sev(sev)
0623 {
0624 }
0625
0626 void PreUserTrackingAction_Optical_FabricateLabel(const G4Track* track)
0627 {
0628 }
0629
0630 void PreUserTrackingAction(const G4Track* track) override
0631 {
0632 }
0633
0634 void PostUserTrackingAction(const G4Track* track) override
0635 {
0636 }
0637 };
0638
0639 struct G4App
0640 {
0641 G4App(std::filesystem::path gdml_file) :
0642 sev(SEvt::CreateOrReuse_EGPU()),
0643 det_cons_(new DetectorConstruction(gdml_file)),
0644 prim_gen_(new PrimaryGenerator(sev)),
0645 event_act_(new EventAction(sev)),
0646 run_act_(new RunAction(event_act_)),
0647 stepping_(new SteppingAction(sev)),
0648
0649 tracking_(new TrackingAction(sev))
0650 {
0651 }
0652
0653
0654
0655
0656 SEvt* sev;
0657
0658 G4VUserDetectorConstruction* det_cons_;
0659 G4VUserPrimaryGeneratorAction* prim_gen_;
0660 EventAction* event_act_;
0661 RunAction* run_act_;
0662 SteppingAction* stepping_;
0663 TrackingAction* tracking_;
0664 };