97 #include "Geant4/G4Alpha.hh" 98 #include "Geant4/G4DynamicParticle.hh" 99 #include "Geant4/G4Electron.hh" 100 #include "Geant4/G4ExceptionSeverity.hh" 101 #include "Geant4/G4Gamma.hh" 102 #include "Geant4/G4KaonMinus.hh" 103 #include "Geant4/G4KaonPlus.hh" 104 #include "Geant4/G4Material.hh" 105 #include "Geant4/G4MaterialPropertiesTable.hh" 106 #include "Geant4/G4MaterialPropertyVector.hh" 107 #include "Geant4/G4MaterialTable.hh" 108 #include "Geant4/G4MuonMinus.hh" 109 #include "Geant4/G4MuonPlus.hh" 110 #include "Geant4/G4ParticleChange.hh" 111 #include "Geant4/G4PhysicsVector.hh" 112 #include "Geant4/G4PionMinus.hh" 113 #include "Geant4/G4PionPlus.hh" 114 #include "Geant4/G4Poisson.hh" 115 #include "Geant4/G4Proton.hh" 116 #include "Geant4/G4Step.hh" 117 #include "Geant4/G4StepPoint.hh" 118 #include "Geant4/G4Track.hh" 119 #include "Geant4/G4VPhysicalVolume.hh" 120 #include "Geant4/G4ios.hh" 121 #include "Geant4/Randomize.hh" 122 #include "Geant4/globals.hh" 142 #include "cetlib_except/exception.h" 145 #include "TGeoSphere.h" 147 #include "TRandom3.h" 153 #include "boost/math/special_functions/ellint_1.hpp" 154 #include "boost/math/special_functions/ellint_3.hpp" 157 typedef boost::math::policies::policy<
159 boost::math::policies::promote_double<false>>
181 : G4VRestDiscreteProcess(processName, type)
189 SetProcessSubType(25);
199 if (verboseLevel > 0) { G4cout << GetProcessName() <<
" is created " << G4endl; }
212 <<
"OpFastScintillation: active volume boundaries from " <<
fActiveVolumes.size()
215 log <<
"\n - C:" << iCryo <<
": " << box.Min() <<
" -- " << box.Max() <<
" cm";
217 log <<
"\n (scintillation photons are propagated " 224 << std::string(80,
'=') <<
"\nA detector with " << geom.
Ncryostats()
225 <<
" cryostats is configured" 226 <<
" , and semi-analytic model is requested for scintillation photon propagation." 227 <<
" THIS CONFIGURATION IS NOT SUPPORTED and it is open to bugs" 228 <<
" (e.g. scintillation may be detected only in cryostat #0)." 229 <<
"\nThis would be normally a fatal error, but it has been forcibly overridden." 231 << std::string(80,
'=');
235 <<
"Photon propagation via semi-analytic model is not supported yet" 236 <<
" on detectors with more than one cryostat.";
243 mf::LogTrace(
"OpFastScintillation") <<
"Cathode_centre: " << Cathode_centre <<
" cm";
255 if (dynamic_cast<TGeoSphere const*>(opDet.
Shape()) !=
nullptr) {
260 else if (opDet.
isBar()) {
274 std::cout <<
"Using parameterisation of timings." << std::endl;
290 const size_t num_params =
314 <<
"OpFastScintillation: using semi-analytic model for number of hits";
317 std::map<double, double> abs_length_spectrum =
318 lar::providerFrom<detinfo::LArPropertiesService>()->AbsLengthSpectrum();
319 std::vector<double> x_v, y_v;
320 for (
auto elem : abs_length_spectrum) {
321 x_v.push_back(elem.first);
322 y_v.push_back(elem.second);
328 std::cout <<
"Loading the GH corrections" << std::endl;
333 <<
"Both isFlatPDCorr and isDomePDCorr parameters are false, at least one type of " 334 "parameterisation is required for the semi-analytic light simulation." 352 std::cout <<
"Loading visible light corrections" << std::endl;
374 tpbemission = lar::providerFrom<detinfo::LArPropertiesService>()->TpbEm();
375 std::vector<double> parent;
378 parent.push_back(iter->second);
380 fTPBEm = std::make_unique<CLHEP::RandGeneral>(parent.data(), parent.size());
415 aParticleChange.Initialize(aTrack);
418 const G4Material* aMaterial = aTrack.GetMaterial();
419 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
420 if (!aMaterialPropertiesTable)
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
422 G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
423 G4ThreeVector x0 = pPreStepPoint->GetPosition();
424 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
472 aParticleChange.SetNumberOfSecondaries(0);
494 double MeanNumberOfPhotons =
498 if (verboseLevel > 0) {
499 G4cout <<
"\n Exiting from OpFastScintillation::DoIt -- NumberOfSecondaries = " 500 << aParticleChange.GetNumberOfSecondaries() << G4endl;
502 return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
507 if (step.GetTotalEnergyDeposit() <= 0)
return;
513 (
double)(step.GetTotalEnergyDeposit() / CLHEP::MeV),
514 (
float)(step.GetPreStepPoint()->GetPosition().x() / CLHEP::cm),
515 (
float)(step.GetPreStepPoint()->GetPosition().y() / CLHEP::cm),
516 (
float)(step.GetPreStepPoint()->GetPosition().z() / CLHEP::cm),
517 (
float)(step.GetPostStepPoint()->GetPosition().x() / CLHEP::cm),
518 (
float)(step.GetPostStepPoint()->GetPosition().y() / CLHEP::cm),
519 (
float)(step.GetPostStepPoint()->GetPosition().z() / CLHEP::cm),
520 (
double)(step.GetPreStepPoint()->GetGlobalTime()),
521 (
double)(step.GetPostStepPoint()->GetGlobalTime()),
524 step.GetTrack()->GetParticleDefinition()->GetPDGEncoding(),
526 step.GetPreStepPoint()->GetPhysicalVolume()->GetName());
530 double MeanNumberOfPhotons)
539 const G4Track* aTrack = aStep.GetTrack();
541 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
544 const G4DynamicParticle* aParticle = aTrack->GetDynamicParticle();
545 const G4Material* aMaterial = aTrack->GetMaterial();
547 G4int materialIndex = aMaterial->GetIndex();
548 G4int tracknumber = aStep.GetTrack()->GetTrackID();
550 G4ThreeVector x0 = pPreStepPoint->GetPosition();
551 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
553 G4double
t0 = pPreStepPoint->GetGlobalTime();
555 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
557 G4MaterialPropertyVector* Fast_Intensity =
558 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
559 G4MaterialPropertyVector* Slow_Intensity =
560 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
562 if (!Fast_Intensity && !Slow_Intensity)
return 1;
570 if (Fast_Intensity && Slow_Intensity) nscnt = 2;
573 double YieldRatio = 0;
580 G4ParticleDefinition* pDef = aParticle->GetDefinition();
587 if (pDef == G4Proton::ProtonDefinition()) {
588 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PROTONYIELDRATIO");
591 else if (pDef == G4MuonPlus::MuonPlusDefinition() ||
592 pDef == G4MuonMinus::MuonMinusDefinition()) {
593 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"MUONYIELDRATIO");
596 else if (pDef == G4PionPlus::PionPlusDefinition() ||
597 pDef == G4PionMinus::PionMinusDefinition()) {
598 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PIONYIELDRATIO");
601 else if (pDef == G4KaonPlus::KaonPlusDefinition() ||
602 pDef == G4KaonMinus::KaonMinusDefinition()) {
603 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"KAONYIELDRATIO");
606 else if (pDef == G4Alpha::AlphaDefinition()) {
607 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ALPHAYIELDRATIO");
611 else if (pDef == G4Electron::ElectronDefinition() || pDef == G4Gamma::GammaDefinition()) {
612 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
616 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
621 if (YieldRatio == 0) {
622 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
626 geo::Point_t const ScintPoint = {x0[0] / CLHEP::cm, x0[1] / CLHEP::cm, x0[2] / CLHEP::cm};
665 for (G4int scnt = 1; scnt <= nscnt; scnt++) {
666 G4double ScintillationTime = 0. * CLHEP::ns;
667 G4double ScintillationRiseTime = 0. * CLHEP::ns;
668 G4PhysicsOrderedFreeVector* ScintillationIntegral = NULL;
671 if (Fast_Intensity) {
672 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
674 ScintillationRiseTime =
675 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
677 ScintillationIntegral =
680 if (Slow_Intensity) {
681 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
683 ScintillationRiseTime =
684 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
686 ScintillationIntegral =
692 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"YIELDRATIO");
694 if (
ExcitationRatio == 1.0) { Num = std::min(YieldRatio, 1.0) * MeanNumberOfPhotons; }
698 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
700 ScintillationRiseTime =
701 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
703 ScintillationIntegral =
709 Num = MeanNumberOfPhotons - Num;
710 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
712 ScintillationRiseTime =
713 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
715 ScintillationIntegral =
719 if (!ScintillationIntegral)
continue;
734 std::map<size_t, int> DetectedNum;
738 int const DetThis = std::round(G4Poisson(Visibilities[OpDet] * Num));
739 if (DetThis > 0) DetectedNum[OpDet] = DetThis;
747 std::map<size_t, int> ReflDetectedNum;
752 int const ReflDetThis = std::round(G4Poisson(ReflVisibilities[OpDet] * Num));
753 if (ReflDetThis > 0) ReflDetectedNum[OpDet] = ReflDetThis;
761 std::vector<double> arrival_time_dist;
763 for (
size_t Reflected = 0; Reflected <= 1; ++Reflected) {
770 itstart = ReflDetectedNum.begin();
771 itend = ReflDetectedNum.end();
774 itstart = DetectedNum.begin();
775 itend = DetectedNum.end();
777 for (
auto itdetphot = itstart; itdetphot != itend; ++itdetphot) {
778 const size_t OpChannel = itdetphot->first;
779 const int NPhotons = itdetphot->second;
786 double Edeposited = 0;
789 Edeposited = aStep.GetTotalEnergyDeposit();
798 Edeposited = aStep.GetTotalEnergyDeposit();
802 arrival_time_dist.resize(NPhotons);
806 Edeposited = Edeposited / double(NPhotons);
809 for (G4int i = 0; i < NPhotons; ++i) {
811 G4double Time = t0 +
scint_time(aStep, ScintillationTime, ScintillationRiseTime) +
812 arrival_time_dist[i] * CLHEP::ns;
819 fst->
AddLitePhoton(OpChannel, static_cast<int>(Time), 1, Reflected);
823 TVector3 PhotonPosition(x0[0], x0[1], x0[2]);
825 float PhotonEnergy = 0;
829 PhotonEnergy = 9.7 * CLHEP::eV;
834 PhotToAdd.
Energy = PhotonEnergy;
835 PhotToAdd.
Time = Time;
839 fst->
AddPhoton(OpChannel, std::move(PhotToAdd), Reflected);
857 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
858 G4int numOfMaterials = G4Material::GetNumberOfMaterials();
867 for (G4int i = 0; i < numOfMaterials; i++) {
868 G4PhysicsOrderedFreeVector* aPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
869 G4PhysicsOrderedFreeVector* bPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
873 G4Material* aMaterial = (*theMaterialTable)[i];
875 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
877 if (aMaterialPropertiesTable) {
879 G4MaterialPropertyVector* theFastLightVector =
880 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
882 if (theFastLightVector) {
885 G4double currentIN = (*theFastLightVector)[0];
886 if (currentIN >= 0.0) {
889 G4double currentPM = theFastLightVector->Energy(0);
890 G4double currentCII = 0.0;
892 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
895 G4double prevPM = currentPM;
896 G4double prevCII = currentCII;
897 G4double prevIN = currentIN;
901 for (
size_t i = 1; i < theFastLightVector->GetVectorLength(); i++) {
902 currentPM = theFastLightVector->Energy(i);
903 currentIN = (*theFastLightVector)[i];
905 currentCII = 0.5 * (prevIN + currentIN);
907 currentCII = prevCII + (currentPM - prevPM) * currentCII;
909 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
912 prevCII = currentCII;
918 G4MaterialPropertyVector* theSlowLightVector =
919 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
920 if (theSlowLightVector) {
923 G4double currentIN = (*theSlowLightVector)[0];
924 if (currentIN >= 0.0) {
927 G4double currentPM = theSlowLightVector->Energy(0);
928 G4double currentCII = 0.0;
930 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
933 G4double prevPM = currentPM;
934 G4double prevCII = currentCII;
935 G4double prevIN = currentIN;
939 for (
size_t i = 1; i < theSlowLightVector->GetVectorLength(); i++) {
940 currentPM = theSlowLightVector->Energy(i);
941 currentIN = (*theSlowLightVector)[i];
943 currentCII = 0.5 * (prevIN + currentIN);
945 currentCII = prevCII + (currentPM - prevPM) * currentCII;
947 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
950 prevCII = currentCII;
969 G4Exception(
"OpFastScintillation::SetScintillationByParticleType",
972 "Redefinition: Birks Saturation is replaced by ScintillationByParticleType!");
980 G4ForceCondition* condition)
982 *condition = StronglyForced;
993 G4double ScintillationTime,
994 G4double ScintillationRiseTime)
const 996 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
997 G4StepPoint
const* pPostStepPoint = aStep.GetPostStepPoint();
998 G4double avgVelocity = (pPreStepPoint->GetVelocity() + pPostStepPoint->GetVelocity()) / 2.;
999 G4double deltaTime = aStep.GetStepLength() / avgVelocity;
1000 if (ScintillationRiseTime == 0.0) {
1001 deltaTime = deltaTime - ScintillationTime * std::log(G4UniformRand());
1004 deltaTime = deltaTime +
sample_time(ScintillationRiseTime, ScintillationTime);
1011 const size_t OpChannel,
1017 <<
"Cannot have both propagation time models simultaneously.";
1023 G4cout <<
"WARNING: Requested parameterized timing, but no function found. Not applying " 1030 <<
"No parameterized propagation time for reflected light";
1031 for (
size_t i = 0; i < arrival_time_dist.size(); ++i) {
1039 const G4ThreeVector OpDetPoint(
1040 opDetCenter.X() * CLHEP::cm, opDetCenter.Y() * CLHEP::cm, opDetCenter.Z() * CLHEP::cm);
1041 double distance_in_cm = (x0 - OpDetPoint).
mag() / CLHEP::cm;
1042 double cosine =
std::abs(x0[0] * CLHEP::cm - OpDetPoint[0] * CLHEP::cm) / distance_in_cm;
1045 getVUVTimes(arrival_time_dist, distance_in_cm, angle_bin);
1048 TVector3
const ScintPoint(x0[0] / CLHEP::cm, x0[1] / CLHEP::cm, x0[2] / CLHEP::cm);
1059 G4double ran1 = G4UniformRand();
1060 G4double ran2 = G4UniformRand();
1064 G4double
d = (tau1 + tau2) / tau2;
1067 G4double t = -1.0 * tau2 * std::log(1 - ran1);
1069 if (ran2 <=
bi_exp(t, tau1, tau2) / g)
return t;
1082 CLHEP::Hep3Vector prePoint = (aStep.GetPreStepPoint())->GetPosition();
1083 CLHEP::Hep3Vector postPoint = (aStep.GetPostStepPoint())->GetPosition();
1084 xyzPos[0] = (((prePoint.getX() + postPoint.getX()) / 2.0) / CLHEP::cm);
1085 xyzPos[1] = (((prePoint.getY() + postPoint.getY()) / 2.0) / CLHEP::cm);
1086 xyzPos[2] = (((prePoint.getZ() + postPoint.getZ()) / 2.0) / CLHEP::cm);
1235 const double signal_t_range = 5000.;
1246 std::array<double, 3> pars_landau;
1257 double pars_far[4] = {t_direct_min, pars_landau[0], pars_landau[1], pars_landau[2]};
1259 fVUVTiming = TF1(
"fVUVTiming",
model_far, 0, signal_t_range, 4);
1260 fVUVTiming.SetParameters(pars_far);
1264 fVUVTiming = TF1(
"fVUVTiming",
model_close, 0, signal_t_range, 7);
1266 double pars_expo[2];
1272 pars_expo[0] *= pars_landau[2];
1273 pars_expo[0] = std::log(pars_expo[0]);
1275 TF1 fint = TF1(
"fint",
finter_d, pars_landau[0], 4 * t_direct_mean, 5);
1276 double parsInt[5] = {
1277 pars_landau[0], pars_landau[1], pars_landau[2], pars_expo[0], pars_expo[1]};
1278 fint.SetParameters(parsInt);
1279 double t_int = fint.GetMinimumX();
1280 double minVal = fint.Eval(t_int);
1282 if (minVal > 0.015) {
1283 std::cout <<
"WARNING: Parametrization of VUV light discontinuous for distance = " 1284 << distance_in_cm << std::endl;
1285 std::cout <<
"WARNING: This shouldn't be happening " << std::endl;
1287 double parsfinal[7] = {t_int,
1294 fVUVTiming.SetParameters(parsfinal);
1300 if (distance_in_cm < 50) { fsampling = 10000; }
1301 else if (distance_in_cm < 100) {
1307 fVUVTiming.SetNpx(fsampling);
1311 const size_t nq_max = 1;
1312 double xq_max[nq_max];
1313 double yq_max[nq_max];
1315 fVUVTiming.GetQuantiles(nq_max, yq_max, xq_max);
1316 double max = yq_max[0];
1318 double min = t_direct_min;
1324 VUV_max[angle_bin][index] = max;
1325 VUV_min[angle_bin][index] = min;
1330 const double distance,
1331 const size_t angle_bin)
1336 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1337 arrivalTimes[i] = t_prop_correction;
1346 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1347 arrivalTimes[i] =
VUV_timing[angle_bin][index].GetRandom(
VUV_min[angle_bin][index],
1355 const TVector3& ScintPoint,
1356 const TVector3& OpDetPoint)
1364 if (ScintPoint[0] < 0) { plane_depth = -
fplane_depth; }
1370 TVector3 bounce_point(plane_depth, ScintPoint[1], ScintPoint[2]);
1373 double VUVdist = (bounce_point - ScintPoint).Mag();
1374 double Visdist = (OpDetPoint - bounce_point).Mag();
1377 int angle_bin_vuv = 0;
1378 getVUVTimes(arrivalTimes, VUVdist, angle_bin_vuv);
1381 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1398 vuv_time =
VUV_min[angle_bin_vuv][index];
1401 double fastest_time = vis_time + vuv_time;
1404 double cosine_theta =
std::abs(OpDetPoint[0] - bounce_point[0]) / Visdist;
1411 double distance_cathode_plane =
std::abs(plane_depth - ScintPoint[0]);
1422 for (
size_t i = 0; i <
fcut_off_pars[theta_bin].size(); i++) {
1431 std::vector<double> interp_vals_tau(
ftau_pars[theta_bin].
size(), 0.0);
1432 for (
size_t i = 0; i <
ftau_pars[theta_bin].size(); i++) {
1433 interp_vals_tau[i] =
1439 if (tau < 0) { tau = 0; }
1442 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1443 double arrival_time_smeared;
1445 if (arrivalTimes[i] >= cutoff) {
continue; }
1453 if (counter >= 10) {
1454 arrival_time_smeared = arrivalTimes[i];
1459 double x = gRandom->Uniform(0.5, 1.0);
1461 arrival_time_smeared =
1462 arrivalTimes[i] + (arrivalTimes[i] - fastest_time) * (std::pow(x, -tau) - 1);
1465 }
while (arrival_time_smeared > cutoff);
1467 arrivalTimes[i] = arrival_time_smeared;
1490 const int DetThis =
VUVHits(Num, ScintPoint, op);
1492 DetectedNum[OpDet] = DetThis;
1510 if (ScintPoint.X() < 0.) { plane_depth = -
fplane_depth; }
1516 std::array<double, 3> ScintPoint_relative = {
std::abs(ScintPoint.X() - plane_depth),
1525 double distance_cathode =
std::abs(plane_depth - ScintPoint.X());
1527 double cathode_hits_geo = std::exp(-1. * distance_cathode /
fL_abs_vuv) *
1528 (solid_angle_cathode / (4. *
CLHEP::pi)) * Num;
1533 double pars_ini[4] = {0, 0, 0, 0};
1548 <<
"Error: flat optical detector VUV correction required for reflected semi-analytic hits." 1552 pars_ini[0] = pars_ini[0] + s1 *
r;
1553 pars_ini[1] = pars_ini[1] + s2 *
r;
1554 pars_ini[2] = pars_ini[2] + s3 *
r;
1555 pars_ini[3] = pars_ini[3];
1558 double GH_correction =
Gaisser_Hillas(distance_cathode, pars_ini);
1559 const double cathode_hits_rec = GH_correction * cathode_hits_geo;
1562 const std::array<double, 3> hotspot = {plane_depth, ScintPoint.Y(), ScintPoint.Z()};
1572 int const ReflDetThis =
VISHits(ScintPoint, op, cathode_hits_rec, hotspot);
1573 if (ReflDetThis > 0) { ReflDetectedNum[OpDet] = ReflDetThis; }
1583 std::array<double, 3U> ScintPoint;
1584 std::array<double, 3U> OpDetPoint;
1589 double distance =
dist(&ScintPoint[0], &OpDetPoint[0], 3);
1590 double cosine =
std::abs(ScintPoint[0] - OpDetPoint[0]) / distance;
1595 double solid_angle = 0;
1597 if (opDet.
type == 0) {
1599 std::array<double, 3> ScintPoint_rel = {
std::abs(ScintPoint[0] - OpDetPoint[0]),
1600 std::abs(ScintPoint[1] - OpDetPoint[1]),
1601 std::abs(ScintPoint[2] - OpDetPoint[2])};
1606 else if (opDet.
type == 1) {
1610 else if (opDet.
type == 2) {
1612 double d =
dist(&ScintPoint[1], &OpDetPoint[1], 2);
1614 double h =
std::abs(ScintPoint[0] - OpDetPoint[0]);
1619 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" 1625 std::exp(-1. * distance /
fL_abs_vuv) * (solid_angle / (4 *
CLHEP::pi)) * Nphotons_created;
1635 double pars_ini[4] = {0, 0, 0, 0};
1660 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or " 1661 "corrections for chosen optical detector type missing." 1665 pars_ini[0] = pars_ini[0] + s1 *
r;
1666 pars_ini[1] = pars_ini[1] + s2 *
r;
1667 pars_ini[2] = pars_ini[2] + s3 *
r;
1668 pars_ini[3] = pars_ini[3];
1674 double hits_rec = GH_correction * hits_geo / cosine;
1675 int hits_vuv = std::round(G4Poisson(hits_rec));
1683 const double cathode_hits_rec,
1684 const std::array<double, 3> hotspot)
const 1692 if (ScintPoint_v.X() < 0.) { plane_depth = -
fplane_depth; }
1701 std::array<double, 3U> ScintPoint;
1702 std::array<double, 3U> OpDetPoint;
1708 double distance_vis =
dist(&hotspot[0], &OpDetPoint[0], 3);
1710 double cosine_vis =
std::abs(hotspot[0] - OpDetPoint[0]) / distance_vis;
1715 double solid_angle_detector = 0;
1717 if (opDet.
type == 0) {
1719 std::array<double, 3> emission_relative = {
std::abs(hotspot[0] - OpDetPoint[0]),
1720 std::abs(hotspot[1] - OpDetPoint[1]),
1721 std::abs(hotspot[2] - OpDetPoint[2])};
1726 else if (opDet.
type == 1) {
1730 else if (opDet.
type == 2) {
1732 double d =
dist(&hotspot[1], &OpDetPoint[1], 2);
1734 double h =
std::abs(hotspot[0] - OpDetPoint[0]);
1739 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" 1744 double hits_geo = (solid_angle_detector / (2. *
CLHEP::pi)) *
1752 double d_c =
std::abs(ScintPoint[0] - plane_depth);
1753 double border_correction = 0;
1758 std::vector<double> interp_vals(nbins_r, 0.0);
1768 for (
size_t i = 0; i < nbins_r; ++i) {
1779 std::vector<double> interp_vals(nbins_r, 0.0);
1789 for (
size_t i = 0; i < nbins_r; ++i) {
1797 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or " 1798 "corrections for chosen optical detector type missing." 1803 double hits_rec = border_correction * hits_geo / cosine_vis;
1804 double hits_vis = std::round(G4Poisson(hits_rec));
1815 if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
1830 return std::exp(-1.0 * t / tau2) / tau2;
1834 const G4double tau1,
1835 const G4double tau2)
const 1837 return std::exp(-1.0 * t / tau2) * (1 - std::exp(-1.0 * t / tau1)) / tau2 / tau2 *
1843 double X_mu_0 = par[3];
1844 double Normalization = par[0];
1845 double Diff = par[1] - X_mu_0;
1846 double Term = std::pow((x - X_mu_0) / Diff, Diff / par[2]);
1847 double Exponential = std::exp((par[1] - x) / par[2]);
1848 return (Normalization * Term * Exponential);
1853 double y1 = par[2] * TMath::Landau(x[0], par[0], par[1]);
1854 double y2 = TMath::Exp(par[3] + x[0] * par[4]);
1855 return TMath::Abs(y1 - y2);
1866 double y1 = par[3] * TMath::Landau(x[0], par[1], par[2]);
1867 double y2 = TMath::Exp(par[4] + x[0] * par[5]);
1868 if (x[0] > par[0]) y1 = 0.;
1869 if (x[0] < par[0]) y2 = 0.;
1875 double y1 = par[2] * TMath::Landau(x[0], par[0], par[1]);
1876 double y2 = par[5] * TMath::Landau(x[0], par[3], par[4]);
1877 return TMath::Abs(y1 - y2);
1889 double y1 = par[3] * TMath::Landau(x[0], par[1], par[2]);
1890 double y2 = TMath::Exp(par[4] + x[0] * par[5]);
1891 if (x[0] <= par[6] || x[0] > par[0]) y1 = 0.;
1892 if (x[0] < par[0]) y2 = 0.;
1902 double y = par[3] * TMath::Landau(x[0], par[1], par[2]);
1903 if (x[0] <= par[0]) y = 0.;
1912 const std::vector<double>& yData,
1918 size_t size = xData.size();
1919 if (x >= xData[size - 2]) {
1923 while (x > xData[i + 1])
1927 double xL = xData[i];
1928 double xR = xData[i + 1];
1929 double yL = yData[i];
1930 double yR = yData[i + 1];
1932 if (x < xL)
return yL;
1933 if (x > xR)
return yL;
1935 const double dydx = (yR - yL) / (xR - xL);
1936 return yL + dydx * (x - xL);
1940 const std::vector<double>& xData,
1941 const std::vector<double>& yData1,
1942 const std::vector<double>& yData2,
1943 const std::vector<double>& yData3,
1945 bool extrapolate)
const 1947 size_t size = xData.size();
1949 if (x >= xData[size - 2]) {
1953 while (x > xData[i + 1])
1956 double xL = xData[i];
1957 double xR = xData[i + 1];
1958 double yL1 = yData1[i];
1959 double yR1 = yData1[i + 1];
1960 double yL2 = yData2[i];
1961 double yR2 = yData2[i + 1];
1962 double yL3 = yData3[i];
1963 double yR3 = yData3[i + 1];
1979 const double m = (x - xL) / (xR - xL);
1980 inter[0] = m * (yR1 - yL1) + yL1;
1981 inter[1] = m * (yR2 - yL2) + yL2;
1982 inter[2] = m * (yR3 - yL3) + yL3;
1992 if (b <= 0. || d < 0. || h <= 0.)
return 0.;
1993 const double leg2 = (b +
d) * (b + d);
1994 const double aa = std::sqrt(h * h / (h * h + leg2));
1996 double bb = 2. * std::sqrt(b * d / (h * h + leg2));
1997 double cc = 4. * b * d / leg2;
2005 catch (std::domain_error&
e) {
2008 <<
"Elliptic Integral in Disk_SolidAngle() given parameters outside domain." 2009 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
2010 <<
"\nRelax condition and carry on.";
2015 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters outside domain.\n" 2016 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
2028 catch (std::domain_error&
e) {
2031 <<
"Elliptic Integral in Disk_SolidAngle() given parameters outside domain." 2032 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
2033 <<
"\nRelax condition and carry on.";
2038 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters outside domain.\n" 2039 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
2053 const double d)
const 2055 double aa = a / (2. *
d);
2056 double bb = b / (2. *
d);
2057 double aux = (1. + aa * aa + bb * bb) / ((1. + aa * aa) * (1. + bb * bb));
2064 const std::array<double, 3> v)
const 2074 double A = v[1] - o.
h * .5;
2075 double B = v[2] - o.
w * .5;
2083 if ((v[1] <= o.
h * .5) && (v[2] <= o.
w * .5)) {
2084 double A = -v[1] + o.
h * .5;
2085 double B = -v[2] + o.
w * .5;
2094 double A = v[1] - o.
h * .5;
2095 double B = -v[2] + o.
w * .5;
2104 double A = -v[1] + o.
h * .5;
2105 double B = v[2] - o.
w * .5;
2129 double par0[9] = {0., 0., 0., 0., 0., 0.597542, 1.00872, 1.46993, 2.04221};
2130 double par1[9] = {0, 0, 0.19569, 0.300449, 0.555598, 0.854939, 1.39166, 2.19141, 2.57732};
2131 const double delta_theta = 10.;
2132 int j = int(theta / delta_theta);
2136 const double d_break = 5 * b;
2138 if (distance >= d_break) {
2139 double R_apparent_far = b - par1[j];
2140 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - std::pow(R_apparent_far / distance, 2))));
2143 double R_apparent_close = b - par0[j];
2144 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - std::pow(R_apparent_close / distance, 2))));
2152 std::vector<geo::BoxBoundedGeo> activeVolumes;
2163 activeVolumes.push_back(std::move(box));
2167 return activeVolumes;
2174 double negate = double(x < 0);
2176 x -= double(x > 1.0) * (x - 1.0);
2177 double ret = -0.0187293;
2179 ret = ret + 0.0742610;
2181 ret = ret - 0.2121144;
2183 ret = ret + 1.5707288;
2184 ret = ret * std::sqrt(1.0 - x);
2185 ret = ret - 2. * negate * ret;
2186 return negate * 3.14159265358979 + ret;
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
details::range_type< T > Iterate() const
Initializes the specified ID with the ID of the first cryostat.
Store parameters for running LArG4.
bool IncludePropTime() const
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
Point_t GetCathodeCenter() const
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
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
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
Float_t y1[n_points_granero]
double finflexion_point_distance
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
Definition of util::enumerate().
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
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)
double finter_d(double *x, double *par)
std::vector< double > fdistances_refl
std::unique_ptr< G4PhysicsTable > theSlowIntegralTable
double model_far(double *x, double *par)
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.
double model_close(double *x, double *par)
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
double finter_r(double *x, double *par)
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
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
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.
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
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.
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)
boost::math::policies::policy< boost::math::policies::promote_double< false > > noLDoublePromote
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.
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 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.
geo::Point_t const & GetCenter() const
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())
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)
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
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
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
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
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
double LandauPlusExpoFinal(double *x, double *par)
double fast_acos(double x)
std::unique_ptr< G4PhysicsTable > theFastIntegralTable
int MotherTrackID
ID of the GEANT4 track causing the scintillation.