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" 146 #include "TRandom3.h" 147 #include "TGeoSphere.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 " 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." 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;
312 <<
"OpFastScintillation: using semi-analytic model for number of hits";
315 std::map<double, double> abs_length_spectrum =
316 lar::providerFrom<detinfo::LArPropertiesService>()->AbsLengthSpectrum();
317 std::vector<double> x_v, y_v;
318 for (
auto elem : abs_length_spectrum) {
319 x_v.push_back(elem.first);
320 y_v.push_back(elem.second);
326 std::cout <<
"Loading the GH corrections" <<
std::endl;
334 <<
"Both isFlatPDCorr and isDomePDCorr parameters are false, at least one type of parameterisation is required for the semi-analytic light simulation." <<
"\n";
357 std::cout <<
"Loading visible light corrections" <<
std::endl;
387 tpbemission = lar::providerFrom<detinfo::LArPropertiesService>()->TpbEm();
388 std::vector<double>
parent;
391 parent.push_back(iter->second);
393 fTPBEm = std::make_unique<CLHEP::RandGeneral>
394 (parent.data(), parent.size());
431 aParticleChange.Initialize(aTrack);
434 const G4Material* aMaterial = aTrack.GetMaterial();
435 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
436 if (!aMaterialPropertiesTable)
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
438 G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
439 G4ThreeVector x0 = pPreStepPoint->GetPosition();
440 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
488 aParticleChange.SetNumberOfSecondaries(0);
510 double MeanNumberOfPhotons =
514 if (verboseLevel > 0) {
515 G4cout <<
"\n Exiting from OpFastScintillation::DoIt -- NumberOfSecondaries = " 516 << aParticleChange.GetNumberOfSecondaries() << G4endl;
518 return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
524 if (step.GetTotalEnergyDeposit() <= 0)
return;
530 (
double)(step.GetTotalEnergyDeposit() /
CLHEP::MeV),
531 (
float)(step.GetPreStepPoint()->GetPosition().x() /
CLHEP::cm),
532 (
float)(step.GetPreStepPoint()->GetPosition().y() /
CLHEP::cm),
533 (
float)(step.GetPreStepPoint()->GetPosition().z() /
CLHEP::cm),
534 (
float)(step.GetPostStepPoint()->GetPosition().x() /
CLHEP::cm),
535 (
float)(step.GetPostStepPoint()->GetPosition().y() /
CLHEP::cm),
536 (
float)(step.GetPostStepPoint()->GetPosition().z() /
CLHEP::cm),
537 (
double)(step.GetPreStepPoint()->GetGlobalTime()),
538 (
double)(step.GetPostStepPoint()->GetGlobalTime()),
541 step.GetTrack()->GetParticleDefinition()->GetPDGEncoding(),
542 step.GetPreStepPoint()->GetPhysicalVolume()->GetName());
546 double MeanNumberOfPhotons)
555 const G4Track* aTrack = aStep.GetTrack();
557 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
560 const G4DynamicParticle* aParticle = aTrack->GetDynamicParticle();
561 const G4Material* aMaterial = aTrack->GetMaterial();
563 G4int materialIndex = aMaterial->GetIndex();
564 G4int tracknumber = aStep.GetTrack()->GetTrackID();
566 G4ThreeVector x0 = pPreStepPoint->GetPosition();
567 G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
569 G4double
t0 = pPreStepPoint->GetGlobalTime();
571 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
573 G4MaterialPropertyVector* Fast_Intensity =
574 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
575 G4MaterialPropertyVector* Slow_Intensity =
576 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
578 if (!Fast_Intensity && !Slow_Intensity)
return 1;
586 if (Fast_Intensity && Slow_Intensity) nscnt = 2;
589 double YieldRatio = 0;
596 G4ParticleDefinition* pDef = aParticle->GetDefinition();
603 if (pDef == G4Proton::ProtonDefinition()) {
604 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PROTONYIELDRATIO");
607 else if (pDef == G4MuonPlus::MuonPlusDefinition() ||
608 pDef == G4MuonMinus::MuonMinusDefinition()) {
609 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"MUONYIELDRATIO");
612 else if (pDef == G4PionPlus::PionPlusDefinition() ||
613 pDef == G4PionMinus::PionMinusDefinition()) {
614 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"PIONYIELDRATIO");
617 else if (pDef == G4KaonPlus::KaonPlusDefinition() ||
618 pDef == G4KaonMinus::KaonMinusDefinition()) {
619 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"KAONYIELDRATIO");
622 else if (pDef == G4Alpha::AlphaDefinition()) {
623 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ALPHAYIELDRATIO");
627 else if (pDef == G4Electron::ElectronDefinition() || pDef == G4Gamma::GammaDefinition()) {
628 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
632 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
637 if (YieldRatio == 0) {
638 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"ELECTRONYIELDRATIO");
681 for (G4int scnt = 1; scnt <= nscnt; scnt++) {
682 G4double ScintillationTime = 0. *
CLHEP::ns;
683 G4double ScintillationRiseTime = 0. *
CLHEP::ns;
684 G4PhysicsOrderedFreeVector* ScintillationIntegral = NULL;
687 if (Fast_Intensity) {
688 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
690 ScintillationRiseTime =
691 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
693 ScintillationIntegral =
696 if (Slow_Intensity) {
697 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
699 ScintillationRiseTime =
700 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
702 ScintillationIntegral =
708 YieldRatio = aMaterialPropertiesTable->GetConstProperty(
"YIELDRATIO");
714 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"FASTTIMECONSTANT");
716 ScintillationRiseTime =
717 aMaterialPropertiesTable->GetConstProperty(
"FASTSCINTILLATIONRISETIME");
719 ScintillationIntegral =
725 Num = MeanNumberOfPhotons - Num;
726 ScintillationTime = aMaterialPropertiesTable->GetConstProperty(
"SLOWTIMECONSTANT");
728 ScintillationRiseTime =
729 aMaterialPropertiesTable->GetConstProperty(
"SLOWSCINTILLATIONRISETIME");
731 ScintillationIntegral =
735 if (!ScintillationIntegral)
continue;
750 std::map<size_t, int> DetectedNum;
754 int const DetThis = std::round(G4Poisson(Visibilities[OpDet] * Num));
755 if (DetThis > 0) DetectedNum[OpDet] = DetThis;
763 std::map<size_t, int> ReflDetectedNum;
768 int const ReflDetThis = std::round(G4Poisson(ReflVisibilities[OpDet] * Num));
769 if (ReflDetThis > 0) ReflDetectedNum[OpDet] = ReflDetThis;
777 std::vector<double> arrival_time_dist;
779 for (
size_t Reflected = 0; Reflected <= 1; ++Reflected) {
786 itstart = ReflDetectedNum.begin();
787 itend = ReflDetectedNum.end();
790 itstart = DetectedNum.begin();
791 itend = DetectedNum.end();
793 for (
auto itdetphot = itstart; itdetphot != itend; ++itdetphot) {
794 const size_t OpChannel = itdetphot->first;
795 const int NPhotons = itdetphot->second;
802 double Edeposited = 0;
805 Edeposited = aStep.GetTotalEnergyDeposit();
814 Edeposited = aStep.GetTotalEnergyDeposit();
818 arrival_time_dist.resize(NPhotons);
822 Edeposited = Edeposited / double(NPhotons);
825 for (G4int i = 0; i < NPhotons; ++i) {
827 G4double Time = t0 +
scint_time(aStep, ScintillationTime, ScintillationRiseTime) +
835 fst->
AddLitePhoton(OpChannel, static_cast<int>(Time), 1, Reflected);
839 TVector3 PhotonPosition(x0[0], x0[1], x0[2]);
841 float PhotonEnergy = 0;
850 PhotToAdd.
Energy = PhotonEnergy;
851 PhotToAdd.
Time = Time;
874 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
875 G4int numOfMaterials = G4Material::GetNumberOfMaterials();
884 for (G4int i = 0; i < numOfMaterials; i++) {
885 G4PhysicsOrderedFreeVector* aPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
886 G4PhysicsOrderedFreeVector* bPhysicsOrderedFreeVector =
new G4PhysicsOrderedFreeVector();
890 G4Material* aMaterial = (*theMaterialTable)[i];
892 G4MaterialPropertiesTable* aMaterialPropertiesTable = aMaterial->GetMaterialPropertiesTable();
894 if (aMaterialPropertiesTable) {
896 G4MaterialPropertyVector* theFastLightVector =
897 aMaterialPropertiesTable->GetProperty(
"FASTCOMPONENT");
899 if (theFastLightVector) {
902 G4double currentIN = (*theFastLightVector)[0];
903 if (currentIN >= 0.0) {
906 G4double currentPM = theFastLightVector->Energy(0);
907 G4double currentCII = 0.0;
909 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
912 G4double prevPM = currentPM;
913 G4double prevCII = currentCII;
914 G4double prevIN = currentIN;
918 for (
size_t i = 1; i < theFastLightVector->GetVectorLength(); i++) {
919 currentPM = theFastLightVector->Energy(i);
920 currentIN = (*theFastLightVector)[i];
922 currentCII = 0.5 * (prevIN + currentIN);
924 currentCII = prevCII + (currentPM - prevPM) * currentCII;
926 aPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
929 prevCII = currentCII;
935 G4MaterialPropertyVector* theSlowLightVector =
936 aMaterialPropertiesTable->GetProperty(
"SLOWCOMPONENT");
937 if (theSlowLightVector) {
940 G4double currentIN = (*theSlowLightVector)[0];
941 if (currentIN >= 0.0) {
944 G4double currentPM = theSlowLightVector->Energy(0);
945 G4double currentCII = 0.0;
947 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
950 G4double prevPM = currentPM;
951 G4double prevCII = currentCII;
952 G4double prevIN = currentIN;
956 for (
size_t i = 1; i < theSlowLightVector->GetVectorLength(); i++) {
957 currentPM = theSlowLightVector->Energy(i);
958 currentIN = (*theSlowLightVector)[i];
960 currentCII = 0.5 * (prevIN + currentIN);
962 currentCII = prevCII + (currentPM - prevPM) * currentCII;
964 bPhysicsOrderedFreeVector->InsertValues(currentPM, currentCII);
967 prevCII = currentCII;
987 G4Exception(
"OpFastScintillation::SetScintillationByParticleType",
990 "Redefinition: Birks Saturation is replaced by ScintillationByParticleType!");
999 *condition = StronglyForced;
1006 *condition = Forced;
1012 G4double ScintillationTime,
1013 G4double ScintillationRiseTime)
const 1015 G4StepPoint
const* pPreStepPoint = aStep.GetPreStepPoint();
1016 G4StepPoint
const* pPostStepPoint = aStep.GetPostStepPoint();
1017 G4double avgVelocity = (pPreStepPoint->GetVelocity() + pPostStepPoint->GetVelocity()) / 2.;
1018 G4double deltaTime = aStep.GetStepLength() / avgVelocity;
1019 if (ScintillationRiseTime == 0.0) {
1020 deltaTime = deltaTime - ScintillationTime * std::log(G4UniformRand());
1023 deltaTime = deltaTime +
sample_time(ScintillationRiseTime, ScintillationTime);
1036 <<
"Cannot have both propagation time models simultaneously.";
1042 G4cout <<
"WARNING: Requested parameterized timing, but no function found. Not applying " 1049 <<
"No parameterized propagation time for reflected light";
1050 for (
size_t i = 0; i < arrival_time_dist.size(); ++i) {
1058 const G4ThreeVector OpDetPoint(
1060 double distance_in_cm = (x0 - OpDetPoint).
mag() /
CLHEP::cm;
1064 getVUVTimes(arrival_time_dist, distance_in_cm, angle_bin);
1079 G4double ran1 = G4UniformRand();
1080 G4double ran2 = G4UniformRand();
1084 G4double
d = (tau1 + tau2) / tau2;
1087 G4double
t = -1.0 * tau2 * std::log(1 - ran1);
1089 if (ran2 <=
bi_exp(t, tau1, tau2) / g)
return t;
1104 CLHEP::Hep3Vector prePoint = (aStep.GetPreStepPoint())->GetPosition();
1105 CLHEP::Hep3Vector postPoint = (aStep.GetPostStepPoint())->GetPosition();
1106 xyzPos[0] = (((prePoint.getX() + postPoint.getX()) / 2.0) /
CLHEP::cm);
1107 xyzPos[1] = (((prePoint.getY() + postPoint.getY()) / 2.0) /
CLHEP::cm);
1108 xyzPos[2] = (((prePoint.getZ() + postPoint.getZ()) / 2.0) /
CLHEP::cm);
1258 const double signal_t_range = 5000.;
1269 std::array<double, 3> pars_landau;
1280 double pars_far[4] = {t_direct_min, pars_landau[0], pars_landau[1], pars_landau[2]};
1282 fVUVTiming = TF1(
"fVUVTiming",
model_far, 0, signal_t_range, 4);
1283 fVUVTiming.SetParameters(pars_far);
1287 fVUVTiming = TF1(
"fVUVTiming",
model_close, 0, signal_t_range, 7);
1289 double pars_expo[2];
1293 pars_expo[0] *= pars_landau[2];
1294 pars_expo[0] = std::log(pars_expo[0]);
1296 TF1 fint = TF1(
"fint",
finter_d, pars_landau[0], 4 * t_direct_mean, 5);
1297 double parsInt[5] = {
1298 pars_landau[0], pars_landau[1], pars_landau[2], pars_expo[0], pars_expo[1]};
1299 fint.SetParameters(parsInt);
1300 double t_int = fint.GetMinimumX();
1301 double minVal = fint.Eval(t_int);
1303 if (minVal > 0.015) {
1304 std::cout <<
"WARNING: Parametrization of VUV light discontinuous for distance = " 1306 std::cout <<
"WARNING: This shouldn't be happening " <<
std::endl;
1308 double parsfinal[7] = {t_int,
1315 fVUVTiming.SetParameters(parsfinal);
1321 if (distance_in_cm < 50) { fsampling = 10000; }
1322 else if (distance_in_cm < 100) {
1328 fVUVTiming.SetNpx(fsampling);
1332 const size_t nq_max = 1;
1333 double xq_max[nq_max];
1334 double yq_max[nq_max];
1336 fVUVTiming.GetQuantiles(nq_max, yq_max, xq_max);
1337 double max = yq_max[0];
1339 double min = t_direct_min;
1356 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1357 arrivalTimes[i] = t_prop_correction;
1366 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1375 const TVector3 &ScintPoint,
1376 const TVector3 &OpDetPoint)
1384 if (ScintPoint[0] < 0) { plane_depth = -
fplane_depth; }
1390 TVector3 bounce_point(plane_depth,ScintPoint[1],ScintPoint[2]);
1393 double VUVdist = (bounce_point - ScintPoint).Mag();
1394 double Visdist = (OpDetPoint - bounce_point).Mag();
1397 int angle_bin_vuv = 0;
1398 getVUVTimes(arrivalTimes, VUVdist, angle_bin_vuv);
1401 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1423 double fastest_time = vis_time + vuv_time;
1426 double cosine_theta =
std::abs(OpDetPoint[0] - bounce_point[0]) / Visdist;
1433 double distance_cathode_plane =
std::abs(plane_depth - ScintPoint[0]);
1443 for (
size_t i = 0; i <
fcut_off_pars[theta_bin].size(); i++){
1451 std::vector<double> interp_vals_tau(
ftau_pars[theta_bin].
size(), 0.0);
1452 for (
size_t i = 0; i <
ftau_pars[theta_bin].size(); i++){
1458 if (tau < 0) { tau = 0; }
1461 for (
size_t i = 0; i < arrivalTimes.size(); ++i) {
1462 double arrival_time_smeared;
1464 if (arrivalTimes[i] >= cutoff) {
continue; }
1472 if (counter >= 10) {
1473 arrival_time_smeared = arrivalTimes[i];
1478 double x = gRandom->Uniform(0.5, 1.0);
1480 arrival_time_smeared =
1481 arrivalTimes[i] + (arrivalTimes[i] - fastest_time) * (
std::pow(x, -tau) - 1);
1484 }
while (arrival_time_smeared > cutoff);
1486 arrivalTimes[i] = arrival_time_smeared;
1510 const int DetThis =
VUVHits(Num, ScintPoint, op);
1512 DetectedNum[OpDet] = DetThis;
1531 if (ScintPoint.X() < 0.) { plane_depth = -
fplane_depth; }
1537 std::array<double, 3> ScintPoint_relative = {
std::abs(ScintPoint.X() - plane_depth),
1546 double distance_cathode =
std::abs(plane_depth - ScintPoint.X());
1548 double cathode_hits_geo = std::exp(-1. * distance_cathode /
fL_abs_vuv) *
1549 (solid_angle_cathode / (4. *
CLHEP::pi)) * Num;
1553 double pars_ini[4] = {0, 0, 0, 0};
1554 double s1 = 0;
double s2 = 0;
double s3 = 0;
1564 else std::cout <<
"Error: flat optical detector VUV correction required for reflected semi-analytic hits." <<
std::endl;
1567 pars_ini[0] = pars_ini[0] + s1 *
r;
1568 pars_ini[1] = pars_ini[1] + s2 *
r;
1569 pars_ini[2] = pars_ini[2] + s3 *
r;
1570 pars_ini[3] = pars_ini[3];
1574 double GH_correction =
Gaisser_Hillas(distance_cathode, pars_ini);
1575 const double cathode_hits_rec = GH_correction * cathode_hits_geo;
1578 const std::array<double, 3> hotspot = {plane_depth, ScintPoint.Y(), ScintPoint.Z()};
1587 int const ReflDetThis =
1588 VISHits(ScintPoint, op, cathode_hits_rec, hotspot);
1589 if (ReflDetThis > 0) { ReflDetectedNum[OpDet] = ReflDetThis; }
1600 std::array<double, 3U> ScintPoint;
1601 std::array<double, 3U> OpDetPoint;
1606 double distance =
dist(&ScintPoint[0], &OpDetPoint[0], 3);
1612 double solid_angle = 0;
1614 if (opDet.
type == 0) {
1616 std::array<double, 3> ScintPoint_rel = {
std::abs(ScintPoint[0] - OpDetPoint[0]),
1617 std::abs(ScintPoint[1] - OpDetPoint[1]),
1618 std::abs(ScintPoint[2] - OpDetPoint[2])};
1623 else if (opDet.
type == 1) {
1627 else if (opDet.
type == 2) {
1629 double d =
dist(&ScintPoint[1], &OpDetPoint[1], 2);
1631 double h =
std::abs(ScintPoint[0] - OpDetPoint[0]);
1636 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" <<
std::endl;
1640 double hits_geo = std::exp(-1. * distance /
fL_abs_vuv) * (solid_angle / (4 *
CLHEP::pi)) * Nphotons_created;
1649 double pars_ini[4] = {0, 0, 0, 0};
1650 double s1 = 0;
double s2 = 0;
double s3 = 0;
1671 else std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or corrections for chosen optical detector type missing." <<
std::endl;
1674 pars_ini[0] = pars_ini[0] + s1 *
r;
1675 pars_ini[1] = pars_ini[1] + s2 *
r;
1676 pars_ini[2] = pars_ini[2] + s3 *
r;
1677 pars_ini[3] = pars_ini[3];
1683 double hits_rec = GH_correction * hits_geo / cosine;
1684 int hits_vuv = std::round(G4Poisson(hits_rec));
1693 const double cathode_hits_rec,
1694 const std::array<double, 3> hotspot)
const 1702 if (ScintPoint_v.X() < 0.) { plane_depth = -
fplane_depth; }
1711 std::array<double, 3U> ScintPoint;
1712 std::array<double, 3U> OpDetPoint;
1718 double distance_vis =
dist(&hotspot[0], &OpDetPoint[0], 3);
1720 double cosine_vis =
std::abs(hotspot[0] - OpDetPoint[0]) / distance_vis;
1725 double solid_angle_detector = 0;
1727 if (opDet.
type == 0) {
1729 std::array<double, 3> emission_relative = {
std::abs(hotspot[0] - OpDetPoint[0]),
1730 std::abs(hotspot[1] - OpDetPoint[1]),
1731 std::abs(hotspot[2] - OpDetPoint[2])};
1736 else if (opDet.
type == 1) {
1740 else if (opDet.
type == 2) {
1742 double d =
dist(&hotspot[1], &OpDetPoint[1], 2);
1744 double h =
std::abs(hotspot[0] - OpDetPoint[0]);
1749 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk" <<
std::endl;
1753 double hits_geo = (solid_angle_detector / (2. *
CLHEP::pi)) * cathode_hits_rec;
1758 double d_c =
std::abs(ScintPoint[0] - plane_depth);
1759 double border_correction = 0;
1764 std::vector<double> interp_vals(nbins_r, 0.0);
1774 for (
size_t i = 0; i < nbins_r; ++i) {
1789 std::vector<double> interp_vals(nbins_r, 0.0);
1799 for (
size_t i = 0; i < nbins_r; ++i) {
1811 std::cout <<
"Error: Invalid optical detector type. 0 = rectangular, 1 = dome, 2 = disk. Or corrections for chosen optical detector type missing." <<
std::endl;
1815 double hits_rec = border_correction * hits_geo / cosine_vis;
1816 double hits_vis = std::round(G4Poisson(hits_rec));
1828 if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
1845 return std::exp(-1.0 * t / tau2) / tau2;
1851 return std::exp(-1.0 * t / tau2) * (1 - std::exp(-1.0 * t / tau1)) / tau2 / tau2 *
1858 double X_mu_0 = par[3];
1859 double Normalization = par[0];
1860 double Diff = par[1] - X_mu_0;
1861 double Term =
std::pow((x - X_mu_0) / Diff, Diff / par[2]);
1862 double Exponential = std::exp((par[1] - x) / par[2]);
1863 return (Normalization * Term * Exponential);
1869 double y1 = par[2] * TMath::Landau(x[0], par[0], par[1]);
1870 double y2 = TMath::Exp(par[3] + x[0] * par[4]);
1871 return TMath::Abs(y1 - y2);
1883 double y1 = par[3] * TMath::Landau(x[0], par[1], par[2]);
1884 double y2 = TMath::Exp(par[4] + x[0] * par[5]);
1885 if (x[0] > par[0]) y1 = 0.;
1886 if (x[0] < par[0]) y2 = 0.;
1893 double y1 = par[2] * TMath::Landau(x[0], par[0], par[1]);
1894 double y2 = par[5] * TMath::Landau(x[0], par[3], par[4]);
1895 return TMath::Abs(y1 - y2);
1908 double y1 = par[3] * TMath::Landau(x[0], par[1], par[2]);
1909 double y2 = TMath::Exp(par[4] + x[0] * par[5]);
1910 if (x[0] <= par[6] || x[0] > par[0]) y1 = 0.;
1911 if (x[0] < par[0]) y2 = 0.;
1922 double y = par[3] * TMath::Landau(x[0], par[1], par[2]);
1923 if (x[0] <= par[0]) y = 0.;
1933 const std::vector<double>& yData,
1939 size_t size = xData.size();
1940 if (x >= xData[size - 2]) {
1944 while (x > xData[i + 1])
1948 double xL = xData[i];
1949 double xR = xData[i + 1];
1950 double yL = yData[i];
1951 double yR = yData[i + 1];
1953 if (x < xL)
return yL;
1954 if (x > xR)
return yL;
1956 const double dydx = (yR - yL) / (xR - xL);
1957 return yL + dydx * (x - xL);
1962 const std::vector<double>& xData,
1963 const std::vector<double>& yData1,
1964 const std::vector<double>& yData2,
1965 const std::vector<double>& yData3,
1967 bool extrapolate)
const 1969 size_t size = xData.size();
1971 if (x >= xData[size - 2]) {
1975 while (x > xData[i + 1])
1978 double xL = xData[i];
1979 double xR = xData[i + 1];
1980 double yL1 = yData1[i];
1981 double yR1 = yData1[i + 1];
1982 double yL2 = yData2[i];
1983 double yR2 = yData2[i + 1];
1984 double yL3 = yData3[i];
1985 double yR3 = yData3[i + 1];
2001 const double m = (x - xL) / (xR - xL);
2002 inter[0] = m * (yR1 - yL1) + yL1;
2003 inter[1] = m * (yR2 - yL2) + yL2;
2004 inter[2] = m * (yR3 - yL3) + yL3;
2015 if (b <= 0. || d < 0. || h <= 0.)
return 0.;
2016 const double leg2 = (b +
d) * (b + d);
2017 const double aa = std::sqrt(h * h / (h * h + leg2));
2019 double bb = 2. * std::sqrt(b * d / (h * h + leg2));
2020 double cc = 4. * b * d /
leg2;
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();
2051 catch (std::domain_error&
e) {
2054 <<
"Elliptic Integral in Disk_SolidAngle() given parameters outside domain." 2055 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
2056 <<
"\nRelax condition and carry on.";
2061 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters outside domain.\n" 2062 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
2077 double aa = a / (2. *
d);
2078 double bb = b / (2. *
d);
2079 double aux = (1. + aa * aa + bb * bb) / ((1. + aa * aa) * (1. + bb * bb));
2096 double A = v[1] - o.
h * .5;
2097 double B = v[2] - o.
w * .5;
2105 if ((v[1] <= o.
h * .5) && (v[2] <= o.
w * .5)) {
2106 double A = -v[1] + o.
h * .5;
2107 double B = -v[2] + o.
w * .5;
2116 double A = v[1] - o.
h * .5;
2117 double B = -v[2] + o.
w * .5;
2126 double A = -v[1] + o.
h * .5;
2127 double B = v[2] - o.
w * .5;
2150 double par0[9] = {0., 0., 0., 0., 0., 0.597542, 1.00872, 1.46993, 2.04221};
2151 double par1[9] = {0, 0, 0.19569, 0.300449, 0.555598, 0.854939, 1.39166, 2.19141, 2.57732};
2152 const double delta_theta = 10.;
2153 int j =
int(theta/delta_theta);
2157 const double d_break = 5*
b;
2159 if(distance >= d_break) {
2160 double R_apparent_far = b - par1[j];
2161 return (2*
CLHEP::pi * (1 - std::sqrt(1 -
std::pow(R_apparent_far/distance,2))));
2165 double R_apparent_close = b - par0[j];
2166 return (2*
CLHEP::pi * (1 - std::sqrt(1 -
std::pow(R_apparent_close/distance,2))));
2171 std::vector<geo::BoxBoundedGeo>
2174 std::vector<geo::BoxBoundedGeo> activeVolumes;
2185 activeVolumes.push_back(
std::move(box));
2189 return activeVolumes;
2197 double negate = double(x < 0);
2199 x -= double(x > 1.0) * (x - 1.0);
2200 double ret = -0.0187293;
2202 ret = ret + 0.0742610;
2204 ret = ret - 0.2121144;
2206 ret = ret + 1.5707288;
2207 ret = ret * std::sqrt(1.0 - x);
2208 ret = ret - 2. * negate * ret;
2209 return negate * 3.14159265358979 + ret;
static constexpr double cm
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
Index OpChannel(Index detNum, Index channel)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
Utilities to extend the interface of geometry vectors.
std::vector< std::vector< std::vector< double > > > fvispars_dome
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
bool isScintInActiveVolume(geo::Point_t const &ScintPoint)
static constexpr double g
std::vector< geo::Point_t > fOpDetCenter
G4double bi_exp(const G4double t, const G4double tau1, const G4double tau2) const
double VisibleEnergyDeposit() const
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
Point GetCathodeCenter() 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
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)
void GetCenter(double *xyz, double localz=0.0) const
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
static constexpr double MeV
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)
art framework interface to geometry description
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
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)
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.
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
static constexpr double eV
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()
bool FillSimEnergyDeposits() const
void AddOpDetBacktrackerRecord(sim::OpDetBacktrackerRecord soc, bool Reflected=false)
Test of util::counter and support utilities.
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
static int max(int a, int b)
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
Specializations of geo_vectors_utils.h for ROOT old vector types.
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
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Encapsulate the geometry of an optical detector.
IteratorBox< cryostat_iterator,&GeometryCore::begin_cryostat,&GeometryCore::end_cryostat > IterateCryostats() const
Enables ranged-for loops on all cryostats of the 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
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.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
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
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 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, std::string const &vol="EMPTY")
void ExtendToInclude(Coord_t x, Coord_t y, Coord_t z)
Extends the current box to also include the specified point.
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
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
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())
TGeoShape const * Shape() const
Returns the geometry object as TGeoShape.
def parent(G, child, parent_type)
G4double single_exp(const G4double t, const G4double tau2) const
cet::coded_exception< error, detail::translate > exception
bool UseLitePhotons() const
QTextStream & endl(QTextStream &s)
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.