9 #include "GaudiKernel/RndmGenerators.h"
10 #include "GaudiKernel/DataSvc.h"
11 #include "GaudiKernel/SmartDataPtr.h"
35 #include "CLHEP/Units/SystemOfUnits.h"
36 #include "CLHEP/Matrix/Vector.h"
37 #include "CLHEP/Random/RandFlat.h"
38 #include "CLHEP/Vector/LorentzVector.h"
41 #include "GaudiKernel/ITHistSvc.h"
53 constexpr
double s_alpha = 1./137.;
54 constexpr
double s_oneOverThree = 1./3.;
62 m_particleBroker(
"ISF_ParticleParticleBroker",
n),
63 m_truthRecordSvc(
"ISF_TruthRecordSvc",
n),
65 m_referenceMaterial(true),
67 m_childEnergyScaleFactor(1.),
68 m_conversionProbScaleFactor(0.98),
69 m_rndGenSvc(
"AtDSFMTGenSvc",
n),
70 m_randomEngine(nullptr),
71 m_randomEngineName(
"FatrasRnd"),
72 m_recordedConversions(0),
73 m_droppedConversions(0),
74 m_validationMode(false),
75 m_validationTreeName(
"FatrasPhotonConversions"),
76 m_validationTreeDescription(
"Validation output from the PhotonConversionTool"),
77 m_validationTreeFolder(
"/val/FatrasPhotonConversions"),
78 m_validationTree(nullptr),
80 m_conversionPointX(0.),
81 m_conversionPointY(0.),
82 m_conversionPointR(0.),
83 m_conversionPointZ(0.),
84 m_conversionPhotonEnergy(0.),
85 m_conversionChildEnergy(0.),
86 m_conversionChildAngle(0.)
89 declareProperty(
"ParticleBroker" ,
m_particleBroker ,
"ISF ParticleBroker Svc" );
90 declareProperty(
"TruthRecordSvc" ,
m_truthRecordSvc ,
"ISF Particle Truth Svc" );
92 declareProperty(
"PhysicsProcessCode" ,
m_processCode ,
"MCTruth Physics Process Code");
99 declareProperty(
"RandomNumberService" ,
m_rndGenSvc ,
"Random number generator");
100 declareProperty(
"RandomStreamName" ,
m_randomEngineName ,
"Name of the random number stream");
117 if (m_particleBroker.retrieve().isFailure()){
118 ATH_MSG_FATAL(
"Could not retrieve ISF Particle Broker: " << m_particleBroker );
119 return StatusCode::FAILURE;
121 if (m_truthRecordSvc.retrieve().isFailure()){
122 ATH_MSG_FATAL(
"Could not retrieve ISF Truth Record Service: " << m_truthRecordSvc );
123 return StatusCode::FAILURE;
127 if ( m_rndGenSvc.retrieve().isFailure() ){
129 return StatusCode::FAILURE;
132 m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
133 if (!m_randomEngine) {
134 ATH_MSG_FATAL(
"Could not get random engine '" << m_randomEngineName <<
"'" );
135 return StatusCode::FAILURE;
139 ATH_CHECK( m_validationTool.retrieve( DisableTool{ m_validationTool.empty() || !m_validationMode } ) );
140 if (m_validationMode){
144 m_validationTree =
new TTree(m_validationTreeName.c_str(), m_validationTreeDescription.c_str());
147 m_validationTree->Branch(
"ConversionPositionX" , &m_conversionPointX,
"convX/F");
148 m_validationTree->Branch(
"ConversionPositionY" , &m_conversionPointY,
"convY/F");
149 m_validationTree->Branch(
"ConversionPositionR" , &m_conversionPointR,
"convR/F");
150 m_validationTree->Branch(
"ConversionPositionZ" , &m_conversionPointZ,
"convZ/F");
151 m_validationTree->Branch(
"ConversionPhotonEnergy" , &m_conversionPhotonEnergy,
"convPhotonE/F");
152 m_validationTree->Branch(
"ConversionChildEnergy" , &m_conversionChildEnergy,
"convChildE/F");
153 m_validationTree->Branch(
"ConversionChildAngle " , &m_conversionChildAngle,
"convChildA/F");
156 SmartIF<ITHistSvc> tHistSvc{Gaudi::svcLocator()->service(
"THistSvc")};
158 ATH_MSG_ERROR(
"initialize() Could not find Hist Service -> Switching ValidationMode Off !" );
159 delete m_validationTree; m_validationTree =
nullptr;
161 if ((tHistSvc->regTree(m_validationTreeFolder, m_validationTree)).isFailure()) {
162 ATH_MSG_ERROR(
"initialize() Could not register the validation Tree -> Switching ValidationMode Off !" );
163 delete m_validationTree; m_validationTree =
nullptr;
169 return StatusCode::SUCCESS;
176 ATH_MSG_INFO(
" ---------- Statistics output -------------------------- " );
177 ATH_MSG_INFO(
" Minimum energy cut of conversions into e+e- : " << m_minChildEnergy <<
" [MeV] " );
178 ATH_MSG_INFO(
" Conversions into e+e- (above cut, recorded) : " << m_recordedConversions );
179 ATH_MSG_INFO(
" Conversions into e+e- (below cut, dropped) : " << m_droppedConversions );
182 return StatusCode::SUCCESS;
189 double childEnergy,
double photonEnergy,
203 CLHEP::HepLorentzVector vtmp;
204 CLHEP::Hep3Vector photonDirectionHep( photonDirection.x(), photonDirection.y(), photonDirection.z() );
205 CLHEP::Hep3Vector childDirectionHep( childDirection.x(), childDirection.y(), childDirection.z() );
206 vtmp = CLHEP::HepLorentzVector(photonEnergy*photonDirectionHep, photonEnergy)
207 - CLHEP::HepLorentzVector(
p1*childDirectionHep, childEnergy);
209 double p2 = vtmp.vect().mag();
213 double charge1, charge2;
214 charge1 = charge2 = 0.;
215 if (CLHEP::RandFlat::shoot(m_randomEngine)>0.5) {
226 int pdg1 = s_pdgToHypo.convert(childType, charge1,
false);
227 int pdg2 = s_pdgToHypo.convert(childType, charge2,
false);
231 if (
p1 > m_minChildEnergy ) nchild++;
232 if (
p2 > m_minChildEnergy ) nchild++;
239 if (
p1 > m_minChildEnergy ) {
251 if (m_validationMode) {
262 if (
p2 > m_minChildEnergy ) {
275 if (m_validationMode) {
291 m_truthRecordSvc->registerTruthIncident( truth);
298 for (
auto *childParticle :
children) {
300 if (!childParticle->getTruthBinding()) {
301 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
303 m_particleBroker->push(childParticle,
parent);
308 if (m_validationMode && m_validationTool.isEnabled()) {
319 double childEnergy,
double photonEnergy,
328 CLHEP::HepLorentzVector vtmp;
329 CLHEP::Hep3Vector photonDirectionHep( photonDirection.x(), photonDirection.y(), photonDirection.z() );
330 CLHEP::Hep3Vector childDirectionHep( childDirection.x(), childDirection.y(), childDirection.z() );
331 vtmp = CLHEP::HepLorentzVector(photonEnergy*photonDirectionHep, photonEnergy)
332 - CLHEP::HepLorentzVector(
p1*childDirectionHep, childEnergy);
334 double p2 = vtmp.vect().mag();
338 double charge1, charge2;
339 charge1 = charge2 = 0.;
340 if (CLHEP::RandFlat::shoot(m_randomEngine)>0.5) {
350 int pdg1 = s_pdgToHypo.convert(childType, charge1,
false);
351 int pdg2 = s_pdgToHypo.convert(childType, charge2,
false);
387 m_truthRecordSvc->registerTruthIncident( truth);
393 for (
auto *childParticle :
children) {
394 if (!childParticle->getTruthBinding()) {
395 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
403 double pathCorrection,
421 double p0 = -7.01612e-03;
422 double p1 = 7.69040e-02;
423 double p2 = -6.07682e-01;
427 double attenuation =
exp( -7.777
e-01*pathCorrection*mprop.
thicknessInX0()*(1.-xi) );
429 ATH_MSG_VERBOSE(
"[ conv ] Propability of conversion = " << (1.-attenuation) * 100. <<
" %." );
444 return m_conversionProbScaleFactor*CLHEP::RandFlat::shoot(m_randomEngine) > attenuation;
450 double gammaMom)
const {
456 double oneOverZpow = 1./
pow(Z,s_oneOverThree);
457 double alphaZsquare = (s_alpha*s_alpha*Z*Z);
459 double fZ = alphaZsquare*(1./(1.+alphaZsquare)+0.20206-0.0369*alphaZsquare+0.0083*alphaZsquare*alphaZsquare);
460 double FZ = (8./3)*
log(Z)+8.*fZ;
462 double deltaMax =
exp((42.24-FZ)*.1195)-0.952;
464 double deltaMin = 4.*
epsilon0*136.*oneOverZpow;
466 double epsilon1 = 0.5-0.5*sqrt(1.-deltaMin/deltaMax);
469 double Phi1 = phi1(deltaMin);
470 double Phi2 = phi2(deltaMin);
472 double F10 = 3.*Phi1 - Phi2 - FZ;
473 double F20 = 1.5*Phi1 + 0.5*Phi2 - FZ;
475 double N1 = (0.25-epsilonMin+epsilonMin*epsilonMin)*F10;
478 if ( CLHEP::RandFlat::shoot(m_randomEngine) <
N1/(
N1+
N2) ) {
481 double epsilon = 0.5 - (0.5 - epsilonMin)*
pow(CLHEP::RandFlat::shoot(m_randomEngine),s_oneOverThree);
483 double delta = 136.*
epsilon0*oneOverZpow/(epsilon-epsilon*epsilon);
484 double F1 = 3.*phi1(delta)-phi2(delta)-FZ;
486 if (F1/F10 > CLHEP::RandFlat::shoot(m_randomEngine))
return m_childEnergyScaleFactor*epsilon;
491 double epsilon = epsilonMin + (0.5-epsilonMin)*CLHEP::RandFlat::shoot(m_randomEngine);
493 double delta = 136.*
epsilon0*oneOverZpow/(epsilon-epsilon*epsilon);
494 double F2 = 1.5*phi1(delta)-0.5*phi2(delta)-FZ;
496 if (F2/F20 > CLHEP::RandFlat::shoot(m_randomEngine))
return m_childEnergyScaleFactor*epsilon;
511 double oneOverZpow = 1./
pow(Z,s_oneOverThree);
512 double alphaZsquare = (s_alpha*s_alpha*Z*Z);
514 double fZ = alphaZsquare*(1./(1.+alphaZsquare)+0.20206-0.0369*alphaZsquare+0.0083*alphaZsquare*alphaZsquare);
515 double FZ = (8./3)*
log(Z)+8.*fZ;
517 double deltaMax =
exp((42.24-FZ)*.1195)-0.952;
519 double deltaMin = 4.*
epsilon0*136.*oneOverZpow;
521 double epsilon1 = 0.5-0.5*sqrt(1.-deltaMin/deltaMax);
524 double Phi1 = phi1(deltaMin);
525 double Phi2 = phi2(deltaMin);
527 double F10 = 3.*Phi1 - Phi2 - FZ;
528 double F20 = 1.5*Phi1 + 0.5*Phi2 - FZ;
530 double N1 = (0.25-epsilonMin+epsilonMin*epsilonMin)*F10;
533 if ( CLHEP::RandFlat::shoot(m_randomEngine) <
N1/(
N1+
N2)) {
536 double epsilon = 0.5 - (0.5 - epsilonMin)*
pow(CLHEP::RandFlat::shoot(m_randomEngine),s_oneOverThree);
538 double delta = 136.*
epsilon0*oneOverZpow/(epsilon-epsilon*epsilon);
539 double F1 = 3.*phi1(delta)-phi2(delta)-FZ;
541 if (F1/F10 > CLHEP::RandFlat::shoot(m_randomEngine))
return m_childEnergyScaleFactor*epsilon;
546 double epsilon = epsilonMin + (0.5-epsilonMin)*CLHEP::RandFlat::shoot(m_randomEngine);
548 double delta = 136.*
epsilon0*oneOverZpow/(epsilon-epsilon*epsilon);
549 double F2 = 1.5*phi1(delta)-0.5*phi2(delta)-FZ;
551 if (F2/F20 > CLHEP::RandFlat::shoot(m_randomEngine))
return m_childEnergyScaleFactor*epsilon;
564 double psi = 2.*
M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
572 double r1 = CLHEP::RandFlat::shoot(m_randomEngine);
573 double r2 = CLHEP::RandFlat::shoot(m_randomEngine);
574 double r3 = CLHEP::RandFlat::shoot(m_randomEngine);
576 double u = -
log(r2*r3)/
a;
578 theta *= (r1 < 0.25 ) ?
u :
u*s_oneOverThree;
580 ATH_MSG_VERBOSE(
"[ conv ] Simulated angle to photon = " << theta <<
"." );
583 CLHEP::Hep3Vector gammaMomHep( gammaMom.x(), gammaMom.y(), gammaMom.z() );
584 CLHEP::Hep3Vector newDirectionHep(gammaMomHep.unit());
585 double x = -newDirectionHep.y();
586 double y = newDirectionHep.x();
589 if (newDirectionHep.z()*newDirectionHep.z() > 0.999999)
592 CLHEP::Hep3Vector deflectorHep(
x,
y,
z);
594 newDirectionHep.rotate(theta, deflectorHep);
596 newDirectionHep.rotate(psi,gammaMomHep);
599 if (m_validationMode){
601 m_conversionChildEnergy =
float(childE);
602 m_conversionChildAngle =
float(theta);
606 Amg::Vector3D newDirection( newDirectionHep.x(), newDirectionHep.y(), newDirectionHep.z() );
612 const Trk::ExtendedMaterialProperties* )
const {
618 double efrac = childEnergyFraction(
p);
619 double childEnergy =
p*efrac;
622 ++m_recordedConversions;
627 ATH_MSG_VERBOSE(
"[ conv ] Child energy simulated as : " << childEnergy <<
" MeV" );
636 if (m_validationTree)
637 m_validationTree->Fill();
645 const Trk::ExtendedMaterialProperties* )
const {
650 double efrac = childEnergyFraction(
p);
651 double childEnergy =
p*efrac;
654 ++m_recordedConversions;
659 ATH_MSG_VERBOSE(
"[ conv ] Child energy simulated as : " << childEnergy <<
" MeV" );
661 if (m_validationTree)
662 m_validationTree->Fill();