File indexing completed on 2025-08-05 08:17:53
0001 #include "PHG4ZDCSteppingAction.h"
0002
0003 #include "PHG4ZDCDetector.h"
0004
0005 #include <phparameter/PHParameters.h>
0006
0007 #include <g4main/PHG4Hit.h>
0008 #include <g4main/PHG4HitContainer.h>
0009 #include <g4main/PHG4Hitv1.h>
0010 #include <g4main/PHG4Shower.h>
0011 #include <g4main/PHG4SteppingAction.h> // for PHG4SteppingAction
0012 #include <g4main/PHG4TrackUserInfoV1.h>
0013
0014 #include <phool/PHRandomSeed.h>
0015 #include <phool/getClass.h>
0016
0017 #include <Geant4/G4DynamicParticle.hh> // for G4DynamicParticle
0018 #include <Geant4/G4IonisParamMat.hh> // for G4IonisParamMat
0019 #include <Geant4/G4Material.hh> // for G4Material
0020 #include <Geant4/G4MaterialCutsCouple.hh>
0021 #include <Geant4/G4ParticleDefinition.hh> // for G4ParticleDefinition
0022 #include <Geant4/G4ReferenceCountedHandle.hh> // for G4ReferenceCountedHandle
0023 #include <Geant4/G4Step.hh>
0024 #include <Geant4/G4StepPoint.hh> // for G4StepPoint
0025 #include <Geant4/G4StepStatus.hh> // for fGeomBoundary, fAtRest...
0026 #include <Geant4/G4String.hh> // for G4String
0027 #include <Geant4/G4SystemOfUnits.hh>
0028 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
0029 #include <Geant4/G4TouchableHandle.hh>
0030 #include <Geant4/G4Track.hh> // for G4Track
0031 #include <Geant4/G4TrackStatus.hh> // for fStopAndKill
0032 #include <Geant4/G4Types.hh> // for G4double
0033 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
0034 #include <Geant4/G4VTouchable.hh> // for G4VTouchable
0035 #include <Geant4/G4VUserTrackInformation.hh> // for G4VUserTrackInformation
0036
0037 #include <TSystem.h>
0038
0039 #include <gsl/gsl_randist.h>
0040 #include <gsl/gsl_rng.h>
0041
0042 #include <array>
0043 #include <cmath>
0044 #include <iostream>
0045 #include <string> // for basic_string, operator+
0046
0047 class PHCompositeNode;
0048
0049
0050 PHG4ZDCSteppingAction::PHG4ZDCSteppingAction(PHG4ZDCDetector* detector, const PHParameters* parameters)
0051 : PHG4SteppingAction(detector->GetName())
0052 , m_Detector(detector)
0053 , m_Params(parameters)
0054 , m_IsActiveFlag(m_Params->get_int_param("active"))
0055 , absorbertruth(m_Params->get_int_param("absorberactive"))
0056 , m_IsBlackHole(m_Params->get_int_param("blackhole"))
0057 {
0058 RandomGenerator = gsl_rng_alloc(gsl_rng_mt19937);
0059 unsigned int seed = PHRandomSeed();
0060 gsl_rng_set(RandomGenerator, seed);
0061 }
0062
0063 PHG4ZDCSteppingAction::~PHG4ZDCSteppingAction()
0064 {
0065
0066
0067
0068
0069 delete m_Hit;
0070 gsl_rng_free(RandomGenerator);
0071 }
0072
0073
0074 bool PHG4ZDCSteppingAction::UserSteppingAction(const G4Step* aStep, bool )
0075 {
0076 G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
0077 G4VPhysicalVolume* volume = touch->GetVolume();
0078
0079
0080
0081
0082
0083
0084
0085 int whichactive = m_Detector->IsInZDC(volume);
0086
0087 if (!whichactive)
0088 {
0089 return false;
0090 }
0091
0092 int layer_id = m_Detector->get_Layer();
0093 int idx_k = -1;
0094 int idx_j = -1;
0095
0096 if (whichactive > 0)
0097 {
0098
0099
0100 if (whichactive == 2)
0101 {
0102 FindIndexZDC(touch, idx_j, idx_k);
0103 }
0104 if (whichactive == 1)
0105 {
0106 FindIndexSMD(touch, idx_j, idx_k);
0107 }
0108 }
0109
0110 G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
0111 G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV;
0112 G4double light_yield = 0;
0113
0114
0115 const G4Track* aTrack = aStep->GetTrack();
0116
0117
0118 if (m_IsBlackHole)
0119 {
0120 edep = aTrack->GetKineticEnergy() / GeV;
0121 G4Track* killtrack = const_cast<G4Track*>(aTrack);
0122 killtrack->SetTrackStatus(fStopAndKill);
0123 }
0124
0125
0126 if (m_IsActiveFlag)
0127 {
0128
0129 bool geantino = false;
0130 if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
0131 aTrack->GetParticleDefinition()->GetParticleName().find("geantino") != std::string::npos)
0132 {
0133 geantino = true;
0134 }
0135
0136
0137 G4StepPoint* prePoint = aStep->GetPreStepPoint();
0138 G4StepPoint* postPoint = aStep->GetPostStepPoint();
0139
0140
0141 if (whichactive > 1)
0142 {
0143 double charge = aTrack->GetParticleDefinition()->GetPDGCharge();
0144
0145 if (charge != 0)
0146 {
0147
0148 G4VPhysicalVolume* postvolume = postPoint->GetTouchableHandle()->GetVolume();
0149 int postactive = m_Detector->IsInZDC(postvolume);
0150
0151 if (!postactive)
0152 {
0153
0154 int pid = aTrack->GetParticleDefinition()->GetPDGEncoding();
0155
0156 const G4DynamicParticle* dypar = aTrack->GetDynamicParticle();
0157 const G4ThreeVector& pdirect = dypar->GetMomentumDirection();
0158
0159
0160 double dy = sqrt(2) / 2.;
0161 double dz = sqrt(2) / 2.;
0162 if (idx_j == 1)
0163 {
0164 dz = -dz;
0165 }
0166 double CosTheta = pdirect.y() * dy + pdirect.z() * dz;
0167 double angle = acos(CosTheta) * 180.0 / M_PI;
0168 if (pid == 11 || pid == -11)
0169 {
0170
0171 G4double E = dypar->GetTotalEnergy();
0172
0173 double avg_ph = ZDCEResponse(E, angle);
0174 avg_ph *= 0.16848;
0175
0176 int n_ph = gsl_ran_poisson(RandomGenerator, avg_ph);
0177 light_yield += n_ph;
0178 }
0179 else
0180 {
0181 G4double E = dypar->GetTotalEnergy();
0182 G4double P = dypar->GetTotalMomentum();
0183 double beta = P / E;
0184 double avg_ph = ZDCResponse(beta, angle);
0185 avg_ph *= 0.16848;
0186 int n_ph = gsl_ran_poisson(RandomGenerator, avg_ph);
0187 light_yield += n_ph;
0188 }
0189 }
0190 }
0191 }
0192 switch (prePoint->GetStepStatus())
0193 {
0194 case fGeomBoundary:
0195 case fUndefined:
0196 if (!m_Hit)
0197 {
0198 m_Hit = new PHG4Hitv1();
0199 }
0200
0201
0202 m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
0203 m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
0204 m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
0205
0206
0207 m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
0208
0209
0210 m_Hit->set_trkid(aTrack->GetTrackID());
0211
0212 m_Hit->set_edep(0);
0213
0214
0215
0216 if (whichactive > 0)
0217 {
0218 m_CurrentHitContainer = m_HitContainer;
0219 m_Hit->set_eion(0);
0220 m_Hit->set_light_yield(0);
0221
0222 m_Hit->set_index_k(idx_k);
0223 m_Hit->set_index_j(idx_j);
0224 }
0225 else
0226 {
0227 if (whichactive == -1)
0228 {
0229 m_CurrentHitContainer = m_AbsorberHitContainer;
0230 }
0231 else
0232 {
0233 m_CurrentHitContainer = m_SupportHitContainer;
0234 }
0235 }
0236
0237 if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0238 {
0239 if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0240 {
0241 m_Hit->set_trkid(pp->GetUserTrackId());
0242 m_Hit->set_shower_id(pp->GetShower()->get_id());
0243 m_CurrentShower = pp->GetShower();
0244 }
0245 }
0246 break;
0247 default:
0248 break;
0249 }
0250
0251 if (whichactive == 1)
0252 {
0253
0254 light_yield = GetVisibleEnergyDeposition(aStep);
0255 static bool once = true;
0256
0257 if (once && edep > 0)
0258 {
0259 once = false;
0260
0261 if (Verbosity() > 0)
0262 {
0263 std::cout << "PHG4ZDCSteppingAction::UserSteppingAction::"
0264
0265 << m_Detector->GetName() << " - "
0266 << " use scintillating light model at each Geant4 steps. "
0267 << "First step: "
0268 << "Material = "
0269 << aTrack->GetMaterialCutsCouple()->GetMaterial()->GetName()
0270 << ", "
0271 << "Birk Constant = "
0272 << aTrack->GetMaterialCutsCouple()->GetMaterial()->GetIonisation()->GetBirksConstant()
0273 << ","
0274 << "edep = " << edep << ", "
0275 << "eion = " << eion
0276 << ", "
0277 << "light_yield = " << light_yield << std::endl;
0278 }
0279 }
0280 }
0281
0282
0283
0284 m_Hit->set_edep(m_Hit->get_edep() + edep);
0285 if (whichactive > 0)
0286 {
0287 m_Hit->set_eion(m_Hit->get_eion() + eion);
0288 m_Hit->set_light_yield(m_Hit->get_light_yield() + light_yield);
0289 }
0290
0291
0292
0293
0294
0295
0296
0297 if (postPoint->GetStepStatus() == fGeomBoundary ||
0298 postPoint->GetStepStatus() == fWorldBoundary ||
0299 postPoint->GetStepStatus() == fAtRestDoItProc ||
0300 aTrack->GetTrackStatus() == fStopAndKill)
0301 {
0302
0303 m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
0304 m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
0305 m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
0306
0307 m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
0308
0309
0310 if (geantino)
0311 {
0312 m_Hit->set_edep(-1);
0313 if (whichactive > 0)
0314 {
0315 m_Hit->set_eion(-1);
0316 m_Hit->set_light_yield(-1);
0317 }
0318 }
0319
0320 if (m_Hit->get_edep())
0321 {
0322 m_CurrentHitContainer->AddHit(layer_id, m_Hit);
0323 if (m_CurrentShower)
0324 {
0325 m_CurrentShower->add_g4hit_id(m_CurrentHitContainer->GetID(), m_Hit->get_hit_id());
0326 }
0327
0328 if (m_Hit->get_edep() > 0 && (whichactive > 0 || absorbertruth > 0))
0329 {
0330 if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0331 {
0332 if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0333 {
0334 pp->SetKeep(1);
0335 }
0336 }
0337 }
0338
0339 m_Hit = nullptr;
0340 }
0341 else
0342 {
0343
0344
0345
0346 m_Hit->Reset();
0347 }
0348 }
0349 return true;
0350 }
0351 else
0352 {
0353 return false;
0354 }
0355 }
0356
0357
0358 void PHG4ZDCSteppingAction::SetInterfacePointers(PHCompositeNode* topNode)
0359 {
0360
0361 m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
0362 m_AbsorberHitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_AbsorberNodeName);
0363 m_SupportHitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_SupportNodeName);
0364
0365 if (!m_HitContainer)
0366 {
0367 std::cout << "PHG4ZDCSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl;
0368 gSystem->Exit(1);
0369 }
0370
0371 if (!m_AbsorberHitContainer)
0372 {
0373 if (Verbosity() > 0)
0374 {
0375 std::cout << "PHG4ZDCSteppingAction::SetTopNode - unable to find " << m_AbsorberNodeName << std::endl;
0376 }
0377 }
0378 if (!m_SupportHitContainer)
0379 {
0380 if (Verbosity() > 0)
0381 {
0382 std::cout << "PHG4ZDCSteppingAction::SetTopNode - unable to find " << m_SupportNodeName << std::endl;
0383 }
0384 }
0385 }
0386
0387 void PHG4ZDCSteppingAction::SetHitNodeName(const std::string& type, const std::string& name)
0388 {
0389 if (type == "G4HIT")
0390 {
0391 m_HitNodeName = name;
0392 return;
0393 }
0394 else if (type == "G4HIT_ABSORBER")
0395 {
0396 m_AbsorberNodeName = name;
0397 return;
0398 }
0399 else if (type == "G4HIT_SUPPORT")
0400 {
0401 m_SupportNodeName = name;
0402 return;
0403 }
0404 std::cout << "Invalid output hit node type " << type << std::endl;
0405 gSystem->Exit(1);
0406 return;
0407 }
0408
0409
0410
0411 int PHG4ZDCSteppingAction::FindIndexZDC(G4TouchableHandle& touch, int& j, int& k)
0412 {
0413 G4VPhysicalVolume* envelope = touch->GetVolume(2);
0414 G4VPhysicalVolume* plate = touch->GetVolume(1);
0415
0416 j = envelope->GetCopyNo();
0417 k = (plate->GetCopyNo()) / 27;
0418
0419 return 0;
0420 }
0421
0422 int PHG4ZDCSteppingAction::FindIndexSMD(G4TouchableHandle& touch, int& j, int& k)
0423 {
0424 int jshift = 10;
0425 int kshift = 10;
0426 G4VPhysicalVolume* envelope = touch->GetVolume(2);
0427 G4VPhysicalVolume* scint = touch->GetVolume(0);
0428
0429 int whichzdc = envelope->GetCopyNo();
0430
0431 j = scint->GetCopyNo() % 7;
0432 k = scint->GetCopyNo() / 7;
0433
0434 if (whichzdc == 1)
0435 {
0436 j += 7;
0437 }
0438
0439 j += jshift;
0440 k += kshift;
0441
0442 return 0;
0443 }
0444
0445 double PHG4ZDCSteppingAction::ZDCResponse(double beta, double angle)
0446 {
0447 if (beta < m_BetaThersh)
0448 {
0449 return 0;
0450 }
0451 if (angle >= 90)
0452 {
0453 return 0;
0454 }
0455 for (int i = 1; i < 9; i++)
0456 {
0457 if (beta <= m_Beta[i])
0458 {
0459 std::array<double, 18> PMMAsub0 = m_PMMA05[i - 1];
0460 std::array<double, 18> PMMAsub1 = m_PMMA05[i];
0461
0462 int Abin = (int) angle / 5;
0463 if (Abin == 0)
0464 {
0465 Abin = 1;
0466 }
0467 double avg_ph0 = PMMAsub0[Abin - 1] + (PMMAsub0[Abin] - PMMAsub0[Abin - 1]) * (angle / 5 - Abin + 1);
0468 double avg_ph1 = PMMAsub1[Abin - 1] + (PMMAsub1[Abin] - PMMAsub1[Abin - 1]) * (angle / 5 - Abin + 1);
0469 if (avg_ph0 < 0)
0470 {
0471 avg_ph0 = 0;
0472 }
0473 if (avg_ph1 < 0)
0474 {
0475 avg_ph1 = 0;
0476 }
0477
0478 double avg_ph = avg_ph0 + (avg_ph1 - avg_ph0) * (beta - m_Beta[i - 1]) / (m_Beta[i] - m_Beta[i - 1]);
0479 if (avg_ph < 0)
0480 {
0481 avg_ph = 0;
0482 }
0483
0484 return avg_ph;
0485 }
0486 }
0487
0488 return 0;
0489 }
0490
0491 double PHG4ZDCSteppingAction::ZDCEResponse(double E, double angle)
0492 {
0493 if (E < m_E[0])
0494 {
0495 return 0;
0496 }
0497
0498 if (E >= 0.05)
0499 {
0500 std::array<double, 36> PMMAsub0 = m_PMMA05E[10];
0501 int Abin = (int) angle / 5;
0502 if (Abin == 0)
0503 {
0504 Abin = 1;
0505 }
0506 double avg_ph = PMMAsub0[Abin - 1] + (PMMAsub0[Abin] - PMMAsub0[Abin - 1]) * (angle / 5 - Abin + 1);
0507 return avg_ph;
0508 }
0509 else
0510 {
0511 for (int i = 1; i < 11; i++)
0512 {
0513 if (E <= m_E[i])
0514 {
0515 std::array<double, 36> PMMAsub0 = m_PMMA05E[i - 1];
0516 std::array<double, 36> PMMAsub1 = m_PMMA05E[i];
0517
0518 int Abin = (int) angle / 5;
0519 if (Abin == 0)
0520 {
0521 Abin = 1;
0522 }
0523 double avg_ph0 = PMMAsub0[Abin - 1] + (PMMAsub0[Abin] - PMMAsub0[Abin - 1]) * (angle / 5 - Abin + 1);
0524 double avg_ph1 = PMMAsub1[Abin - 1] + (PMMAsub1[Abin] - PMMAsub1[Abin - 1]) * (angle / 5 - Abin + 1);
0525 if (avg_ph0 < 0)
0526 {
0527 avg_ph0 = 0;
0528 }
0529 if (avg_ph1 < 0)
0530 {
0531 avg_ph1 = 0;
0532 }
0533
0534 double avg_ph = avg_ph0 + (avg_ph1 - avg_ph0) * (E - m_E[i - 1]) / (m_E[i] - m_E[i - 1]);
0535 if (avg_ph < 0)
0536 {
0537 avg_ph = 0;
0538 }
0539
0540 return avg_ph;
0541 }
0542 }
0543 }
0544 std::cout << "out of range" << std::endl;
0545 return 0;
0546 }