9 #include "GaudiKernel/IRndmGenSvc.h"
10 #include "GaudiKernel/RndmGenerators.h"
22 #include "CLHEP/Units/SystemOfUnits.h"
23 #include "CLHEP/Matrix/Vector.h"
24 #include "CLHEP/Random/RandFlat.h"
25 #include "CLHEP/Random/RandGauss.h"
26 #include "CLHEP/Geometry/Transform3D.h"
29 #include "GaudiKernel/ITHistSvc.h"
42 m_minimumHadOutEnergy(200.*
CLHEP::
MeV),
45 m_hadIntFromX0(false),
46 m_hadIntProbScale(1.0),
47 m_minimumHadInitialEnergy(1000.*
CLHEP::
MeV),
48 m_particleBroker(
"ISF_ParticleBroker",
n),
49 m_truthRecordSvc(
"ISF_TruthRecordSvc",
n),
50 m_rndGenSvc(
"AtDSFMTGenSvc",
n),
52 m_randomEngine(nullptr),
53 m_randomEngineName(
"FatrasRnd"),
54 m_validationMode(false),
56 m_hadIntValidation(false),
57 m_hadIntValidationTreeName(
"FatrasHadronicInteractions"),
58 m_hadIntValidationTreeDescription(
"Validation output from the HadIntProcessorParametric"),
59 m_hadIntValidationTreeFolder(
"/val/FatrasHadronicInteractions"),
60 m_hadIntValidationTree(nullptr),
66 m_hadIntMotherBarcode(0),
69 m_hadIntMotherPhi(0.),
70 m_hadIntMotherEta(0.),
81 declareProperty(
"ShortenHadIntChain" ,
m_cutChain);
86 declareProperty(
"RandomNumberService" ,
m_rndGenSvc ,
"Random number generator");
87 declareProperty(
"RandomStreamName" ,
m_randomEngineName ,
"Name of the random number stream");
89 declareProperty(
"PhysicsProcessCode" ,
m_processCode ,
"MCTruth Physics Process Code" );
91 declareProperty(
"ParticleBroker" ,
m_particleBroker ,
"ISF ParticleBroker Svc" );
92 declareProperty(
"TruthRecordSvc" ,
m_truthRecordSvc ,
"ISF Particle Truth Svc" );
107 if (m_rndGenSvc.retrieve().isFailure()){
109 return StatusCode::FAILURE;
114 m_randomEngine = m_rndGenSvc->GetEngine(m_randomEngineName);
115 if (!m_randomEngine) {
116 ATH_MSG_FATAL(
"Could not get random engine '" << m_randomEngineName <<
"'" );
117 return StatusCode::FAILURE;
121 if (m_particleBroker.retrieve().isFailure()){
123 return StatusCode::FAILURE;
125 if (m_truthRecordSvc.retrieve().isFailure()){
127 return StatusCode::FAILURE;
131 ATH_CHECK( m_validationTool.retrieve( DisableTool{ m_validationTool.empty() || !m_validationMode } ) );
133 if (m_hadIntValidation){
135 SmartIF<ITHistSvc> tHistSvc{Gaudi::svcLocator()->service(
"THistSvc")};
137 ATH_MSG_ERROR(
"initialize() Could not find Hist Service -> Switching ValidationMode Off !" );
139 ATH_MSG_VERBOSE(
"Booking hadronic interaction validation TTree ... " );
142 m_hadIntValidationTree =
new TTree(m_hadIntValidationTreeName.c_str(), m_hadIntValidationTreeDescription.c_str());
145 m_hadIntValidationTree->Branch(
"HadIntPointX" , &m_hadIntPointX,
"hintX/F");
146 m_hadIntValidationTree->Branch(
"HadIntPointY" , &m_hadIntPointY,
"hintY/F");
147 m_hadIntValidationTree->Branch(
"HadIntPointR" , &m_hadIntPointR,
"hintR/F");
148 m_hadIntValidationTree->Branch(
"HadIntPointZ" , &m_hadIntPointZ,
"hintZ/F");
149 m_hadIntValidationTree->Branch(
"HadIntMotherPdg" , &m_hadIntMotherPdg,
"hintMotherPdg/I");
150 m_hadIntValidationTree->Branch(
"HadIntMotherBarcode" , &m_hadIntMotherBarcode,
"hintMotherBarcode/I");
151 m_hadIntValidationTree->Branch(
"HadIntMotherP" , &m_hadIntMotherP,
"hintMotherP/F");
152 m_hadIntValidationTree->Branch(
"HadIntMotherPt" , &m_hadIntMotherPt,
"hintMotherPt/F");
153 m_hadIntValidationTree->Branch(
"HadIntMotherPhi" , &m_hadIntMotherPhi,
"hintMotherPhi/F");
154 m_hadIntValidationTree->Branch(
"HadIntMotherEta" , &m_hadIntMotherEta,
"hintMohterEta/F");
156 m_hadIntValidationTree->Branch(
"HadIntChildren" , &m_hadIntChildren,
"hintcs/I");
157 m_hadIntValidationTree->Branch(
"HadIntChildE " , &m_hadIntChildE,
"hintce/F");
158 m_hadIntValidationTree->Branch(
"HadIntChildPdg" , m_hadIntChildPdg,
"hintChildPdg[hintcs]/I");
159 m_hadIntValidationTree->Branch(
"HadIntChildP" , m_hadIntChildP,
"hintChildP[hintcs]/F");
160 m_hadIntValidationTree->Branch(
"HadIntChildPcms" , m_hadIntChildPcms,
"hintChildPcms[hintcs]/F");
161 m_hadIntValidationTree->Branch(
"HadIntChildTh" , m_hadIntChildTh,
"hintChildTh[hintcs]/F");
162 m_hadIntValidationTree->Branch(
"HadIntChildThc" , m_hadIntChildThc,
"hintChildThc[hintcs]/F");
163 m_hadIntValidationTree->Branch(
"HadIntChildPhi" , m_hadIntChildPhi,
"hintChildPhi[hintcs]/F");
164 m_hadIntValidationTree->Branch(
"HadIntChildEta" , m_hadIntChildEta,
"hintChildEta[hintcs]/F");
165 m_hadIntValidationTree->Branch(
"HadIntChildDeltaPhi", m_hadIntChildDeltaPhi,
"hintChildPhi[hintcs]/F");
166 m_hadIntValidationTree->Branch(
"HadIntChildDeltaEta", m_hadIntChildDeltaEta,
"hintChildEta[hintcs]/F");
169 if ((tHistSvc->regTree(m_hadIntValidationTreeFolder, m_hadIntValidationTree)).isFailure()) {
170 ATH_MSG_ERROR(
"initialize() Could not register the validation Tree -> Switching ValidationMode Off !" );
171 delete m_hadIntValidationTree; m_hadIntValidationTree =
nullptr;
173 ATH_MSG_INFO(
"TTree for Hadronic Interactions validation booked." );
177 return StatusCode::SUCCESS;
184 return StatusCode::SUCCESS;
189 double p,
double ,
double charge,
197 if (extMprop && !m_hadIntFromX0) {
205 ATH_MSG_VERBOSE(
" [ had ] Nuclear Interaction length not available, using appox. from X0" );
212 << (1. -
prob) * 100. * m_hadIntProbScale <<
" %." );
217 if (CLHEP::RandFlat::shoot(m_randomEngine) < (1. -
prob) * m_hadIntProbScale )
return recordHadState(0.,
p,
230 double al =
mat->l0();
241 al *= 1./(1.+
exp(-0.5*(
p-270.)*(
p-270.)/60./60.));
260 double E = sqrt(
p*
p +
m*
m);
263 double multiplicity_max = 0.25 *
E/1000. + 18.;
266 double randx , randy,
arg = 0.;
280 randx = 30. * CLHEP::RandFlat::shoot(m_randomEngine);
281 randy = 1. * CLHEP::RandFlat::shoot(m_randomEngine);
283 if (randy < arg && randx>3 && randx<multiplicity_max)
break;
286 randx *= (1.2-0.4*
exp(-0.001*
p));
288 int Npart = (
int)randx;
292 ATH_MSG_VERBOSE(
"[ had ] Number of particles smaller than 3, parameterisation not valid."
293 <<
" Doing Nothing");
298 <<
" with " << Npart <<
" outgoing particles " );
303 ATH_MSG_DEBUG(
"[ had ] create hadronic shower for particle with PDG ID "
304 <<
parent->pdgCode() <<
" and barcode "
311 if (m_hadIntValidationTree){
312 m_hadIntPointX =
vertex.x();
313 m_hadIntPointY =
vertex.y();
314 m_hadIntPointZ =
vertex.z();
315 m_hadIntPointR =
vertex.perp();
316 m_hadIntMotherPdg =
parent->pdgCode();
319 m_hadIntMotherPt =
p*particleDir.perp();
320 m_hadIntMotherPhi = particleDir.phi();
321 m_hadIntMotherEta = particleDir.eta();
323 m_hadIntChildren = 0;
327 <<
E <<
" | " <<
m <<
" | " <<
p <<
" | " );
330 if (m_hadIntValidationTree) m_hadIntValidationTree->Fill();
331 ATH_MSG_VERBOSE(
"[ had ] interaction initiated by a secondary particle, no children saved " );
339 double chargedist = 0.;
340 std::vector<double>
charge(Npart);
341 std::vector<Trk::ParticleHypothesis> childType(Npart);
342 std::vector<double> newm(Npart);
343 std::vector<int> pdgid(Npart);
371 for (
int i=0;
i<Npart;
i++) {
372 chargedist = CLHEP::RandFlat::shoot(m_randomEngine);
373 if (chargedist<pif) {
380 if ( chargedist<2*pif) {
387 if (chargedist<3*pif) {
394 if (chargedist<3*pif+nef) {
401 if (chargedist<3*pif+nef+prf) {
416 for (
int i=1;
i<Npart;
i++) {
418 childType[
i]=childType[0];
449 std::vector<double>
mom(Npart);
450 std::vector<double>
th(Npart);
451 std::vector<double> ph(Npart);
454 double eps = 2./Npart;
455 double rnd = CLHEP::RandFlat::shoot(m_randomEngine);
456 mom[0] = 0.5*
pow(eps,rnd);
457 th[0] = acos( 2*CLHEP::RandFlat::shoot(m_randomEngine)-1.);
458 ph[0] = 2*
M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
464 double ptot =
mom[0];
466 double theta = 0.;
double phi = 0.;
467 for (
int i=1;
i<Npart-2;
i++) {
470 mom[
i] = ( eps + CLHEP::RandFlat::shoot(m_randomEngine)*(1-eps))*(1-ptot);
471 if (ptemp.mag()<1-ptot) {
472 while ( fabs(ptemp.mag()-
mom[
i])>1-ptot-
mom[
i] ){
473 mom[
i] = ( eps + CLHEP::RandFlat::shoot(m_randomEngine)*(1-eps))*(1-ptot);
477 double p_rem=1-ptot-
mom[
i];
478 double cthmax = fmin(1.,(-ptemp.mag()*ptemp.mag()-
mom[
i]*
mom[
i]+p_rem*p_rem)/2/ptemp.mag()/
mom[
i]);
480 double rnd = CLHEP::RandFlat::shoot(m_randomEngine);
481 theta = acos( (cthmax+1.)*rnd-1.);
482 phi = 2*
M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
484 HepGeom::Vector3D<double> dnewHep = HepGeom::RotateZ3D(ptemp.phi())*HepGeom::RotateY3D(ptemp.theta())*
test;
488 ptemp +=
mom[
i]*dnew;
493 mom[Npart-2] =
pow(eps,CLHEP::RandFlat::shoot(m_randomEngine))*(1-ptot);
494 mom[Npart-1] = 1-ptot-
mom[Npart-2];
496 if (ptemp.mag()<1-ptot) {
497 while (
mom[Npart-1]+
mom[Npart-2]<ptemp.mag()) {
498 mom[Npart-2] =
pow(eps,CLHEP::RandFlat::shoot(m_randomEngine))*(1-ptot);
499 mom[Npart-1] = 1-ptot-
mom[Npart-2];
502 if (ptemp.mag()<fabs(
mom[Npart-1]-
mom[Npart-2]) ) {
503 double diff = ptemp.mag()*CLHEP::RandFlat::shoot(m_randomEngine);
508 double cth =(-ptemp.mag()*ptemp.mag()-
mom[Npart-2]*
mom[Npart-2]+
mom[Npart-1]*
mom[Npart-1])/2/ptemp.mag()/
mom[Npart-2];
509 if (fabs(cth)>1.) cth = (cth>0.) ? 1. : -1.;
512 phi = 2*
M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
514 HepGeom::Vector3D<double> dnewHep = HepGeom::RotateZ3D(ptemp.phi())*HepGeom::RotateY3D(ptemp.theta())*
test;
517 th[Npart-2]=dnew.theta();
518 ph[Npart-2]=dnew.phi();
519 ptemp +=
mom[Npart-2]*dnew;
521 th[Npart-1]=dlast.theta();
522 ph[Npart-1]=dlast.phi();
527 for (
int i=0;
i<Npart;
i++) etot += sqrt(
mom[
i]*
mom[
i]+newm[
i]*newm[
i]);
529 for (
int i=0;
i<Npart;
i++) summ += newm[
i];
533 float scale = sqrt(summ*summ+2*summ*
p+
m*
m)/etot;
535 for (
int i=0;
i<Npart;
i++) {
541 CLHEP::HepLorentzVector bv(
p*particleDir.unit().x(),
p*particleDir.unit().y(),
p*particleDir.unit().z(),sqrt(etot*etot+
p*
p));
542 std::vector<CLHEP::HepLorentzVector> childBoost(Npart);
550 for (
int i=0;
i<Npart;
i++) {
555 CLHEP::HepLorentzVector newp(childP.x(),childP.y(),childP.z(),sqrt(
mom[
i]*
mom[
i]+newm[
i]*newm[
i]));
556 CLHEP::HepLorentzVector childPB = newp.boost(bv.boostVector());
557 childBoost[
i]=childPB;
569 unsigned short numChildren = 0;
571 for (
int i=0;
i<Npart;
i++) {
572 if (pdgid[
i]<10000) {
576 eout += childBoost[
i].e();
580 m_hadIntChildPdg[m_hadIntChildren] = pdgid[
i];
581 m_hadIntChildP[m_hadIntChildren] = childP.mag();
582 m_hadIntChildPcms[m_hadIntChildren] =
mom[
i];
583 m_hadIntChildTh[m_hadIntChildren] = childP.unit().dot(particleDir);
584 m_hadIntChildThc[m_hadIntChildren] =chP.dot(particleDir);
585 m_hadIntChildPhi[m_hadIntChildren] = childP.phi();
586 m_hadIntChildEta[m_hadIntChildren] = childP.eta();
587 double deltaPhi = m_hadIntMotherPhi - m_hadIntChildPhi[m_hadIntChildren];
591 m_hadIntChildDeltaPhi[m_hadIntChildren] =
deltaPhi;
592 m_hadIntChildDeltaEta[m_hadIntChildren] = m_hadIntMotherEta - m_hadIntChildEta[m_hadIntChildren];
596 if (childP.mag()> m_minimumHadOutEnergy) {
614 if (m_validationMode) {
623 ++childrenIt; numChildren++;
636 m_truthRecordSvc->registerTruthIncident( truth);
642 if (m_validationMode && m_validationTool.isEnabled()) {
649 m_hadIntChildE = eout;
651 if (m_hadIntValidationTree) m_hadIntValidationTree->Fill();
653 ATH_MSG_VERBOSE(
"[ had ] it was kinematically possible to create " << gen_part <<
" shower particles " );
675 if (processSecondaries && !ispVec.empty() ) {
676 for (
auto *childParticle : ispVec) {
678 if (!childParticle->getTruthBinding()) {
679 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
681 m_particleBroker->push(childParticle,
parent);
715 if (!ispVec.empty() ) {
716 for (
auto *childParticle : ispVec) {
718 if (!childParticle->getTruthBinding()) {
719 ATH_MSG_ERROR(
"Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
721 m_particleBroker->push(childParticle,
parent);