ATLAS Offline Software
Loading...
Searching...
No Matches
HadIntProcessorParametric.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// class header
7
8// Gaudi Kernel
9#include "GaudiKernel/IRndmGenSvc.h"
10#include "GaudiKernel/RndmGenerators.h"
11// ISF
17// Fatras
19// AtlasHepMC
21// CLHEP
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"
27// Validation mode - TTree includes
28#include "TTree.h"
29#include "GaudiKernel/ITHistSvc.h"
30// STD
31#include <cmath>
32
36
37
38
39// constructor
40iFatras::HadIntProcessorParametric::HadIntProcessorParametric(const std::string& t, const std::string& n, const IInterface* p) :
41 base_class(t,n,p),
44 m_cutChain(false),
45 m_hadIntFromX0(false),
48 m_particleBroker("ISF_ParticleBroker", n),
49 m_truthRecordSvc("ISF_TruthRecordSvc", n),
50 m_rndGenSvc("AtDSFMTGenSvc", n),
51 m_processCode(121),
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"),
73{
74 // property setting
75 declareProperty("MinimumHadronicOutEnergy" , m_minimumHadOutEnergy);
76 declareProperty("HadronicChildMomParam" , m_childMomParam);
77 declareProperty("HadronicInteractionFromX0" , m_hadIntFromX0);
78 declareProperty("HadronicInteractionScaleFactor" , m_hadIntProbScale);
79 declareProperty("MinimumHadronicInitialEnergy" , m_minimumHadInitialEnergy);
80 // the steering --------------------------------------------------------------
81 declareProperty("ShortenHadIntChain" , m_cutChain);
82 declareProperty("ValidationMode" , m_validationMode);
83 declareProperty("PhysicsValidationTool" , m_validationTool);
84 declareProperty("HadronicInteractionValidation" , m_hadIntValidation);
85 // validation mode
86 declareProperty("RandomNumberService" , m_rndGenSvc , "Random number generator");
87 declareProperty("RandomStreamName" , m_randomEngineName , "Name of the random number stream");
88 // MC Truth Properties
89 declareProperty("PhysicsProcessCode" , m_processCode , "MCTruth Physics Process Code" );
90 // ISF Services and Tools
91 declareProperty("ParticleBroker" , m_particleBroker , "ISF ParticleBroker Svc" );
92 declareProperty("TruthRecordSvc" , m_truthRecordSvc , "ISF Particle Truth Svc" );
93}
94
95// destructor
97= default;
98
99// Athena standard methods
100// initialize
102{
103
104 ATH_MSG_DEBUG( "initialize()" );
105
106 // get the random generator serice
107 if (m_rndGenSvc.retrieve().isFailure()){
108 ATH_MSG_FATAL( "Could not retrieve " << m_rndGenSvc );
109 return StatusCode::FAILURE;
110 } else
111 ATH_MSG_VERBOSE( "Successfully retrieved " << m_rndGenSvc );
112
113 //Get own engine with own seeds:
115 if (!m_randomEngine) {
116 ATH_MSG_FATAL( "Could not get random engine '" << m_randomEngineName << "'" );
117 return StatusCode::FAILURE;
118 }
119
120 // ISF Services
121 if (m_particleBroker.retrieve().isFailure()){
122 ATH_MSG_FATAL( "Could not retrieve " << m_particleBroker );
123 return StatusCode::FAILURE;
124 }
125 if (m_truthRecordSvc.retrieve().isFailure()){
126 ATH_MSG_FATAL( "Could not retrieve " << m_truthRecordSvc );
127 return StatusCode::FAILURE;
128 }
129
130 // the validation setup -------------------------------- PART 3: Hadronic Interaction ---------------------
131 ATH_CHECK( m_validationTool.retrieve( DisableTool{ m_validationTool.empty() || !m_validationMode } ) );
132
134
135 SmartIF<ITHistSvc> tHistSvc{Gaudi::svcLocator()->service("THistSvc")};
136 if (!tHistSvc) {
137 ATH_MSG_ERROR( "initialize() Could not find Hist Service -> Switching ValidationMode Off !" );
138 }
139 ATH_MSG_VERBOSE( "Booking hadronic interaction validation TTree ... " );
140
141 // create the new Tree
143
144 // counter for boundary surfaces
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");
155
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");
167
168
169 if ((tHistSvc->regTree(m_hadIntValidationTreeFolder, m_hadIntValidationTree)).isFailure()) {
170 ATH_MSG_ERROR("initialize() Could not register the validation Tree -> Switching ValidationMode Off !" );
172 } else {
173 ATH_MSG_INFO( "TTree for Hadronic Interactions validation booked." );
174 }
175 } // ------------- end of validation mode -----------------------------------------------------------------
176 ATH_MSG_DEBUG( "finalize() successful" );
177 return StatusCode::SUCCESS;
178}
179
180// finalize
182{
183 ATH_MSG_DEBUG( "finalize() successful" );
184 return StatusCode::SUCCESS;
185}
186
187
189 double p, double /*E*/, double charge,
190 const Trk::MaterialProperties& mprop, double pathCorrection,
191 Trk::ParticleHypothesis particle) const
192{
193 const Trk::MaterialProperties* extMprop = dynamic_cast<const Trk::MaterialProperties*>(&mprop);
194 double prob = 0.;
195
196 // m_hadIntProbScale is used later, not here
197 if (extMprop && !m_hadIntFromX0) {
198
199 double al = absorptionLength(extMprop, p, charge, particle); // in mm
200
201 if (al>0.) prob = exp( (-1.)*pathCorrection*extMprop->thickness()/al );
202 else prob = exp( (-1.)*pathCorrection*extMprop->thicknessInL0());
203
204 } else {
205 ATH_MSG_VERBOSE( " [ had ] Nuclear Interaction length not available, using appox. from X0" );
206 // using approximation lambda = 0.37 * Z * X0 instead -- giving a warning message
207 prob = exp( (-1.)*pathCorrection*mprop.thicknessInX0() / ( 0.37 * mprop.averageZ()) );
208 }
209
210 if (msgLvl(MSG::VERBOSE))
211 ATH_MSG_VERBOSE( " [ had ] Probability of hadronic interaction = "
212 << (1. - prob) * 100. * m_hadIntProbScale << " %." );
213
214 // apply a global scalor of the probability
215 // (1. - prob) is generally O(0.01), so this is the right way to scale it
216 // TODO fix time info (if needed)
217 if (CLHEP::RandFlat::shoot(m_randomEngine) < (1. - prob) * m_hadIntProbScale ) return recordHadState(0.,p,
218 position,
219 momentum.unit(),
220 particle); // Registers TruthIncident internally
221
222 // no hadronic interactions were computed
223 return false;
224}
225
226
229 double p, double, Trk::ParticleHypothesis particle) {
230 double al = mat->l0();
231
232 /* // these parametrization comes from comparison with G4 sampler, but give too many interactions
233 // not understood yet
234 if ( particle == Trk::pion ) al = ( 0.53+0.2*exp(-p/1000.) ) * mat->l0();
235 else if ( particle == Trk::kaon ) al = ( 0.1+0.65*exp(-p/5000.) ) * mat->l0();
236 else if ( particle == Trk::proton ) al = 0.57 * mat->l0();
237 else al = mat->l0();
238 */
239
240 if ( particle == Trk::pion || particle == Trk::kaon || particle == Trk::pi0 || particle == Trk::k0) {
241 al *= 1./(1.+ exp(-0.5*(p-270.)*(p-270.)/60./60.));
242 }
243 if ( particle == Trk::proton || particle == Trk::neutron ) al *=0.7;
244 if ( particle == Trk::pion || particle == Trk::pi0) al *=0.9;
245
246 return al;
247}
248
249
251 const Amg::Vector3D& vertex,
252 const Amg::Vector3D& particleDir,
254 ) const
255{
256 ISF::ISFParticleVector chDef(0);
257
258 // sampling of hadronic interaction
259 double m = Trk::ParticleMasses::mass[particle];
260 double E = sqrt(p*p + m*m);
261
262 // get the maximum multiplicity
263 double multiplicity_max = 0.25 * E/1000. + 18.;
264
265 // multiplicity distribution
266 double randx , randy, arg = 0.;
267
268 double p1 = 0.;
269 double p2 = 0.;
270
271 if (E > 15000.) {
272 p1 = 8.69;
273 p2 = 2.34;
274 } else {
275 p1 = 6.77;
276 p2 = 2.02;
277 }
278
279 for (;;) {
280 randx = 30. * CLHEP::RandFlat::shoot(m_randomEngine);
281 randy = 1. * CLHEP::RandFlat::shoot(m_randomEngine);
282 arg = exp(-0.5*( (randx-p1)/p2 + exp(-(randx-p1)/p2) ) );
283 if (randy < arg && randx>3 && randx<multiplicity_max) break;
284 }
285
286 randx *= (1.2-0.4*exp(-0.001*p)); // trying to adjust
287
288 int Npart = (int)randx;
289
290 // protection against Npart < 3
291 if (Npart < 3) {
292 ATH_MSG_VERBOSE( "[ had ] Number of particles smaller than 3, parameterisation not valid."
293 << " Doing Nothing");
294 return chDef;
295 }
296
297 ATH_MSG_VERBOSE( "[ had ] interaction of " << HepMC::barcode(parent)
298 << " with " << Npart << " outgoing particles " );
299
300 // record the interaction
301
302 // ------ now create the new hadrons ------
303 ATH_MSG_DEBUG( "[ had ] create hadronic shower for particle with PDG ID "
304 << parent->pdgCode() << " and barcode "
305 << HepMC::barcode(parent) );
306
307
308 // create the genParticles
309
310 // validation if needed
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();
317 m_hadIntMotherBarcode = HepMC::barcode(parent); // FIXME barcode-based
318 m_hadIntMotherP = p;
319 m_hadIntMotherPt = p*particleDir.perp();
320 m_hadIntMotherPhi = particleDir.phi();
321 m_hadIntMotherEta = particleDir.eta();
322 // reset the children
324 }
325
326 ATH_MSG_VERBOSE( "[ had ] incoming particle energy | mass | momentum "
327 << E << " | " << m << " | " << p << " | " );
328
329 if (m_cutChain && ( HepMC::generations(parent) > 0 || (HepMC::barcode(parent) ==HepMC::UNDEFINED_ID && HepMC::uniqueID(parent) == HepMC::UNDEFINED_ID) ) ) {
331 ATH_MSG_VERBOSE( "[ had ] interaction initiated by a secondary particle, no children saved " );
332 return chDef;
333 }
334
335 int gen_part = 0;
336
337 // new sampling: sample particle type and energy in the CMS frame of outgoing particles
338 // creation of shower particles
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);
344
345 // children type sampling : simplified
346 //double pif = 0.19;
347 //double nef = 0.20;
348 //double prf = 0.20;
349
350 // sample heavy particles (alpha) but don't save
351 double pif = 0.10;
352 double nef = 0.30;
353 double prf = 0.30;
354
355 if ( particle == Trk::pion || particle == Trk::kaon || particle == Trk::pi0 || particle == Trk::k0 ) {
356 pif = 0.15;
357 nef = 0.25;
358 prf = 0.25;
359 }
360 if ( particle == Trk::proton ) {
361 pif = 0.06;
362 nef = 0.25;
363 prf = 0.35;
364 }
365 if ( particle == Trk::neutron ) {
366 pif = 0.03;
367 nef = 0.35;
368 prf = 0.17;
369 }
370
371 for (int i=0; i<Npart; i++) {
372 chargedist = CLHEP::RandFlat::shoot(m_randomEngine);
373 if (chargedist<pif) {
374 charge[i]=0.;
375 childType[i]=Trk::pi0;
376 newm[i]=Trk::ParticleMasses::mass[Trk::pi0]; // MeV
377 pdgid[i]=111;
378 continue;
379 }
380 if ( chargedist<2*pif) {
381 charge[i]=1.;
382 childType[i]=Trk::pion;
383 newm[i]=Trk::ParticleMasses::mass[Trk::pion]; // MeV
384 pdgid[i]=211;
385 continue;
386 }
387 if (chargedist<3*pif) {
388 charge[i]=-1.;
389 childType[i]=Trk::pion;
390 newm[i]=Trk::ParticleMasses::mass[Trk::pion]; // MeV
391 pdgid[i]=-211;
392 continue;
393 }
394 if (chargedist<3*pif+nef) {
395 charge[i]=0.;
396 childType[i]=Trk::neutron;
398 pdgid[i]=2112; // neutron
399 continue;
400 }
401 if (chargedist<3*pif+nef+prf) {
402 charge[i]=1.;
403 childType[i]=Trk::proton;
405 pdgid[i]=2212;
406 continue;
407 }
408 charge[i]=2.;
409 childType[i]=Trk::proton;
410 newm[i]=4000.;
411 pdgid[i]=20000;
412 }
413
414 // move the incoming particle type forward
415 if ( childType[0] != particle ) {
416 for (int i=1; i<Npart; i++) {
417 if (childType[i]==particle) {
418 childType[i]=childType[0];
419 childType[0]=particle;
420 double cho = charge[i];
421 charge[i]=charge[0];
422 charge[0]=parent ? parent->charge() : cho;
423 newm[i]=Trk::ParticleMasses::mass[childType[i]]; // MeV
424 newm[0]=Trk::ParticleMasses::mass[childType[0]]; // MeV
425 break;
426 }
427 }
428 }
429
430 /*
431 // sample momentum of daughters in CMS frame of outgoing particles [ exp(-par/p) ]
432 std::vector<double> mom;
433 mom.clear();mom.reserve(Npart);
434 double mom_n = 0.;
435 for (int _npart=0; _npart<Npart; _npart++) {
436 rand1 = CLHEP::RandFlat::shoot(m_randomEngine);
437 mom_n = -log(rand1)/m_childMomParam * p;
438 int ipos = _npart;
439 while ( ipos>0 && mom_n>mom[ipos-1]) ipos--;
440 mom.insert(mom.begin()+ipos,mom_n);
441 }
442
443 // check if configuration acceptable - if not, resample hardest mom
444 double momR = 0.;
445 for (int i=1; i<Npart; i++) momR += mom[i];
446 if (momR < mom[0]) mom[0] = mom[1]+rand1*(momR-mom[1]);
447 */
448
449 std::vector<double> mom(Npart);
450 std::vector<double> th(Npart);
451 std::vector<double> ph(Npart);
452
453 // sample first particle energy fraction and random momentum direction
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);
459
460 // toss particles around in a way which preserves the total momentum (0.,0.,0.) at this point
461 // TODO shoot first particle along the impact direction preferentially
462
463 Amg::Vector3D ptemp(mom[0]*sin(th[0])*cos(ph[0]),mom[0]*sin(th[0])*sin(ph[0]),mom[0]*cos(th[0]));
464 double ptot = mom[0];
465
466 double theta = 0.; double phi = 0.;
467 for (int i=1; i<Npart-2; i++) {
468 eps = 1./(Npart-i);
469 //mom[i] = pow(eps,CLHEP::RandFlat::shoot(m_randomEngine))*(1-ptot);
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);
474 }
475 }
476 // max p remaining
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]);
479 //if (cthmax<-1.) std::cout <<"problem in theta sampling:p_rem:ptot:pcurr:"<<p_rem<<","<<ptemp.mag()<<","<<mom[i]<< std::endl;
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);
483 HepGeom::Vector3D<double> test(sin(theta)*cos(phi),sin(theta)*sin(phi),cos(theta));
484 HepGeom::Vector3D<double> dnewHep = HepGeom::RotateZ3D(ptemp.phi())*HepGeom::RotateY3D(ptemp.theta())*test;
485 Amg::Vector3D dnew( dnewHep.x(), dnewHep.y(), dnewHep.z() );
486 th[i]=dnew.theta();
487 ph[i]=dnew.phi();
488 ptemp += mom[i]*dnew;
489 ptot += mom[i];
490 }
491
492 eps = 0.5;
493 mom[Npart-2] = pow(eps,CLHEP::RandFlat::shoot(m_randomEngine))*(1-ptot);
494 mom[Npart-1] = 1-ptot-mom[Npart-2];
495
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];
500 }
501 }
502 if (ptemp.mag()<fabs(mom[Npart-1]-mom[Npart-2]) ) {
503 double diff = ptemp.mag()*CLHEP::RandFlat::shoot(m_randomEngine);
504 double sum = mom[Npart-1]-mom[Npart-2];
505 mom[Npart-2]=0.5*(sum+diff);
506 mom[Npart-1]=0.5*(sum-diff);
507 }
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.;
510
511 theta = acos(cth);
512 phi = 2*M_PI*CLHEP::RandFlat::shoot(m_randomEngine);
513 HepGeom::Vector3D<double> test(sin(theta)*cos(phi),sin(theta)*sin(phi),cos(theta));
514 HepGeom::Vector3D<double> dnewHep = HepGeom::RotateZ3D(ptemp.phi())*HepGeom::RotateY3D(ptemp.theta())*test;
515 Amg::Vector3D dnew( dnewHep.x(), dnewHep.y(), dnewHep.z() );
516
517 th[Npart-2]=dnew.theta();
518 ph[Npart-2]=dnew.phi();
519 ptemp += mom[Npart-2]*dnew;
520 Amg::Vector3D dlast = -ptemp;
521 th[Npart-1]=dlast.theta();
522 ph[Npart-1]=dlast.phi();
523
524 // particle sampled, rotate, boost and save final state
525 //CLHEP::HepLorentzVector bv(p*particleDir.unit().x(),p*particleDir.unit().y(),p*particleDir.unit().z(),s_currentGenParticle->momentum().e()+mtot);
526 double etot = 0.;
527 for (int i=0;i<Npart; i++) etot += sqrt(mom[i]*mom[i]+newm[i]*newm[i]);
528 double summ = 0.;
529 for (int i=0;i<Npart; i++) summ += newm[i];
530
531 // std::cout <<"hadronic interaction: current energy, expected :"<< etot <<","<< sqrt(summ*summ+2*summ*p+m*m)<< std::endl;
532 // rescale (roughly) to the expected energy
533 float scale = sqrt(summ*summ+2*summ*p+m*m)/etot;
534 etot = 0.;
535 for (int i=0;i<Npart; i++) {
536 mom[i] *= scale;
537 etot += sqrt(mom[i]*mom[i]+newm[i]*newm[i]);
538 }
539
540
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);
543
544 //std::cout <<"boost vector:"<<p<<","<<bv.e()<<","<<bv.m()<<std::endl;
545 //std::cout <<"etot, mother E,m:"<<etot<<","<<E<<","<<m<<std::endl;
546
547 Amg::Vector3D in(0.,0.,0.);
548 Amg::Vector3D fin(0.,0.,0.);
549
550 for (int i=0; i<Npart; i++) {
551 Amg::Vector3D dirCms(sin(th[i])*cos(ph[i]),sin(th[i])*sin(ph[i]),cos(th[i]));
552 //Amg::Vector3D rotDirCms=HepGeom::RotateZ3D(particleDir.phi())*HepGeom::RotateY3D(particleDir.theta())*dirCms;
553 Amg::Vector3D childP = mom[i]*dirCms;
554 in += childP;
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;
558 fin += Amg::Vector3D(childPB.x(),childPB.y(),childPB.z());
559 }
560
561 double eout = 0.;
562
563 // child particle vector for TruthIncident
564 // Reserve space for as many paricles as created due to hadr. int.
565 // However, the number of child particles for TruthIncident might be
566 // smaller due to (momentum) cuts
567 ISF::ISFParticleVector children(Npart);
568 ISF::ISFParticleVector::iterator childrenIt = children.begin();
569 unsigned short numChildren = 0;
570
571 for (int i=0; i<Npart; i++) {
572 if (pdgid[i]<10000) {
573 Amg::Vector3D childP = Amg::Vector3D(childBoost[i].x(),childBoost[i].y(),childBoost[i].z());
574 Amg::Vector3D chP = Amg::Vector3D(sin(th[i])*cos(ph[i]),sin(th[i])*sin(ph[i]),cos(th[i]));
575
576 eout += childBoost[i].e();
577
578 // validation if needed
581 m_hadIntChildP[m_hadIntChildren] = childP.mag();
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();
588 // rescale the deltaPhi
589 deltaPhi -= deltaPhi > M_PI ? M_PI : 0.;
590 deltaPhi += deltaPhi < -M_PI ? M_PI : 0.;
594 }
595
596 if (childP.mag()> m_minimumHadOutEnergy) {
597 // get the new particle
598 double mass = Trk::ParticleMasses::mass[ childType[i] ];
599
600 // create the particle
601 const int status = 1 + HepMC::SIM_STATUS_THRESHOLD;
602 const int id = HepMC::UNDEFINED_ID;
603 ISF::ISFParticle *child = new ISF::ISFParticle ( vertex,
604 childP,
605 mass,
606 charge[i],
607 pdgid[i],
608 status,
609 time,
610 *parent,
611 id
612 );
613 // in the validation mode, add process info
614 if (m_validationMode) {
616 validInfo->setProcess(m_processCode);
617 if (parent->getUserInformation()) validInfo->setGeneration(parent->getUserInformation()->generation()+1);
618 else validInfo->setGeneration(1); // assume parent is a primary track
619 child->setUserInformation(validInfo);
620 }
621 // record child for TruthIncident
622 *childrenIt = child;
623 ++childrenIt; numChildren++;
624 }
625
626 gen_part++;
627 }
628 } // particle loop
629
630 children.resize(numChildren);
631 ISF::ISFTruthIncident truth( const_cast<ISF::ISFParticle&>(*parent),
632 children,
634 parent->nextGeoID(),
636 m_truthRecordSvc->registerTruthIncident( truth);
637 // At this point we need to update the properties of the
638 // ISFParticles produced in the interaction
640
641 // save info for validation
642 if (m_validationMode && m_validationTool.isEnabled()) {
643 Amg::Vector3D* nMom = nullptr;
644 m_validationTool->saveISFVertexInfo(m_processCode,vertex,*parent,p*particleDir,nMom,children);
645 delete nMom;
646 }
647
648
649 m_hadIntChildE = eout;
650
652
653 ATH_MSG_VERBOSE( "[ had ] it was kinematically possible to create " << gen_part << " shower particles " );
654
655 return children;
656
657}
658
660 const Trk::Material* /*ematprop*/,
661 Trk::ParticleHypothesis particle, bool processSecondaries) const {
662 // Called by McMaterialEffectsUpdator::interact
663 // get parent particle
665 // something is seriously wrong if there is no parent particle
666 assert(parent);
667
668 ISF::ISFParticleVector ispVec=getHadState(parent, time, momentum.mag(), position, momentum.unit(), particle); // Registers TruthIncident internally
669
670
671 // having no secondaries does not necessarily mean the interaction did not take place : TODO : add flag into ::getHadState
672 // if (!ispVec.size()) return false;
673
674 // push onto ParticleStack
675 if (processSecondaries && !ispVec.empty() ) {
676 for (auto *childParticle : ispVec) {
677 //Check that the new ISFParticles have a valid TruthBinding
678 if (!childParticle->getTruthBinding()) {
679 ATH_MSG_ERROR("Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
680 }
681 m_particleBroker->push(childParticle, parent);
682 }
683 }
684
685 return true;
686
687}
688
690 const Amg::Vector3D& position, const Amg::Vector3D& momentum,
691 const Trk::Material* /*emat*/,
692 Trk::ParticleHypothesis particle) const {
693 // called from McMaterialEffectsUpdator::interact and
694 // McMaterialEffectsUpdator::interactLay methods
695 return getHadState(parent, time, momentum.mag(), position, momentum.unit(), particle); // Registers TruthIncident internally
696
697}
698
701 const Amg::Vector3D& vertex,
702 const Amg::Vector3D& particleDir,
703 Trk::ParticleHypothesis particle ) const {
704 // get parent particle
706 // something is seriously wrong if there is no parent particle
707 assert(parent);
708
709 ISF::ISFParticleVector ispVec=getHadState(parent, time, p, vertex, particleDir, particle); // Registers TruthIncident internally
710
711 // having no secondaries does not necessarily mean the interaction did not take place : TODO : add flag into ::getHadState
712 // if (!ispVec.size()) return false;
713
714 // push onto ParticleStack
715 if (!ispVec.empty() ) {
716 for (auto *childParticle : ispVec) {
717 //Check that the new ISFParticles have a valid TruthBinding
718 if (!childParticle->getTruthBinding()) {
719 ATH_MSG_ERROR("Could not retrieve TruthBinding from child ISFParticle "<< *childParticle);
720 }
721 m_particleBroker->push(childParticle, parent);
722 }
723 }
724
725 return true;
726}
727
#define M_PI
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
#define MAXHADINTCHILDREN
static Double_t al
static TRandom * rnd
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631
#define y
#define x
#define z
constexpr int pow(int base, int exp) noexcept
The generic ISF particle definition,.
Definition ISFParticle.h:42
void setUserInformation(ParticleUserInformation *userInfo)
Interface class for all truth incidents handled by the ISF.
void updateChildParticleProperties()
Update the id and particleLink properties of the child particles (to be called after registerTruthInc...
static ParticleClipboard & getInstance()
get the singleton instance
const ISF::ISFParticle * getParticle() const
get the particle from the clipboard
Each ISFParticle carries a pointer to this class.
Material with information about thickness of material.
float thicknessInX0() const
Return the radiationlength fraction.
float thicknessInL0() const
Return the nuclear interaction length fraction.
float averageZ() const
Returns the average Z of the material.
float thickness() const
Return the thickness in mm.
A common object to be contained by.
Definition Material.h:117
float m_hadIntPointY
ntuple variable : hadronic interaction point y coordinate
ISF::ISFParticleVector getHadState(const ISF::ISFParticle *parent, double time, double p, const Amg::Vector3D &vertex, const Amg::Vector3D &particleDir, Trk::ParticleHypothesis particle) const
collect secondaries for layer material update
StatusCode finalize()
AlgTool finalize method.
float m_hadIntPointR
ntuple variable : hadronic interaction point r distance
int m_processCode
MCTruth process code for TruthIncidents created by this tool.
float m_hadIntPointX
ntuple variable : hadronic interaction point x coordinate
float m_hadIntChildEta[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child eta
double m_minimumHadOutEnergy
hadronic interaction setting
ServiceHandle< ISF::ITruthSvc > m_truthRecordSvc
bool hadronicInteraction(const Amg::Vector3D &position, const Amg::Vector3D &momentum, double p, double E, double charge, const Trk::MaterialProperties &mprop, double pathCorrection, Trk::ParticleHypothesis particle=Trk::pion) const
interface for processing of the nuclear interactions
static double absorptionLength(const Trk::MaterialProperties *mat, double p, double q, Trk::ParticleHypothesis particle=Trk::pion)
interface for calculation of absorption length
int m_hadIntChildPdg[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child Pdg
std::string m_hadIntValidationTreeFolder
stream/folder to for the TTree to be written out
int m_hadIntMotherBarcode
ntuple variable : hadronic interaction mother barcode
float m_hadIntPointZ
ntuple variable : hadronic interaction point z coordinate
TTree * m_hadIntValidationTree
Root Validation Tree.
ToolHandle< IPhysicsValidationTool > m_validationTool
ServiceHandle< IAtRndmGenSvc > m_rndGenSvc
Random Generator service.
float m_hadIntChildPcms[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child Energy
float m_hadIntMotherEta
ntuple variable : hadronic interaction photon eta
bool doHadronicInteraction(double time, const Amg::Vector3D &position, const Amg::Vector3D &momentum, const Trk::Material *emat, Trk::ParticleHypothesis particle, bool processSecondaries) const
int m_hadIntMotherPdg
ntuple variable : hadronic interaction mother Pdg
float m_hadIntMotherPhi
ntuple variable : hadronic interaction mother phi
float m_hadIntChildPhi[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child phi
std::string m_randomEngineName
Name of the random number stream.
float m_hadIntChildDeltaEta[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child delta eta
ServiceHandle< ISF::IParticleBroker > m_particleBroker
ISF services & Tools.
std::string m_hadIntValidationTreeDescription
validation tree description - second argument in TTree
float m_hadIntMotherP
ntuple variable : hadronic interaction mother momentum
int m_hadIntChildren
nutple variable : hadronic interaction children numbers
float m_hadIntMotherPt
ntuple variable : hadronic interaction mother momentum
ISF::ISFParticleVector doHadIntOnLayer(const ISF::ISFParticle *parent, double time, const Amg::Vector3D &position, const Amg::Vector3D &momentum, const Trk::Material *emat, Trk::ParticleHypothesis particle) const
virtual ~HadIntProcessorParametric()
Destructor.
CLHEP::HepRandomEngine * m_randomEngine
Random engine.
HadIntProcessorParametric(const std::string &, const std::string &, const IInterface *)
AlgTool constructor for HadIntProcessorParametric.
std::string m_hadIntValidationTreeName
validation tree name - to be acessed by this from root
StatusCode initialize()
AlgTool initailize method.
float m_hadIntChildDeltaPhi[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child delta phi
bool recordHadState(double time, double p, const Amg::Vector3D &vertex, const Amg::Vector3D &particleDir, Trk::ParticleHypothesis particle) const
interface for processing of the presampled nuclear interaction
float m_hadIntChildP[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child Energy
float m_hadIntChildTh[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child phi
float m_hadIntChildThc[MAXHADINTCHILDREN]
nutple variable : hadronic interaction child eta
float m_hadIntChildE
nutple variable : hadronic interaction children total energy
Eigen::Matrix< double, 3, 1 > Vector3D
int barcode(const T *p)
Definition Barcode.h:16
int uniqueID(const T &p)
constexpr int UNDEFINED_ID
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
int generations(const T &p)
Method to return how many interactions a particle has undergone during simulation (TODO migrate to be...
@ fKillsPrimary
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
constexpr double neutronMassInMeV
the mass of the neutron (in MeV)
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
ParticleHypothesis
Enumeration for Particle hypothesis respecting the interaction with material.