GENIEGenerator
Loading...
Searching...
No Matches
HNLDecayer.cxx
Go to the documentation of this file.
1//____________________________________________________________________________
2/*
3 Copyright (c) 2003-2025, The GENIE Collaboration
4 For the full text of the license visit http://copyright.genie-mc.org
5
6 Author: John Plows <komninos-john.plows \at physics.ox.ac.uk>
7 University of Oxford
8
9 Costas Andreopoulos <c.andreopoulos \at cern.ch>
10 University of Liverpool
11*/
12//____________________________________________________________________________
13
32
33using namespace genie;
34using namespace genie::hnl;
35
36//____________________________________________________________________________
38DecayRecordVisitorI("genie::hnl::Decayer")
39{
40
41}
42//____________________________________________________________________________
43Decayer::Decayer(string config) :
44DecayRecordVisitorI("genie::hnl::Decayer",config)
45{
46
47}
48//____________________________________________________________________________
50{
51
52}
53//____________________________________________________________________________
55{
56
57 Interaction * interaction = event->Summary();
58
59 fCurrInitStatePdg = interaction->InitState().ProbePdg();
61
62 LOG("HNL", pNOTICE)
63 << "Simulating HNL decay " << utils::hnl::AsString(fCurrDecayMode)
64 << " for an initial state with PDG code " << fCurrInitStatePdg;
65
66 this->ReadCreationInfo(event);
67 this->AddInitialState(event);
68 this->GenerateDecayProducts(event);
69 this->UpdateEventRecord(event);
70
71}
72//____________________________________________________________________________
74{
75 std::vector< double > * prodVtx = 0;
76
77 Interaction * interaction = event->Summary();
78 InitialState * init_state = interaction->InitStatePtr();
79
80 TLorentzVector p4;
81 if( event->Particle(0) ){
82 // p4 was already set using HNLFluxCreator. No action needed.
83 // Read event vertex == HNL production vertex. We will find the decay vertex later.
84 p4 = *( init_state->GetProbeP4() );
85
86 prodVtx = new std::vector< double >();
87 prodVtx->emplace_back( event->Vertex()->X() );
88 prodVtx->emplace_back( event->Vertex()->Y() );
89 prodVtx->emplace_back( event->Vertex()->Z() );
90 prodVtx->emplace_back( event->Vertex()->T() );
91 } else {
92 std::vector< double > * p3HNL = this->GenerateMomentum( event );
93
94 double px = p3HNL->at(0);
95 double py = p3HNL->at(1);
96 double pz = p3HNL->at(2);
97 double E = interaction->InitState().ProbeE(kRfLab);
98
99 p4 = TLorentzVector( px, py, pz, E );
100
101 if( !event->Vertex() || (event->Vertex()->Vect()).Mag() == 0.0 )
102 prodVtx = this->GenerateDecayPosition( event );
103 else{
104 prodVtx = new std::vector< double >();
105 prodVtx->emplace_back( event->Vertex()->X() );
106 prodVtx->emplace_back( event->Vertex()->Y() );
107 prodVtx->emplace_back( event->Vertex()->Z() );
108 prodVtx->emplace_back( event->Vertex()->T() );
109 }
110 }
111
112 TLorentzVector v4( prodVtx->at(0), prodVtx->at(1), prodVtx->at(2), prodVtx->at(3) );
113
114 init_state->SetProbeP4( p4 );
115
116 int hpdg = interaction->InitState().ProbePdg();
117 if( !event->Particle(0) )
118 event->AddParticle(hpdg, kIStInitialState, 0,-1,-1,-1, p4, v4);
119}
120//____________________________________________________________________________
122{
123 LOG("HNL", pINFO) << "Generating decay...";
124 fDecLepPdg = 0; fDecHadPdg = 0;
125
126 // do we have nubar?
128 int typeMod = ( fCurrInitStatePdg >= 0 ) ? 1 : -1;
130 fDecHadPdg = typeMod * kPdgPi0;
131 } else if( fCurrDecayMode != kHNLDcyNuNuNu ){
132 fDecHadPdg = typeMod * kPdgPiP;
133 }
134
135 if( event->Particle(0) && !fIsMajorana ){
136 typeMod = ( event->Particle(0)->Pdg() >= 0 ) ? 1 : -1;
137 } else if( event->Particle(0) && fIsMajorana ){
138 // equal probability to decay to 1 of 2 charge-conjugated states
140 double rnd = Rng->RndGen().Uniform(0.0, 1.0);
141 typeMod = ( rnd >= 0.5 ) ? 1.0 : -1.0;
142 }
143 PDGCodeList pdgv(true);
144 for( std::vector<int>::iterator it = pdgv0.begin(); it != pdgv0.end(); ++it ){
145 int pdgc = *it;
146 int newpdgc = ( pdgc == genie::kPdgPi0 ) ? pdgc : typeMod * pdgc; // pi-0 is its own antiparticle
147 pdgv.push_back( newpdgc );
148 }
149
150 assert ( pdgv.size() > 1);
151
152 // if user wants to include polarisation effects, start prep now
153 /*
154 double fPolDirMag = 0.0;
155 if( fPolDir.size() == 3 ){
156 fPolDirMag = std::sqrt( ( fPolDir.at(0) * fPolDir.at(0) ) +
157 ( fPolDir.at(1) * fPolDir.at(1) ) +
158 ( fPolDir.at(2) * fPolDir.at(2) ) );
159 }
160 */
161 bool doPol = fDoPol && (fPolDir.size() == 3);
162
163 std::ostringstream asts;
164 if( !doPol ) asts << "Performing a phase space decay...";
165 else asts << "Performing a polarised decay with polarisation vector:"
166 << " ( " << fPolDir.at(0) << ", " << fPolDir.at(1) << ", " << fPolDir.at(2) << " )";
167 LOG("HNL", pINFO) << asts.str();
168
169 // Get the decay product masses
170
171 vector<int>::const_iterator pdg_iter;
172 int i = 0;
173 double * mass = new double[pdgv.size()];
174 double sum = 0;
175 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
176 int pdgc = *pdg_iter;
177 double m = PDGLibrary::Instance()->Find(pdgc)->Mass();
178 mass[i++] = m;
179 sum += m;
180 }
181
182 LOG("HNL", pINFO)
183 << "Decaying N = " << pdgv.size() << " particles / total mass = " << sum;
184
185 int hnl_id = 0;
186 GHepParticle * hnl = event->Particle(hnl_id);
187 assert(hnl);
188 TLorentzVector * p4d = hnl->GetP4(); TVector3 HNLBVec = p4d->BoostVector();
189 TLorentzVector * p4d_rest = (TLorentzVector *) p4d->Clone(); p4d_rest->Boost( -HNLBVec );
190 TLorentzVector * v4d = hnl->GetX4();
191
192 LOG("HNL", pINFO)
193 << "\nDecaying system p4 = " << utils::print::P4AsString(p4d)
194 << "\nin rest frame, p4 = " << utils::print::P4AsString(p4d_rest);
195
196 // Set the decay
197 TGenPhaseSpace fPhaseSpaceGenerator;
198 //bool permitted = fPhaseSpaceGenerator.SetDecay(*p4d, pdgv.size(), mass);
199 bool permitted = fPhaseSpaceGenerator.SetDecay(*p4d_rest, pdgv.size(), mass);
200 if(!permitted) {
201 LOG("HNL", pERROR)
202 << " *** Phase space decay is not permitted \n"
203 << " Total particle mass = " << sum << "\n"
204 << " Decaying system p4 = " << utils::print::P4AsString(p4d);
205 // clean-up
206 delete [] mass;
207 delete p4d; delete p4d_rest;
208 delete v4d;
209 // throw exception
211 exception.SetReason("Decay not permitted kinematically");
212 exception.SwitchOnFastForward();
213 throw exception;
214 }
215
216 // Get the maximum weight
217 //double wmax = fPhaseSpaceGenerator.GetWtMax();
218 double wmax = -1;
219 for(int idec=0; idec<200; idec++) {
220 double w = fPhaseSpaceGenerator.Generate();
221 wmax = TMath::Max(wmax,w);
222 }
223 assert(wmax>0);
224 wmax *= 2;
225
226 LOG("HNL", pNOTICE)
227 << "Max phase space gen. weight @ current hadronic system: " << wmax;
228
229 // Generate a decay
230 bool decayFailed = false;
231 if( doPol && fCurrDecayMode != kHNLDcyNuNuNu ){
232 // if polarisation is on we must calculate the polarisation modulus for comparison
233 // for now, assume 2-body production and 2-body decay describes the pol modulus
234 // see arXiv:1805.06419[hep-ph]
235 TVector3 vecPolDir( fPolDir.at(0), fPolDir.at(1), fPolDir.at(2) );
236 LOG( "HNL", pDEBUG ) << "Doing a polarised decay...";
237 decayFailed = this->PolarisedDecay( fPhaseSpaceGenerator, pdgv, wmax, vecPolDir );
238 } else {
239 if( doPol && fCurrDecayMode == kHNLDcyNuNuNu ){
240 // no charged lepton here... warn the user about it, though
241 LOG( "HNL", pWARN )
242 << "Polarisation for invisible FS not implemented yet, defaulting to phase-space decay...";
243 }
244
245 LOG( "HNL", pDEBUG ) << "Doing a phase-space decay...";
246 decayFailed = this->UnpolarisedDecay( fPhaseSpaceGenerator, pdgv, wmax );
247 }
248 if( decayFailed ){
249 // clean up
250 delete [] mass;
251 delete p4d;
252 delete v4d;
253 // throw exception
255 exception.SetReason("Couldn't select decay after N attempts");
256 exception.SwitchOnFastForward();
257 throw exception;
258 }
259
260 // Insert final state products into a TClonesArray of GHepParticle's
261 TLorentzVector v4(*v4d);
262 int idp = 0; int npip = 0, npi0 = 0, npim = 0;
263 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
264 int pdgc = *pdg_iter;
265 TLorentzVector * p4fin = fPhaseSpaceGenerator.GetDecay(idp);
266 if( !fGetCMFrameInstead )
267 p4fin->Boost( HNLBVec ); // from rest to lab again
269 event->AddParticle(pdgc, ist, hnl_id,-1,-1,-1, *p4fin, v4);
270 switch( pdgc ){
271 case kPdgPiP: npip++; break;
272 case kPdgPi0: npi0++; break;
273 case kPdgPiM: npim++; break;
274 }
275 idp++;
276 }
277 Interaction * interaction = event->Summary();
278 interaction->ExclTagPtr()->SetNPions( npip, npi0, npim );
279
280 // Manually set up some mother-daughter links
281 // find primary (=leading) *charged!* lepton
282 double Elead = -1.0; int ilead = -1;
283 std::vector< int > lpdgv = { 11, 13, 15 };
284 for( std::vector<int>::iterator lit = lpdgv.begin(); lit != lpdgv.end(); ++lit ) {
285 GHepParticle * tmpPart = event->FindParticle( (*lit), kIStStableFinalState, 1 );
286 if( !tmpPart ) tmpPart = event->FindParticle( -1 * (*lit), kIStStableFinalState, 1 ); //antiparticle?
287 if( tmpPart ){
288 double tmpE = tmpPart->E();
289 if( tmpE > Elead ){ Elead = tmpE; ilead = event->ParticlePosition( tmpPart ); }
290 }
291 }
292 event->Particle( 0 )->SetFirstDaughter( ilead );
293 event->Particle( 0 )->SetFirstMother(-1); // why do I need to do this explicitly?
294 event->Particle( 0 )->SetLastMother(-1);
295
296 assert( event->Probe() );
297 if( !event->FinalStatePrimaryLepton() ){ // no charged lepton means invisible or pi0 nu or test
298 LOG( "HNL", pWARN )
299 << "No final state primary lepton for this event.";
302 }
303 //assert( event->FinalStatePrimaryLepton() );
304
305 // loop over all FS particles and set their mother to HNL
306 int itmp = 1, ilast = 1;
307 while( event->Particle( itmp ) ){
308 if( event->Particle(itmp)->Status() != kIStStableFinalState ){ itmp++; continue; }
309 event->Particle(itmp)->SetFirstMother(0);
310 event->Particle(itmp)->SetLastMother(-1);
311 if( itmp != ilead ) ilast = itmp;
312 itmp++;
313 }
314 event->Particle( 0 )->SetLastDaughter( ilast );
315 // "last daughter" of HNL means last non-primary-FS-lepton, so can be less than "first" daughter
316
317 LOG("HNL", pNOTICE)
318 << "Finished with decay products. Clean up and exit!";
319
320 // Clean-up
321 delete [] mass;
322 delete p4d;
323 delete v4d;
324}
325//____________________________________________________________________________
326std::vector< double > * Decayer::GenerateDecayPosition( GHepRecord * /* event */ ) const
327{
328 // let's query *where* the HNL decayed from.
329 LOG( "HNL", pWARN )
330 << "\nYou are seeing this message because the input dk2nu files did not give position information (for some reason)..."
331 << "\nDistributing the production vertex at some point in a 1m-side box. This is not good, and results will likely be unphysical.";
332 fProdVtxHist = new TH3D( "dummy", "dummy", 100, -0.5, 0.5, 100, -0.5, 0.5, 100, -0.5, 0.5 );
333 assert( fProdVtxHist );
334
336 double pvx = (rnd->RndGen()).Uniform( -0.5, 0.5 );
337 double pvy = (rnd->RndGen()).Uniform( -0.5, 0.5 );
338 double pvz = (rnd->RndGen()).Uniform( -0.5, 0.5 );
339 std::vector< double > * prodVtx = new std::vector< double >();
340 prodVtx->emplace_back( pvx ); prodVtx->emplace_back( pvy ); prodVtx->emplace_back( pvz );
341 LOG( "HNL", pDEBUG )
342 << "Production vertex at: ( " << prodVtx->at(0) << ", " << prodVtx->at(1) << ", " << prodVtx->at(2) << ") [cm]";
343
344 TLorentzVector v4( prodVtx->at(0), prodVtx->at(1), prodVtx->at(2), 0.0 );
345
346 SetProdVtxPosition( v4 );
347
348 return prodVtx;
349}
350//____________________________________________________________________________
351std::vector< double > * Decayer::GenerateMomentum( GHepRecord * event ) const
352{
353 Interaction * interaction = event->Summary();
354 double E = interaction->InitState().ProbeE(kRfLab);
355 double M = PDGLibrary::Instance()->Find(kPdgHNL)->Mass();
356 double p = TMath::Sqrt(E*E-M*M);
357
358 // set some initial deviation from beam axis due to collimation effect
359 double thetaDev = 0.0; //fAngularDeviation; // deg
360 thetaDev *= genie::constants::kPi / 180.0; // rad
362 double theta = Rng->RndGen().Gaus(0.0, thetaDev);
363 if( theta < 0.0 ) theta *= -1.0;
364 double phi = Rng->RndGen().Uniform(0.0, 2.0 * genie::constants::kPi);
365
366 double px = p * std::sin(theta) * std::cos(phi);
367 double py = p * std::sin(theta) * std::sin(phi);
368 double pz = p * std::cos(theta);
369
370 std::vector< double > * p3HNL = new std::vector< double >();
371 p3HNL->emplace_back(px);
372 p3HNL->emplace_back(py);
373 p3HNL->emplace_back(pz);
374
375 return p3HNL;
376}
377//____________________________________________________________________________
379{
380 Interaction * interaction = event->Summary();
381
382 interaction->KinePtr()->Sett( 0.0, true );
383 interaction->KinePtr()->SetW( interaction->InitStatePtr()->Probe()->Mass(), true );
384 TLorentzVector * p4HNL = event->Particle(0)->GetP4(); assert( p4HNL );
385 // primary lepton is FirstDaughter() of Probe()
386 // need Probe() as a GHepParticle(), not a TParticlePDG()!
387 // get from event record position 0
388 TLorentzVector * p4FSL = 0;
389 if( event->FinalStatePrimaryLepton() ){
390 int iFSL = event->Particle(0)->FirstDaughter();
391 assert( event->Particle( iFSL ) );
392 p4FSL = ( event->Particle( iFSL ) )->GetP4();
393 assert( p4FSL );
394 TLorentzVector p4DIF( p4HNL->Px() - p4FSL->Px(),
395 p4HNL->Py() - p4FSL->Py(),
396 p4HNL->Pz() - p4FSL->Pz(),
397 p4HNL->E() - p4FSL->E() );
398 interaction->KinePtr()->SetQ2( p4DIF.M2(), true );
399
400 }
401
402 // clean up
403 delete p4HNL;
404 if(p4FSL) delete p4FSL;
405}
406//____________________________________________________________________________
407void Decayer::Configure(const Registry & config)
408{
409 Algorithm::Configure(config);
410 this->LoadConfig();
411}
412//___________________________________________________________________________
413void Decayer::Configure(string config)
414{
415 Algorithm::Configure(config);
416 this->LoadConfig();
417}
418//___________________________________________________________________________
420{
421 LOG("HNL", pDEBUG)
422 << "Loading configuration from file...";
423
424 this->GetParam( "HNL-Mass", fMass );
425 std::vector< double > U4l2s;
426 this->GetParamVect( "HNL-LeptonMixing", U4l2s );
427 SetHNLCouplings( U4l2s.at(0), U4l2s.at(1), U4l2s.at(2) );
428 this->GetParam( "HNL-Majorana", fIsMajorana );
429 //this->GetParam( "HNL-Type", fType );
430
431 //this->GetParam( "HNL-angular_deviation", fAngularDeviation );
432
433 this->GetParam( "IncludePolarisation", fDoPol );
434
435 this->GetParamVect( "Near2User_T", fB2UTranslation );
436 this->GetParamVect( "Near2Beam_R", fB2URotation );
438
439 fIntChannels = {}; bool itChan = false;
440 //int chanBits[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
441
442 this->GetParam( "HNL-3B_nu_nu_nu", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyNuNuNu ); fChanBits[0] = 1; }
443 this->GetParam( "HNL-3B_nu_e_e", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyNuEE ); fChanBits[1] = 1; }
444 this->GetParam( "HNL-3B_nu_mu_e", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyNuMuE ); fChanBits[2] = 1; }
445 this->GetParam( "HNL-2B_nu_pi0", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPi0Nu ); fChanBits[3] = 1; }
446 this->GetParam( "HNL-2B_e_pi", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPiE ); fChanBits[4] = 1; }
447 this->GetParam( "HNL-3B_nu_mu_mu", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyNuMuMu ); fChanBits[5] = 1; }
448 this->GetParam( "HNL-2B_mu_pi", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPiMu ); fChanBits[6] = 1; }
449 this->GetParam( "HNL-3B_nu_pi0_pi0", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPi0Pi0Nu ); fChanBits[7] = 1; }
450 this->GetParam( "HNL-3B_e_pi_pi0", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPiPi0E ); fChanBits[8] = 1; }
451 this->GetParam( "HNL-3B_mu_pi_pi0", itChan ); if( itChan ){ fIntChannels.push_back( kHNLDcyPiPi0Mu ); fChanBits[9] = 1; }
452
453 this->GetParam( "GetCMFrameInstead", fGetCMFrameInstead );
454
455 // call GetHNLInstance here, to get lifetime
456 SimpleHNL sh = this->GetHNLInstance();
457 double CoMLifetime = sh.GetCoMLifetime();
458 assert( CoMLifetime > 0.0 );
459
460 // also read in particle gun parameters
461 this->GetParam( "PG-OriginX", fPGOx );
462 this->GetParam( "PG-OriginY", fPGOy );
463 this->GetParam( "PG-OriginZ", fPGOz );
464
465 this->GetParam( "PG-OriginDX", fPGDx );
466 this->GetParam( "PG-OriginDY", fPGDy );
467 this->GetParam( "PG-OriginDZ", fPGDz );
468
469 this->GetParam( "PG-Energy", fPGE );
470
471 this->GetParam( "PG-cx", fPGCx );
472 this->GetParam( "PG-cy", fPGCy );
473 this->GetParam( "PG-cz", fPGCz );
474
475 this->GetParam( "PG-DTheta", fPGDTheta );
476 this->GetParam( "PG-DPhi", fPGDPhi );
477
478 fIsConfigLoaded = true;
479}
480//___________________________________________________________________________
481void Decayer::SetHNLCouplings( double Ue42, double Um42, double Ut42 ) const
482{
483 fUe42 = Ue42;
484 fUm42 = Um42;
485 fUt42 = Ut42;
486}
487//___________________________________________________________________________
488void Decayer::SetBeam2User( std::vector< double > translation, std::vector< double > rotation ) const
489{
490 fTx = -1.0 * translation.at(0);
491 fTy = -1.0 * translation.at(1);
492 fTz = -1.0 * translation.at(2);
493
494 fR1 = rotation.at(0);
495 fR2 = rotation.at(1);
496 fR3 = rotation.at(2);
497}
498//___________________________________________________________________________
500{
501 SimpleHNL sh = SimpleHNL( "HNLInstance", 0, genie::kPdgHNL, genie::kPdgKP,
503 sh.SetType( 0 );
505 sh.SetAngularDeviation( 0.0 ); //fAngularDeviation );
508 return sh;
509}
510//____________________________________________________________________________
511void Decayer::SetProdVtxPosition(const TLorentzVector & v4) const
512{
513 TLorentzVector * pv4 = new TLorentzVector();
514 pv4->SetXYZT( v4.X(), v4.Y(), v4.Z(), v4.T() );
515 fProdVtx = pv4;
516}
517//____________________________________________________________________________
519{
520 if( fPolDir.size() > 0 ) fPolDir.clear();
521 /*
522 fPolDir.emplace_back( gnmf.ppvx );
523 fPolDir.emplace_back( gnmf.ppvy );
524 fPolDir.emplace_back( gnmf.ppvz );
525
526 fParentPdg = gnmf.ptype;
527 fProdLepPdg = gnmf.ppmedium;
528 */
529
530 TLorentzVector * vv = event->Vertex();
531 TLorentzVector * tmpx4 = event->Particle(0)->GetX4();
532 // this will only have been modified if we have enough polarisation information to do something.
533 // Otherwise, FluxCreator hasn't been run and we shouldn't do stuff.
534 if( tmpx4->X() != vv->X() || tmpx4->Y() != vv->Y() || tmpx4->Z() != vv->Z() ){
535 fPolDir.emplace_back( tmpx4->X() );
536 fPolDir.emplace_back( tmpx4->Y() );
537 int tmpMod = ( event->XSec() > 0.0 ) ? 1 : -1;
538 fPolDir.emplace_back( tmpMod * std::sqrt( 1.0 -
539 ( tmpx4->X() * tmpx4->X() + tmpx4->Y() * tmpx4->Y() ) ) );
540
541 fParentPdg = tmpx4->Z();
542 fProdLepPdg = tmpx4->T();
543
544 // now reset the x4 of the HNL to whatever the vertex is
545 event->Particle(0)->SetPosition( vv->X(), vv->Y(), vv->Z(), vv->T() );
546 event->SetXSec(0.0);
547 } else { return; }
548}
549//____________________________________________________________________________
550bool Decayer::UnpolarisedDecay( TGenPhaseSpace & fPSG, PDGCodeList pdgv, double wm ) const
551{
552
554
555 bool accept_decay=false;
556 unsigned int itry=0;
557
558 bool failed = false;
559 while(!accept_decay) {
560 itry++;
561
563 // report and return
564 LOG("HNL", pWARN)
565 << "Couldn't generate an unweighted phase space decay after "
566 << itry << " attempts";
567 failed = true;
568 return failed;
569 }
570 double w = fPSG.Generate();
571 if(w > wm) {
572 LOG("HNL", pWARN)
573 << "Decay weight = " << w << " > max decay weight = " << wm;
574 }
575 double gw = wm * rnd->RndHadro().Rndm();
576 accept_decay = (gw<=w);
577
578 /*
579 LOG("HNL", pDEBUG)
580 << "Decay weight = " << w << " / R = " << gw
581 << " - accepted: " << accept_decay;
582 */
583
584 } //!accept_decay
585
586 return failed;
587
588}
589//____________________________________________________________________________
590bool Decayer::PolarisedDecay( TGenPhaseSpace & fPSG, PDGCodeList pdgv, double wm, TVector3 vPolDir ) const
591{
592 // calculate polarisation modulus
594 double MHNL = pdgl->Find( kPdgHNL )->Mass();
595 double polMag = this->CalcPolMag( fParentPdg, fProdLepPdg, MHNL );
596 double polMod = -999.99;
597
598 // do decays until weight \in Uniform[0.0, 2.0] < 1 \mp polMod * cos\theta
599 unsigned int iUPD = 0;
600 double polWgt = -999.9;
602 double rwgt = 0.0;
603 bool isAccepted = false;
604
605 bool failed = false;
606
607 // first, check to see if we have pi0 + v. Then let the neutrino be a QLep.
608 bool isPi0Nu = ( pdgv.size() == 3 &&
609 std::abs( pdgv.at(1) ) == kPdgPi0 &&
610 std::abs( pdgv.at(2) ) == kPdgNuMu );
611
612 while( !isAccepted && iUPD < controls::kMaxUnweightDecayIterations ){
613 bool failed = this->UnpolarisedDecay( fPSG, pdgv, wm );
614
615 // find charged lepton of FS. If two, take the leading one.
616 // For now, this method doesn't handle vvv invisible decay mode.
617
618 TVector3 lepDir;
619 vector<int>::const_iterator pdg_iter;
620 int idc = 0; double Elead = -1.0;
621 for(pdg_iter = pdgv.begin(); pdg_iter != pdgv.end(); ++pdg_iter) {
622 int pdgc = *pdg_iter; Elead = -1.0;
623 bool isQLep = ( std::abs( pdgc ) == kPdgElectron ||
624 std::abs( pdgc ) == kPdgMuon ||
625 std::abs( pdgc ) == kPdgTau ||
626 ( isPi0Nu && std::abs( pdgc ) == kPdgNuMu ) );
627 if( isQLep ){
628 TLorentzVector * p4lep = fPSG.GetDecay(idc);
629 if( p4lep->E() > Elead ){
630 Elead = p4lep->E();
631 lepDir = p4lep->Vect();
632 fDecLepPdg = pdgc;
633 if( std::abs(fDecLepPdg) != std::abs(pdgc) || polMod < -1.0 ){
634 // update polarisation modulus for new leading lepton
635 polMod = this->CalcPolMod( polMag, fDecLepPdg, fDecHadPdg, MHNL );
636 } // std::abs(fDecLepPdg) != std::abs(pdgc) || polMod == -999.9
637 } // p4lep->E() > Elead
638 } // isQLep
639
640 idc++;
641 }
642
643 // find angle \theta of leading FS QLep with vPolDir
644 // assume differential decay rate \propto ( 1 \pm pMod * cos\theta )
645
646 double theta = vPolDir.Angle( lepDir ); // rad
647 double ctheta = TMath::Cos( theta );
648
649 rwgt = rnd->RndGen().Uniform(0.0, 2.0);
650 int typeMod = ( *(pdgv.begin()) > 0 ) ? 1 : -1;
651 polWgt = 1 + typeMod * polMod * ctheta;
652
653 isAccepted = ( rwgt >= polWgt );
654
655 iUPD++;
656 } // while( rwgt >= polWgt && iUPD < controls::kMaxUnweightDecayIterations )
657
659 // report and return
660 LOG("HNL", pWARN)
661 << "Couldn't generate a polarised decay after "
662 << iUPD << " attempts";
663 failed = true;
664 return failed;
665 }
666
667 return failed;
668
669}
670//____________________________________________________________________________
671double Decayer::CalcPolMag( int parPdg, int lepPdg, double M ) const
672{
674 double mPar = pdgl->Find( std::abs( parPdg ) )->Mass();
675 double mLep = pdgl->Find( std::abs( lepPdg ) )->Mass();
676
677 double num1 = mLep * mLep - M * M;
678 double num2 = TMath::Sqrt(utils::hnl::Kallen( mPar*mPar, M*M, mLep*mLep ));
679
680 double den1 = mPar*mPar*( mLep*mLep + M*M );
681 double den2 = mLep*mLep - M*M;
682
683 // pMag is a modulus, not a magnitude... not positive semi-definite. See Fig.4 in 1805.06419[hep-ph]
684 double pMag = -1.0 * num1*num2 / ( den1 - den2*den2 );
685 return pMag;
686}
687//____________________________________________________________________________
688double Decayer::CalcPolMod( double polMag, int lepPdg, int hadPdg, double M ) const
689{
691 double mLep = pdgl->Find( std::abs( lepPdg ) )->Mass();
692 double mHad = pdgl->Find( std::abs( hadPdg ) )->Mass();
693
694 double num1 = M*M - mLep*mLep;
695 double num2 = TMath::Sqrt(utils::hnl::Kallen( M*M, mLep*mLep, mHad*mHad ));
696 double num3 = polMag;
697
698 double den1 = M*M - mLep*mLep;
699 double den2 = mHad*mHad*( M*M + mLep*mLep );
700
701 double pMod = num1*num2*num3 / ( den1*den1 - den2 );
702 return pMod;
703}
704//____________________________________________________________________________
706{
707 return (this->GetHNLInstance()).GetCoMLifetime();
708}
709//____________________________________________________________________________
711{
712 return fMass;
713}
714//____________________________________________________________________________
715std::vector<double> Decayer::GetHNLCouplings() const
716{
717 std::vector<double> allCoups;
718 allCoups.emplace_back(fUe42); allCoups.emplace_back(fUm42); allCoups.emplace_back(fUt42);
719 return allCoups;
720}
721//____________________________________________________________________________
723{
724 return fIsMajorana;
725}
726//____________________________________________________________________________
728{
729 std::string chanInt = "";
730 for( int iCBits = sizeof( fChanBits ) / sizeof( fChanBits[0] ) - 1; iCBits >= 0 ; iCBits-- ){
731 chanInt.append( Form("%d", fChanBits[iCBits]) );
732 }
733 return chanInt;
734}
735//____________________________________________________________________________
736std::vector< double > Decayer::GetPGunOrigin() const
737{
738 std::vector< double > PGOrigin;
739 PGOrigin.emplace_back( fPGOx ); PGOrigin.emplace_back( fPGOy ); PGOrigin.emplace_back( fPGOz );
740 return PGOrigin;
741}
742//____________________________________________________________________________
743std::vector< double > Decayer::GetPGunDOrigin() const
744{
745 std::vector< double > PGDOrigin;
746 PGDOrigin.emplace_back( fPGDx ); PGDOrigin.emplace_back( fPGDy ); PGDOrigin.emplace_back( fPGDz );
747 return PGDOrigin;
748}
749//____________________________________________________________________________
751{
752 return fPGE;
753}
754//____________________________________________________________________________
755std::vector< double > Decayer::GetPGunDirection() const
756{
757 std::vector< double > PGDirection;
758 PGDirection.emplace_back( fPGCx ); PGDirection.emplace_back( fPGCy ); PGDirection.emplace_back( fPGCz );
759 return PGDirection;
760}
761//____________________________________________________________________________
762std::vector< double > Decayer::GetPGunDeviation() const
763{
764 std::vector< double > PGDeviation;
765 PGDeviation.emplace_back( fPGDTheta ); PGDeviation.emplace_back( fPGDPhi );
766 return PGDeviation;
767}
#define pNOTICE
Definition Messenger.h:61
#define pINFO
Definition Messenger.h:62
#define pERROR
Definition Messenger.h:59
#define pDEBUG
Definition Messenger.h:63
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE,...
Definition Messenger.h:96
#define pWARN
Definition Messenger.h:60
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils.
bool GetParam(const RgKey &name, T &p, bool is_top_call=true) const
int GetParamVect(const std::string &comm_name, std::vector< T > &v, bool is_top_call=true) const
Handle to load vectors of parameters.
virtual void Configure(const Registry &config)
Definition Algorithm.cxx:62
STDHEP-like event record entry that can fit a particle or a nucleus.
double E(void) const
Get energy.
GHepStatus_t Status(void) const
GENIE's GHEP MC event record.
Definition GHepRecord.h:45
virtual GHepParticle * Probe(void) const
virtual TLorentzVector * Vertex(void) const
Definition GHepRecord.h:140
virtual GHepParticle * Particle(int position) const
virtual GHepParticle * FinalStatePrimaryLepton(void) const
Initial State information.
TLorentzVector * GetProbeP4(RefFrame_t rf=kRfHitNucRest) const
void SetProbeP4(const TLorentzVector &P4)
TParticlePDG * Probe(void) const
int ProbePdg(void) const
double ProbeE(RefFrame_t rf) const
Summary information for an interaction.
Definition Interaction.h:56
const XclsTag & ExclTag(void) const
Definition Interaction.h:72
InitialState * InitStatePtr(void) const
Definition Interaction.h:74
XclsTag * ExclTagPtr(void) const
Definition Interaction.h:77
const InitialState & InitState(void) const
Definition Interaction.h:69
Kinematics * KinePtr(void) const
Definition Interaction.h:76
void SetQ2(double Q2, bool selected=false)
void Sett(double t, bool selected=false)
void SetW(double W, bool selected=false)
A list of PDG codes.
Definition PDGCodeList.h:32
void push_back(int pdg_code)
Singleton class to load & serve a TDatabasePDG.
Definition PDGLibrary.h:36
static PDGLibrary * Instance(void)
TParticlePDG * Find(int pdgc, bool must_exist=true)
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition RandomGen.h:29
TRandom3 & RndHadro(void) const
rnd number generator used by hadronization models
Definition RandomGen.h:53
static RandomGen * Instance()
Access instance.
Definition RandomGen.cxx:74
TRandom3 & RndGen(void) const
rnd number generator for generic usage
Definition RandomGen.h:80
A registry. Provides the container for algorithm configuration parameters.
Definition Registry.h:65
int DecayMode(void) const
Definition XclsTag.h:70
void SetNPions(int npi_plus, int npi_0, int npi_minus)
Definition XclsTag.cxx:88
An exception thrown by EventRecordVisitorI when the normal processing sequence has to be disrupted (f...
std::vector< double > GetPGunDirection() const
bool PolarisedDecay(TGenPhaseSpace &fPSG, PDGCodeList pdgv, double wm, TVector3 vPolDir) const
std::vector< double > GetPGunDeviation() const
TLorentzVector * fProdVtx
Definition HNLDecayer.h:124
std::vector< double > * GenerateMomentum(GHepRecord *event) const
std::string GetHNLInterestingChannels() const
double GetHNLMass() const
genie::hnl::HNLDecayMode_t fCurrDecayMode
Definition HNLDecayer.h:100
void UpdateEventRecord(GHepRecord *event) const
void ProcessEventRecord(GHepRecord *event) const
double CalcPolMag(int parPdg, int lepPdg, double M) const
void SetHNLCouplings(double Ue42, double Um42, double Ut42) const
std::vector< double > fB2URotation
Definition HNLDecayer.h:120
std::vector< genie::hnl::HNLDecayMode_t > fIntChannels
Definition HNLDecayer.h:114
double GetHNLLifetime() const
double CalcPolMod(double polMag, int lepPdg, int hadPdg, double M) const
void Configure(const Registry &config)
void SetProdVtxPosition(const TLorentzVector &v4) const
void AddInitialState(GHepRecord *event) const
bool IsHNLMajorana() const
std::vector< double > fB2UTranslation
Definition HNLDecayer.h:118
double GetPGunEnergy() const
std::vector< double > * GenerateDecayPosition(GHepRecord *event) const
std::vector< double > GetPGunDOrigin() const
genie::hnl::SimpleHNL GetHNLInstance() const
std::vector< double > GetPGunOrigin() const
void GenerateDecayProducts(GHepRecord *event) const
std::vector< double > fPolDir
Definition HNLDecayer.h:103
void SetBeam2User(std::vector< double > translation, std::vector< double > rotation) const
void ReadCreationInfo(GHepRecord *event) const
std::vector< double > GetHNLCouplings() const
bool UnpolarisedDecay(TGenPhaseSpace &fPSG, PDGCodeList pdgv, double wm) const
void SetBeam2UserTranslation(const double tx, const double ty, const double tz)
Definition SimpleHNL.h:298
double GetCoMLifetime()
Definition SimpleHNL.h:96
void SetBeam2UserRotation(const double r1, const double r2, const double r3)
Definition SimpleHNL.h:302
void SetInterestingChannelsVec(const std::vector< genie::hnl::HNLDecayMode_t > decVec)
Definition SimpleHNL.h:281
void SetAngularDeviation(const double adev)
Definition SimpleHNL.h:296
void SetType(const int type)
Definition SimpleHNL.h:294
double CoMLifetime
static const unsigned int kMaxUnweightDecayIterations
Definition Controls.h:61
enum genie::hnl::EHNLDecayMode HNLDecayMode_t
PDGCodeList DecayProductList(genie::hnl::HNLDecayMode_t hnldm)
string AsString(genie::hnl::HNLDecayMode_t hnldm)
double Kallen(double x, double y, double z)
Definition HNLKinUtils.h:37
string P4AsString(const TLorentzVector *p)
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25
const int kPdgPiM
Definition PDGCodes.h:159
@ kIStStableFinalState
Definition GHepStatus.h:30
@ kIStInitialState
Definition GHepStatus.h:29
const int kPdgPi0
Definition PDGCodes.h:160
const int kPdgTau
Definition PDGCodes.h:39
const int kPdgKP
Definition PDGCodes.h:172
enum genie::EGHepStatus GHepStatus_t
@ kRfLab
Definition RefFrame.h:26
const int kPdgHNL
Definition PDGCodes.h:224
const int kPdgPiP
Definition PDGCodes.h:158
const int kPdgMuon
Definition PDGCodes.h:37
const int kPdgNuMu
Definition PDGCodes.h:30
const int kPdgElectron
Definition PDGCodes.h:35