23 #include "Geant4/G4Alpha.hh" 24 #include "Geant4/G4DynamicParticle.hh" 25 #include "Geant4/G4Electron.hh" 26 #include "Geant4/G4ExceptionSeverity.hh" 27 #include "Geant4/G4Gamma.hh" 28 #include "Geant4/G4KaonMinus.hh" 29 #include "Geant4/G4KaonPlus.hh" 30 #include "Geant4/G4Material.hh" 31 #include "Geant4/G4MaterialPropertiesTable.hh" 32 #include "Geant4/G4MaterialPropertyVector.hh" 33 #include "Geant4/G4MaterialTable.hh" 34 #include "Geant4/G4MuonMinus.hh" 35 #include "Geant4/G4MuonPlus.hh" 36 #include "Geant4/G4ParticleChange.hh" 37 #include "Geant4/G4PhysicsVector.hh" 38 #include "Geant4/G4PionMinus.hh" 39 #include "Geant4/G4PionPlus.hh" 40 #include "Geant4/G4Poisson.hh" 41 #include "Geant4/G4Proton.hh" 42 #include "Geant4/G4Step.hh" 43 #include "Geant4/G4StepPoint.hh" 44 #include "Geant4/G4Track.hh" 45 #include "Geant4/G4VPhysicalVolume.hh" 46 #include "Geant4/G4ios.hh" 47 #include "Geant4/Randomize.hh" 48 #include "Geant4/globals.hh" 67 #include "cetlib_except/exception.h" 70 #include "TGeoSphere.h" 74 #include "range/v3/view/enumerate.hpp" 80 #include "boost/math/special_functions/ellint_1.hpp" 81 #include "boost/math/special_functions/ellint_3.hpp" 84 typedef boost::math::policies::policy<boost::math::policies::promote_double<false>>
89 double finter_d(
double*
x,
double* par)
91 double y1 = par[2] * TMath::Landau(x[0], par[0], par[1]);
92 double y2 = TMath::Exp(par[3] + x[0] * par[4]);
93 return TMath::Abs(y1 - y2);
96 double model_close(
double* x,
double* par)
105 double y1 = par[3] * TMath::Landau(x[0], par[1], par[2]);
106 double y2 = TMath::Exp(par[4] + x[0] * par[5]);
107 if (x[0] <= par[6] || x[0] > par[0]) y1 = 0.;
108 if (x[0] < par[0]) y2 = 0.;
112 double model_far(
double* x,
double* par)
118 double y = par[3] * TMath::Landau(x[0], par[1], par[2]);
119 if (x[0] <= par[0]) y = 0.;
125 double negate = double(x < 0);
127 x -= double(x > 1.0) * (x - 1.0);
128 double ret = -0.0187293;
130 ret = ret + 0.0742610;
132 ret = ret - 0.2121144;
134 ret = ret + 1.5707288;
135 ret = ret * std::sqrt(1.0 - x);
136 ret = ret - 2. * negate * ret;
137 return negate * 3.14159265358979 + ret;
144 : G4VRestDiscreteProcess(processName, type)
152 SetProcessSubType(25);
162 if (verboseLevel > 0) { G4cout << GetProcessName() <<
" is created " << G4endl; }
175 <<
"OpFastScintillation: active volume boundaries from " <<
fActiveVolumes.size()
178 log <<
"\n - C:" << iCryo <<
": " << box.Min() <<
" -- " << box.Max() <<
" cm";
180 log <<
"\n (scintillation photons are propagated " 187 << std::string(80,
'=') <<
"\nA detector with " << geom.
Ncryostats()
188 <<
" cryostats is configured" 189 <<
" , and semi-analytic model is requested for scintillation photon propagation." 190 <<
" THIS CONFIGURATION IS NOT SUPPORTED and it is open to bugs" 191 <<
" (e.g. scintillation may be detected only in cryostat #0)." 192 <<
"\nThis would be normally a fatal error, but it has been forcibly overridden." 194 << std::string(80,
'=');
198 <<
"Photon propagation via semi-analytic model is not supported yet" 199 <<
" on detectors with more than one cryostat.";
206 mf::LogTrace(
"OpFastScintillation") <<
"Cathode_centre: " << Cathode_centre <<
" cm";
212 if (dynamic_cast<TGeoSphere const*>(opDet.
Shape()) !=
nullptr) {
217 else if (opDet.
isBar()) {
230 std::cout <<
"Using parameterisation of timings." << std::endl;
245 const size_t num_params =
270 <<
"OpFastScintillation: using semi-analytic model for number of hits";
273 std::map<double, double> abs_length_spectrum =
274 lar::providerFrom<detinfo::LArPropertiesService>()->AbsLengthSpectrum();
275 std::vector<double> x_v, y_v;
276 for (
auto elem : abs_length_spectrum) {
277 x_v.push_back(elem.first);
278 y_v.push_back(elem.second);
284 std::cout <<
"Loading the GH corrections" << std::endl;
289 <<
"Both isFlatPDCorr and isDomePDCorr parameters are false, at least one type of " 290 "parameterisation is required for the semi-analytic light simulation." 308 std::cout <<
"Loading visible light corrections" << std::endl;
330 tpbemission = lar::providerFrom<detinfo::LArPropertiesService>()->TpbEm();
331 std::vector<double> parent;
334 parent.push_back(iter->second);
336 fTPBEm = std::make_unique<CLHEP::RandGeneral>(parent.data(), parent.size());
364 aParticleChange.Initialize(aTrack);
366 const G4Material* aMaterial = aTrack.GetMaterial();
367 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
368 if (!aMaterialPropertiesTable)
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
370 G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
371 G4ThreeVector x0 = pPreStepPoint->GetPosition();
372 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
375 aParticleChange.SetNumberOfSecondaries(0);
396 double MeanNumberOfPhotons =
400 if (verboseLevel > 0) {
401 G4cout <<
"\n Exiting from OpFastScintillation::DoIt -- NumberOfSecondaries = " 402 << aParticleChange.GetNumberOfSecondaries() << G4endl;
404 return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
409 if (step.GetTotalEnergyDeposit() <= 0)
return;
415 (
double)(step.GetTotalEnergyDeposit() / CLHEP::MeV),
416 (
float)(step.GetPreStepPoint()->GetPosition().x() / CLHEP::cm),
417 (
float)(step.GetPreStepPoint()->GetPosition().y() / CLHEP::cm),
418 (
float)(step.GetPreStepPoint()->GetPosition().z() / CLHEP::cm),
419 (
float)(step.GetPostStepPoint()->GetPosition().x() / CLHEP::cm),
420 (
float)(step.GetPostStepPoint()->GetPosition().y() / CLHEP::cm),
421 (
float)(step.GetPostStepPoint()->GetPosition().z() / CLHEP::cm),
422 (
double)(step.GetPreStepPoint()->GetGlobalTime()),
423 (
double)(step.GetPostStepPoint()->GetGlobalTime()),
425 step.GetTrack()->GetParticleDefinition()->GetPDGEncoding(),
427 step.GetPreStepPoint()->GetPhysicalVolume()->GetName());
439 const G4Track* aTrack = aStep.GetTrack();
441 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
443 const G4DynamicParticle* aParticle = aTrack->GetDynamicParticle();
444 const G4Material* aMaterial = aTrack->GetMaterial();
446 G4int materialIndex = aMaterial->GetIndex();
447 G4int tracknumber = aStep.GetTrack()->GetTrackID();
449 G4ThreeVector x0 = pPreStepPoint->GetPosition();
450 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
451 G4double
t0 = pPreStepPoint->GetGlobalTime();
453 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
455 G4MaterialPropertyVector* Fast_Intensity =
456 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
457 G4MaterialPropertyVector* Slow_Intensity =
458 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
460 if (!Fast_Intensity && !Slow_Intensity)
return 1;
468 if (Fast_Intensity && Slow_Intensity) nscnt = 2;
471 double YieldRatio = 0;
478 G4ParticleDefinition* pDef = aParticle->GetDefinition();
484 if (pDef == G4Proton::ProtonDefinition()) {
485 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PROTONYIELDRATIO");
488 else if (pDef == G4MuonPlus::MuonPlusDefinition() ||
489 pDef == G4MuonMinus::MuonMinusDefinition()) {
490 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"MUONYIELDRATIO");
493 else if (pDef == G4PionPlus::PionPlusDefinition() ||
494 pDef == G4PionMinus::PionMinusDefinition()) {
495 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PIONYIELDRATIO");
498 else if (pDef == G4KaonPlus::KaonPlusDefinition() ||
499 pDef == G4KaonMinus::KaonMinusDefinition()) {
500 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"KAONYIELDRATIO");
503 else if (pDef == G4Alpha::AlphaDefinition()) {
504 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ALPHAYIELDRATIO");
508 else if (pDef == G4Electron::ElectronDefinition() || pDef == G4Gamma::GammaDefinition()) {
509 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
513 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
517 if (YieldRatio == 0) {
518 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
522 geo::Point_t const ScintPoint = {x0[0] / CLHEP::cm, x0[1] / CLHEP::cm, x0[2] / CLHEP::cm};
535 for (G4int scnt = 1; scnt <= nscnt; scnt++) {
536 G4double ScintillationTime = 0. * CLHEP::ns;
537 G4double ScintillationRiseTime = 0. * CLHEP::ns;
538 G4PhysicsOrderedFreeVector* ScintillationIntegral = NULL;
541 if (Fast_Intensity) {
542 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
544 ScintillationRiseTime =
545 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
547 ScintillationIntegral =
550 if (Slow_Intensity) {
551 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
553 ScintillationRiseTime =
554 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
556 ScintillationIntegral =
562 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"YIELDRATIO");
564 if (
ExcitationRatio == 1.0) { Num = std::min(YieldRatio, 1.0) * MeanNumberOfPhotons; }
568 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
570 ScintillationRiseTime =
571 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
573 ScintillationIntegral =
579 Num = MeanNumberOfPhotons - Num;
580 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
582 ScintillationRiseTime =
583 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
585 ScintillationIntegral =
589 if (!ScintillationIntegral)
continue;
594 std::map<size_t, int> DetectedNum;
598 int const DetThis = std::round(G4Poisson(Visibilities[OpDet] * Num));
599 if (DetThis > 0) DetectedNum[OpDet] = DetThis;
607 std::map<size_t, int> ReflDetectedNum;
612 int const ReflDetThis = std::round(G4Poisson(ReflVisibilities[OpDet] * Num));
613 if (ReflDetThis > 0) ReflDetectedNum[OpDet] = ReflDetThis;
621 std::vector<double> arrival_time_dist;
623 for (
size_t Reflected = 0; Reflected <= 1; ++Reflected) {
630 itstart = ReflDetectedNum.begin();
631 itend = ReflDetectedNum.end();
634 itstart = DetectedNum.begin();
635 itend = DetectedNum.end();
637 for (
auto itdetphot = itstart; itdetphot != itend; ++itdetphot) {
638 const size_t OpChannel = itdetphot->first;
639 const int NPhotons = itdetphot->second;
646 double Edeposited = 0;
650 Edeposited = aStep.GetTotalEnergyDeposit();
660 Edeposited = aStep.GetTotalEnergyDeposit();
664 arrival_time_dist.resize(NPhotons);
669 Edeposited = Edeposited / double(NPhotons);
672 for (G4int i = 0; i < NPhotons; ++i) {
673 G4double Time = t0 +
scint_time(aStep, ScintillationTime, ScintillationRiseTime) +
674 arrival_time_dist[i] * CLHEP::ns;
681 fst->
AddLitePhoton(OpChannel, static_cast<int>(Time), 1, Reflected);
685 TVector3 PhotonPosition(x0[0], x0[1], x0[2]);
687 float PhotonEnergy = 0;
691 PhotonEnergy = 9.7 * CLHEP::eV;
696 PhotToAdd.
Energy = PhotonEnergy;
697 PhotToAdd.
Time = Time;
701 fst->
AddPhoton(OpChannel, std::move(PhotToAdd), Reflected);
718 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
719 G4int numOfMaterials = G4Material::GetNumberOfMaterials();
728 for (G4int i = 0; i < numOfMaterials; i++) {
729 G4PhysicsOrderedFreeVector* aPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
730 G4PhysicsOrderedFreeVector* bPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
734 G4Material* aMaterial = (*theMaterialTable)[i];
736 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
738 if (aMaterialPropertiesTable) {
740 G4MaterialPropertyVector* theFastLightVector =
741 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
743 if (theFastLightVector) {
746 G4double currentIN = (*theFastLightVector)[0];
747 if (currentIN >= 0.0) {
749 G4double currentPM = theFastLightVector->Energy(0);
750 G4double currentCII = 0.0;
752 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
755 G4double prevPM = currentPM;
756 G4double prevCII = currentCII;
757 G4double prevIN = currentIN;
760 for (
size_t i = 1; i < theFastLightVector->GetVectorLength(); i++) {
761 currentPM = theFastLightVector->Energy(i);
762 currentIN = (*theFastLightVector)[i];
764 currentCII = 0.5 * (prevIN + currentIN);
766 currentCII = prevCII + (currentPM - prevPM) * currentCII;
768 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
771 prevCII = currentCII;
777 G4MaterialPropertyVector* theSlowLightVector =
778 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
779 if (theSlowLightVector) {
782 G4double currentIN = (*theSlowLightVector)[0];
783 if (currentIN >= 0.0) {
785 G4double currentPM = theSlowLightVector->Energy(0);
786 G4double currentCII = 0.0;
788 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
791 G4double prevPM = currentPM;
792 G4double prevCII = currentCII;
793 G4double prevIN = currentIN;
796 for (
size_t i = 1; i < theSlowLightVector->GetVectorLength(); i++) {
797 currentPM = theSlowLightVector->Energy(i);
798 currentIN = (*theSlowLightVector)[i];
800 currentCII = 0.5 * (prevIN + currentIN);
802 currentCII = prevCII + (currentPM - prevPM) * currentCII;
804 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
807 prevCII = currentCII;
825 G4Exception(
"OpFastScintillation::SetScintillationByParticleType",
828 "Redefinition: Birks Saturation is replaced by ScintillationByParticleType!");
836 G4ForceCondition* condition)
838 *condition = StronglyForced;
849 G4double ScintillationTime,
850 G4double ScintillationRiseTime)
const 852 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
853 G4StepPoint
const* pPostStepPoint = aStep.GetPostStepPoint();
854 G4double avgVelocity = (pPreStepPoint->GetVelocity() + pPostStepPoint->GetVelocity()) / 2.;
855 G4double deltaTime = aStep.GetStepLength() / avgVelocity;
856 if (ScintillationRiseTime == 0.0) {
857 deltaTime = deltaTime - ScintillationTime * std::log(G4UniformRand());
860 deltaTime = deltaTime +
sample_time(ScintillationRiseTime, ScintillationTime);
867 const size_t OpChannel,
873 <<
"Cannot have both propagation time models simultaneously.";
879 G4cout <<
"WARNING: Requested parameterized timing, but no function found. Not applying " 886 <<
"No parameterized propagation time for reflected light";
887 for (
size_t i = 0; i < arrival_time_dist.size(); ++i) {
895 const G4ThreeVector OpDetPoint(
896 opDetCenter.X() * CLHEP::cm, opDetCenter.Y() * CLHEP::cm, opDetCenter.Z() * CLHEP::cm);
897 double distance_in_cm = (x0 - OpDetPoint).
mag() / CLHEP::cm;
898 double cosine =
std::abs(x0[0] * CLHEP::cm - OpDetPoint[0] * CLHEP::cm) / distance_in_cm;
901 getVUVTimes(arrival_time_dist, distance_in_cm, angle_bin);
904 TVector3
const ScintPoint(x0[0] / CLHEP::cm, x0[1] / CLHEP::cm, x0[2] / CLHEP::cm);
915 G4double ran1 = G4UniformRand();
916 G4double ran2 = G4UniformRand();
920 G4double
d = (tau1 + tau2) / tau2;
922 G4double t = -1.0 * tau2 * std::log(1 - ran1);
924 if (ran2 <=
bi_exp(t, tau1, tau2) / g)
return t;
937 CLHEP::Hep3Vector prePoint = (aStep.GetPreStepPoint())->GetPosition();
938 CLHEP::Hep3Vector postPoint = (aStep.GetPostStepPoint())->GetPosition();
939 xyzPos[0] = (((prePoint.getX() + postPoint.getX()) / 2.0) / CLHEP::cm);
940 xyzPos[1] = (((prePoint.getY() + postPoint.getY()) / 2.0) / CLHEP::cm);
941 xyzPos[2] = (((prePoint.getZ() + postPoint.getZ()) / 2.0) / CLHEP::cm);
951 const double signal_t_range = 5000.;
962 std::array<double, 3> pars_landau;
973 double pars_far[4] = {t_direct_min, pars_landau[0], pars_landau[1], pars_landau[2]};
975 fVUVTiming = TF1(
"fVUVTiming", model_far, 0, signal_t_range, 4);
976 fVUVTiming.SetParameters(pars_far);
980 fVUVTiming = TF1(
"fVUVTiming", model_close, 0, signal_t_range, 7);
988 pars_expo[0] *= pars_landau[2];
989 pars_expo[0] = std::log(pars_expo[0]);
991 TF1 fint = TF1(
"fint", finter_d, pars_landau[0], 4 * t_direct_mean, 5);
992 double parsInt[5] = {
993 pars_landau[0], pars_landau[1], pars_landau[2], pars_expo[0], pars_expo[1]};
994 fint.SetParameters(parsInt);
995 double t_int = fint.GetMinimumX();
996 double minVal = fint.Eval(t_int);
998 if (minVal > 0.015) {
999 std::cout <<
"WARNING: Parametrization of VUV light discontinuous for distance = " 1000 << distance_in_cm << std::endl;
1001 std::cout <<
"WARNING: This shouldn't be happening " << std::endl;
1003 double parsfinal[7] = {t_int,
1010 fVUVTiming.SetParameters(parsfinal);
1016 if (distance_in_cm < 50) { fsampling = 10000; }
1017 else if (distance_in_cm < 100) {
1023 fVUVTiming.SetNpx(fsampling);
1026 const size_t nq_max = 1;
1027 double xq_max[nq_max];
1028 double yq_max[nq_max];
1030 fVUVTiming.GetQuantiles(nq_max, yq_max, xq_max);
1031 double max = yq_max[0];
1033 double min = t_direct_min;
1040 VUV_max[angle_bin][index] = max;
1041 VUV_min[angle_bin][index] = min;
1046 const double distance,
1047 const size_t angle_bin)
1052 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1053 arrivalTimes[i] = t_prop_correction;
1062 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1063 arrivalTimes[i] =
VUV_timing[angle_bin][index].GetRandom(
VUV_min[angle_bin][index],
1071 const TVector3& ScintPoint,
1072 const TVector3& OpDetPoint)
1080 if (ScintPoint[0] < 0) { plane_depth = -
fplane_depth; }
1086 TVector3 bounce_point(plane_depth, ScintPoint[1], ScintPoint[2]);
1089 double VUVdist = (bounce_point - ScintPoint).Mag();
1090 double Visdist = (OpDetPoint - bounce_point).Mag();
1093 int angle_bin_vuv = 0;
1094 getVUVTimes(arrivalTimes, VUVdist, angle_bin_vuv);
1097 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1114 vuv_time =
VUV_min[angle_bin_vuv][index];
1117 double fastest_time = vis_time + vuv_time;
1120 double cosine_theta =
std::abs(OpDetPoint[0] - bounce_point[0]) / Visdist;
1127 double distance_cathode_plane =
std::abs(plane_depth - ScintPoint[0]);
1138 for (
size_t i = 0; i <
fcut_off_pars[theta_bin].size(); i++) {
1147 std::vector<double> interp_vals_tau(
ftau_pars[theta_bin].
size(), 0.0);
1148 for (
size_t i = 0; i <
ftau_pars[theta_bin].size(); i++) {
1149 interp_vals_tau[i] =
1155 if (tau < 0) { tau = 0; }
1158 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1159 double arrival_time_smeared;
1161 if (arrivalTimes[i] >= cutoff) {
continue; }
1169 if (counter >= 10) {
1170 arrival_time_smeared = arrivalTimes[i];
1175 double x = gRandom->Uniform(0.5, 1.0);
1177 arrival_time_smeared =
1178 arrivalTimes[i] + (arrivalTimes[i] - fastest_time) * (std::pow(x, -tau) - 1);
1181 }
while (arrival_time_smeared > cutoff);
1183 arrivalTimes[i] = arrival_time_smeared;
1206 const int DetThis =
VUVHits(Num, ScintPoint, op);
1207 if (DetThis > 0) { DetectedNum[OpDet] = DetThis; }
1220 if (ScintPoint.X() < 0.) { plane_depth = -
fplane_depth; }
1226 std::array<double, 3> ScintPoint_relative = {
std::abs(ScintPoint.X() - plane_depth),
1235 double distance_cathode =
std::abs(plane_depth - ScintPoint.X());
1237 double cathode_hits_geo = std::exp(-1. * distance_cathode /
fL_abs_vuv) *
1238 (solid_angle_cathode / (4. *
CLHEP::pi)) * Num;
1242 double pars_ini[4] = {0, 0, 0, 0};
1257 <<
"Error: flat optical detector VUV correction required for reflected semi-analytic hits." 1261 pars_ini[0] = pars_ini[0] + s1 *
r;
1262 pars_ini[1] = pars_ini[1] + s2 *
r;
1263 pars_ini[2] = pars_ini[2] + s3 *
r;
1264 pars_ini[3] = pars_ini[3];
1267 double GH_correction =
Gaisser_Hillas(distance_cathode, pars_ini);
1268 const double cathode_hits_rec = GH_correction * cathode_hits_geo;
1271 const std::array<double, 3> hotspot = {plane_depth, ScintPoint.Y(), ScintPoint.Z()};
1281 int const ReflDetThis =
VISHits(ScintPoint, op, cathode_hits_rec, hotspot);
1282 if (ReflDetThis > 0) { ReflDetectedNum[OpDet] = ReflDetThis; }
1292 std::array<double, 3U> ScintPoint;
1293 std::array<double, 3U> OpDetPoint;
1298 double distance =
dist(&ScintPoint[0], &OpDetPoint[0], 3);
1299 double cosine =
std::abs(ScintPoint[0] - OpDetPoint[0]) / distance;
1304 double solid_angle = 0;
1306 if (opDet.
type == 0) {
1308 std::array<double, 3> ScintPoint_rel = {
std::abs(ScintPoint[0] - OpDetPoint[0]),
1309 std::abs(ScintPoint[1] - OpDetPoint[1]),
1310 std::abs(ScintPoint[2] - OpDetPoint[2])};
1315 else if (opDet.
type == 1) {
1319 else if (opDet.
type == 2) {
1321 double d =
dist(&ScintPoint[1], &OpDetPoint[1], 2);
1323 double h =
std::abs(ScintPoint[0] - OpDetPoint[0]);
1328 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" 1335 std::exp(-1. * distance /
fL_abs_vuv) * (solid_angle / (4 *
CLHEP::pi)) * Nphotons_created;
1346 double pars_ini[4] = {0, 0, 0, 0};
1371 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or " 1372 "corrections for chosen optical detector type missing." 1376 pars_ini[0] = pars_ini[0] + s1 *
r;
1377 pars_ini[1] = pars_ini[1] + s2 *
r;
1378 pars_ini[2] = pars_ini[2] + s3 *
r;
1379 pars_ini[3] = pars_ini[3];
1385 double hits_rec = GH_correction * hits_geo / cosine;
1386 int hits_vuv = std::round(G4Poisson(hits_rec));
1394 const double cathode_hits_rec,
1395 const std::array<double, 3> hotspot)
const 1403 if (ScintPoint_v.X() < 0.) { plane_depth = -
fplane_depth; }
1412 std::array<double, 3U> ScintPoint;
1413 std::array<double, 3U> OpDetPoint;
1419 double distance_vis =
dist(&hotspot[0], &OpDetPoint[0], 3);
1421 double cosine_vis =
std::abs(hotspot[0] - OpDetPoint[0]) / distance_vis;
1425 double solid_angle_detector = 0;
1427 if (opDet.
type == 0) {
1429 std::array<double, 3> emission_relative = {
std::abs(hotspot[0] - OpDetPoint[0]),
1430 std::abs(hotspot[1] - OpDetPoint[1]),
1431 std::abs(hotspot[2] - OpDetPoint[2])};
1436 else if (opDet.
type == 1) {
1440 else if (opDet.
type == 2) {
1442 double d =
dist(&hotspot[1], &OpDetPoint[1], 2);
1444 double h =
std::abs(hotspot[0] - OpDetPoint[0]);
1449 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" 1454 double hits_geo = (solid_angle_detector / (2. *
CLHEP::pi)) *
1462 double d_c =
std::abs(ScintPoint[0] - plane_depth);
1463 double border_correction = 0;
1468 std::vector<double> interp_vals(nbins_r, 0.0);
1478 for (
size_t i = 0; i < nbins_r; ++i) {
1489 std::vector<double> interp_vals(nbins_r, 0.0);
1499 for (
size_t i = 0; i < nbins_r; ++i) {
1507 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or " 1508 "corrections for chosen optical detector type missing." 1513 double hits_rec = border_correction * hits_geo / cosine_vis;
1514 double hits_vis = std::round(G4Poisson(hits_rec));
1526 if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
1541 return std::exp(-1.0 * t / tau2) / tau2;
1545 const G4double tau1,
1546 const G4double tau2)
const 1548 return std::exp(-1.0 * t / tau2) * (1 - std::exp(-1.0 * t / tau1)) / tau2 / tau2 *
1554 double X_mu_0 = par[3];
1555 double Normalization = par[0];
1556 double Diff = par[1] - X_mu_0;
1557 double Term = std::pow((x - X_mu_0) / Diff, Diff / par[2]);
1558 double Exponential = std::exp((par[1] - x) / par[2]);
1559 return (Normalization * Term * Exponential);
1566 const std::vector<double>& yData,
1572 size_t size = xData.size();
1573 if (x >= xData[size - 2]) {
1577 while (x > xData[i + 1])
1581 double xL = xData[i];
1582 double xR = xData[i + 1];
1583 double yL = yData[i];
1584 double yR = yData[i + 1];
1586 if (x < xL)
return yL;
1587 if (x > xR)
return yL;
1589 const double dydx = (yR - yL) / (xR - xL);
1590 return yL + dydx * (x - xL);
1594 const std::vector<double>& xData,
1595 const std::vector<double>& yData1,
1596 const std::vector<double>& yData2,
1597 const std::vector<double>& yData3,
1599 bool extrapolate)
const 1601 size_t size = xData.size();
1603 if (x >= xData[size - 2]) {
1607 while (x > xData[i + 1])
1610 double xL = xData[i];
1611 double xR = xData[i + 1];
1612 double yL1 = yData1[i];
1613 double yR1 = yData1[i + 1];
1614 double yL2 = yData2[i];
1615 double yR2 = yData2[i + 1];
1616 double yL3 = yData3[i];
1617 double yR3 = yData3[i + 1];
1633 const double m = (x - xL) / (xR - xL);
1634 inter[0] = m * (yR1 - yL1) + yL1;
1635 inter[1] = m * (yR2 - yL2) + yL2;
1636 inter[2] = m * (yR3 - yL3) + yL3;
1645 if (b <= 0. || d < 0. || h <= 0.)
return 0.;
1646 const double leg2 = (b +
d) * (b + d);
1647 const double aa = std::sqrt(h * h / (h * h + leg2));
1649 double bb = 2. * std::sqrt(b * d / (h * h + leg2));
1650 double cc = 4. * b * d / leg2;
1658 catch (std::domain_error&
e) {
1661 <<
"Elliptic Integral in Disk_SolidAngle() given parameters outside domain." 1662 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
1663 <<
"\nRelax condition and carry on.";
1668 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters outside domain.\n" 1669 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
1681 catch (std::domain_error&
e) {
1684 <<
"Elliptic Integral in Disk_SolidAngle() given parameters outside domain." 1685 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
1686 <<
"\nRelax condition and carry on.";
1691 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters outside domain.\n" 1692 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
1706 const double d)
const 1708 double aa = a / (2. *
d);
1709 double bb = b / (2. *
d);
1710 double aux = (1. + aa * aa + bb * bb) / ((1. + aa * aa) * (1. + bb * bb));
1716 const std::array<double, 3> v)
const 1726 double A = v[1] - o.
h * .5;
1727 double B = v[2] - o.
w * .5;
1735 if ((v[1] <= o.
h * .5) && (v[2] <= o.
w * .5)) {
1736 double A = -v[1] + o.
h * .5;
1737 double B = -v[2] + o.
w * .5;
1746 double A = v[1] - o.
h * .5;
1747 double B = -v[2] + o.
w * .5;
1756 double A = -v[1] + o.
h * .5;
1757 double B = v[2] - o.
w * .5;
1779 double par0[9] = {0., 0., 0., 0., 0., 0.597542, 1.00872, 1.46993, 2.04221};
1780 double par1[9] = {0, 0, 0.19569, 0.300449, 0.555598, 0.854939, 1.39166, 2.19141, 2.57732};
1781 const double delta_theta = 10.;
1782 int j = int(theta / delta_theta);
1786 const double d_break = 5 * b;
1788 if (distance >= d_break) {
1789 double R_apparent_far = b - par1[j];
1790 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - std::pow(R_apparent_far / distance, 2))));
1793 double R_apparent_close = b - par0[j];
1794 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - std::pow(R_apparent_close / distance, 2))));
1802 std::vector<geo::BoxBoundedGeo> activeVolumes;
1813 activeVolumes.push_back(std::move(box));
1817 return activeVolumes;
code to link reconstructed objects back to the MC truth information
void LoadTimingsForVISPar(std::vector< double > &distances, std::vector< double > &radial_distances, std::vector< std::vector< std::vector< double >>> &cut_off, std::vector< std::vector< std::vector< double >>> &tau, double &vis_vmean, double &angle_bin_timing_vis) const
Store parameters for running LArG4.
bool IncludePropTime() const
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
Point_t GetCathodeCenter() const
Returns the expected drift direction based on geometry.
std::vector< std::vector< std::vector< double > > > fvispars_dome
Specializations of geo_vectors_utils.h for ROOT old vector types.
G4bool scintillationByParticleType
void detectedDirectHits(std::map< size_t, int > &DetectedNum, const double Num, geo::Point_t const &ScintPoint) const
void detectedReflecHits(std::map< size_t, int > &ReflDetectedNum, const double Num, geo::Point_t const &ScintPoint) const
void average_position(G4Step const &aStep, double *xzyPos) const
Utilities related to art service access.
bool isScintInActiveVolume(geo::Point_t const &ScintPoint)
std::vector< geo::Point_t > fOpDetCenter
static int GetCurrentOrigTrackID()
G4double bi_exp(const G4double t, const G4double tau1, const G4double tau2) const
double VisibleEnergyDeposit() const
double finflexion_point_distance
Float_t y1[n_points_granero]
void LoadTimingsForVUVPar(std::vector< std::vector< double >>(&v)[7], double &step_size, double &max_d, double &min_d, double &vuv_vgroup_mean, double &vuv_vgroup_max, double &inflexion_point_distance, double &angle_bin_timing_vuv) const
G4double Gaisser_Hillas(const double x, const double *par) const
std::vector< double > fOpDetHeight
static std::vector< geo::BoxBoundedGeo > extractActiveVolumes(geo::GeometryCore const &geom)
void propagationTime(std::vector< double > &arrival_time_dist, G4ThreeVector x0, const size_t OpChannel, bool Reflected=false)
bool isBar() const
Returns whether the detector shape is a bar (TGeoBBox).
bool const fOnlyActiveVolume
Whether photon propagation is performed only from active volumes.
int VISHits(geo::Point_t const &ScintPoint, OpticalDetector const &opDet, const double cathode_hits_rec, const std::array< double, 3 > hotspot) const
Point_t const & GetCenter() const
std::map< double, double > tpbemission
Geometry information for a single TPC.
All information of a photon entering the sensitive optical detector volume.
std::vector< std::vector< std::vector< double > > > fvispars_flat
constexpr auto abs(T v)
Returns the absolute value of the argument.
G4bool fTrackSecondariesFirst
bool isOpDetInSameTPC(geo::Point_t const &ScintPoint, geo::Point_t const &OpDetPoint) const
void LoadVisParsFlat(std::vector< double > &vis_distances_x_flat, std::vector< double > &vis_distances_r_flat, std::vector< std::vector< std::vector< double >>> &vispars_flat) const
MappedFunctions_t GetTimingTF1(Point const &p) const
std::vector< double > fvis_distances_r_flat
void ProcessStep(const G4Step &step)
std::vector< double > fdistances_refl
std::unique_ptr< G4PhysicsTable > theSlowIntegralTable
std::vector< std::vector< TF1 > > VUV_timing
std::vector< std::vector< double > > fparameters[7]
std::vector< int > fOpDetType
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
Geometry information for a single cryostat.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
void LoadGHDome(std::vector< std::vector< double >> &GHvuvpars_dome, std::vector< double > &border_corr_angulo_dome, std::vector< std::vector< double >> &border_corr_dome) const
std::vector< std::vector< double > > fGHvuvpars_flat
std::vector< std::vector< double > > VUV_min
G4double scint_time(const G4Step &aStep, G4double ScintillationTime, G4double ScintillationRiseTime) const
double fangle_bin_timing_vis
Energy deposited on a readout Optical Detector by simulated tracks.
void getVISTimes(std::vector< double > &arrivalTimes, const TVector3 &ScintPoint, const TVector3 &OpDetPoint)
geo::Point_t InitialPosition
Scintillation position in world coordinates [cm].
OpFastScintillation(const G4String &processName="Scintillation", G4ProcessType type=fElectromagnetic)
void Reset(const G4Step *step)
std::vector< std::vector< double > > fGHvuvpars_dome
void LoadVUVSemiAnalyticProperties(bool &isFlatPDCorr, bool &isDomePDCorr, double &delta_angulo_vuv, double &radius) const
Float_t y2[n_points_geant4]
int VUVHits(const double Nphotons_created, geo::Point_t const &ScintPoint, OpticalDetector const &opDet) const
unsigned int fillCoords(Coords &dest, Vector const &src)
Fills a coordinate array with the coordinates of a vector.
std::vector< double > fborder_corr_angulo_dome
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
bool StoreReflected() const
virtual G4VParticleChange * AtRestDoIt(const G4Track &aTrack, const G4Step &aStep)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
bool const bPropagate
Whether propagation of photons is enabled.
std::vector< std::vector< double > > fborder_corr_dome
std::vector< std::vector< double > > fborder_corr_flat
Simulation objects for optical detectors.
void BuildThePhysicsTable()
std::vector< double > fvis_distances_x_flat
void LoadGHFlat(std::vector< std::vector< double >> &GHvuvpars_flat, std::vector< double > &border_corr_angulo_flat, std::vector< std::vector< double >> &border_corr_flat) const
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4.
bool usesSemiAnalyticModel() const
Returns whether the semi-analytic visibility parametrization is being used.
MappedT0s_t GetReflT0s(Point const &p) const
void LoadVisParsDome(std::vector< double > &vis_distances_x_dome, std::vector< double > &vis_distances_r_dome, std::vector< std::vector< std::vector< double >>> &vispars_dome) const
std::vector< double > fborder_corr_angulo_flat
void AddPhoton(size_t opchannel, sim::OnePhoton &&photon, bool Reflected=false)
std::vector< double > fOpDetLength
geo::Point_t fcathode_centre
void SetScintillationByParticleType(const G4bool)
bool RecordPhotonsProduced(const G4Step &aStep, double N)
double fast_acos(double xin)
std::unique_ptr< CLHEP::RandGeneral > fTPBEm
std::vector< geo::BoxBoundedGeo > const fActiveVolumes
std::vector< std::vector< std::vector< double > > > ftau_pars
static IonizationAndScintillation * Instance()
Utilities to extend the interface of geometry vectors.This library provides facilities that can be us...
bool FillSimEnergyDeposits() const
void AddOpDetBacktrackerRecord(sim::OpDetBacktrackerRecord soc, bool Reflected=false)
Test of util::counter and support utilities.
void AddLitePhoton(int opchannel, int time, int nphotons, bool Reflected=false)
Description of the physical geometry of one entire detector.
static constexpr bool isDefinitelyGreaterThan(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
MappedCounts_t GetAllVisibilities(Point const &p, bool wantReflected=false) const
G4double sample_time(const G4double tau1, const G4double tau2) const
bool const fOnlyOneCryostat
void AddScintillationPhotons(TrackID_t trackID, timePDclock_t timePDclock, double numberPhotons, double const *xyz, double energy)
Add scintillation photons and energy to this OpticalDetector.
std::vector< double > fradial_distances_refl
Encapsulate the geometry of an optical detector.
std::vector< double > fvis_distances_r_dome
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
static OpDetPhotonTable * Instance(bool LitePhotons=false)
void interpolate3(std::array< double, 3 > &inter, const std::vector< double > &xData, const std::vector< double > &yData1, const std::vector< double > &yData2, const std::vector< double > &yData3, double x, bool extrapolate) const
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
void LoadVisSemiAnalyticProperties(double &delta_angulo_vis, double &radius) const
std::vector< std::vector< std::vector< double > > > fcut_off_pars
double fcathode_ydimension
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
bool const fUseNhitsModel
Whether the semi-analytic model is being used for photon visibility.
A container for photon visibility mapping data.
static constexpr bool isApproximatelyEqual(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
double dist(const TReal *x, const TReal *y, const unsigned int dimension)
std::vector< double > fvis_distances_x_dome
double Rectangle_SolidAngle(const double a, const double b, const double d) const
bool SetInSD
Whether the photon reaches the sensitive detector.
void getVUVTimes(std::vector< double > &arrivalTimes, const double distance_in_cm, const size_t angle_bin)
double Omega_Dome_Model(const double distance, const double theta) const
Singleton to access a unified treatment of ionization and scintillation in LAr.
TVector3 toTVector3(Vector const &v)
Converts a vector into a TVector3.
double reemission_energy() const
double Disk_SolidAngle(const double d, const double h, const double b) const
double interpolate(const std::vector< double > &xData, const std::vector< double > &yData, double x, bool extrapolate, size_t i=0) const
phot::MappedT0s_t ReflT0s
static int GetCurrentTrackID()
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
range_type< T > Iterate() const
void generateParam(const size_t index, const size_t angle_bin)
virtual G4VParticleChange * PostStepDoIt(const G4Track &aTrack, const G4Step &aStep)
bool UseNhitsModel() const
void ExtendToInclude(Coord_t x, Coord_t y, Coord_t z)
Extends the current box to also include the specified point.
constexpr T pi()
Returns the constant pi (up to 35 decimal digits of precision)
phot::PhotonVisibilityService const *const fPVS
Photon visibility service instance.
bool const fOpaqueCathode
Whether the cathodes are fully opaque; currently hard coded "no".
std::vector< std::vector< double > > VUV_max
boost::math::policies::policy< boost::math::policies::promote_double< false > > noLDoublePromote
double NumberScintillationPhotons() const
G4EmSaturation * emSaturation
MaybeLogger_< ELseverityLevel::ELsev_success, true > LogTrace
bool IncludeParPropTime() const
float Energy
Scintillation photon energy [GeV].
G4double GetMeanFreePath(const G4Track &aTrack, G4double, G4ForceCondition *)
G4double GetMeanLifeTime(const G4Track &aTrack, G4ForceCondition *)
size_t NOpChannels() const
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
static constexpr bool isDefinitelyLessThan(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
phot::MappedFunctions_t ParPropTimeTF1
virtual bool ScintByParticleType() const =0
double fcathode_zdimension
double fangle_bin_timing_vuv
static constexpr bool isApproximatelyZero(TReal a, TReal tolerance=std::numeric_limits< TReal >::epsilon())
void AddEnergyDeposit(int n_photon, int n_elec, double scint_yield, double energy, float start_x, float start_y, float start_z, float end_x, float end_y, float end_z, double start_time, double end_time, int trackid, int pdgcode, int g4trackid, std::string const &vol="EMPTY")
TGeoShape const * Shape() const
Returns the geometry object as TGeoShape.
art framework interface to geometry description
G4double single_exp(const G4double t, const G4double tau2) const
cet::coded_exception< error, detail::translate > exception
bool UseLitePhotons() const
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
std::unique_ptr< G4PhysicsTable > theFastIntegralTable
int MotherTrackID
ID of the GEANT4 track causing the scintillation.