GENIEGenerator
Loading...
Searching...
No Matches
gBeamHNLValidationApp.cxx
Go to the documentation of this file.
1//________________________________________________________________________________________
2/*!
3
4\program gevald_hnl
5
6\brief Validation app for HNL generation.
7
8 *** Synopsis :
9
10 gevald_hnl [-h]
11 [-r run#]
12 -n n_of_events
13 -f path/to/flux/files
14 [-E hnl_energy]
15 [-g geometry (ROOT file)]
16 [-L geometry_length_units]
17 [-A geometry_angle_units]
18 [-T geometry_time_units]
19 [-o output_event_file_prefix]
20 [--seed random_number_seed]
21
22 *** Options :
23
24 [] Denotes an optional argument
25
26 -h
27 Prints out the gevald_hnl syntax and exits.
28 -r
29 Specifies the MC run number [default: 1000].
30 -n
31 Specifies how many events to generate.
32 -f
33 Input HNL flux.
34 -E
35 HNL energy for monoenergetic HNL
36 -g
37 Input detector geometry.
38 If a geometry is specified, HNL decay vertices will be distributed
39 in the desired detector volume.
40 Using this argument, you can pass a ROOT file containing your
41 detector geometry description.
42 -L
43 Input geometry length units, eg 'm', 'cm', 'mm', ...
44 [default: 'mm']
45 -A
46 Input geometry angle units: 'deg', 'rad', or 'mrad'
47 [default: 'rad']
48 -T
49 Input geometry time units, eg 's', 'us', 'ns', ...
50 [default: 'ns']
51 -o
52 Sets the prefix of the output event file.
53 The output filename is built as:
54 [prefix].[run_number].[event_tree_format].[file_format]
55 The default output filename is:
56 gntp.[run_number].ghep.root
57 This cmd line arguments lets you override 'gntp'
58 --seed
59 Random number seed.
60
61\author Costas Andreopoulos <c.andreopoulos \at cern.ch>
62 University of Liverpool
63
64 John Plows <komninos-john.plows \at cern.ch>
65 University of Oxford
66
67\created May 17, 2022
68
69\cpright Copyright (c) 2003-2025, The GENIE Collaboration
70 For the full text of the license visit http://copyright.genie-mc.org
71
72*/
73//_________________________________________________________________________________________
74
75#include <cassert>
76#include <cstdlib>
77#include <string>
78#include <vector>
79#include <sstream>
80
81#include <TSystem.h>
82
92
101
112
113using std::string;
114using std::vector;
115using std::ostringstream;
116
117using namespace genie;
118using namespace genie::hnl;
119
120#ifdef __GENIE_FLUX_DRIVERS_ENABLED__
121#define __CAN_GENERATE_EVENTS_USING_A_FLUX__
122//#include "Tools/Flux/GNuMIFlux.h"
123#include <TH1.h>
124#endif // #ifdef __GENIE_FLUX_DRIVERS_ENABLED__
125
126#ifdef __GENIE_GEOM_DRIVERS_ENABLED__
127#define __CAN_USE_ROOT_GEOM__
128#include <TGeoVolume.h>
129#include <TGeoManager.h>
130#include <TGeoShape.h>
131#include <TGeoBBox.h>
132#endif // #ifdef __GENIE_GEOM_DRIVERS_ENABLED__
133
143
144// function prototypes
145void GetCommandLineArgs (int argc, char ** argv);
146void ReadInConfig (void);
147void PrintSyntax (void);
149
150#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
151int TestFluxFromDk2nu (void);
152#endif
153
154int TestDecay (void);
155
156#ifdef __CAN_USE_ROOT_GEOM__
157int TestGeom (void);
158void InitBoundingBox (void);
159#endif // #ifdef __CAN_USE_ROOT_GEOM__
160
161//
162string kDefOptGeomLUnits = "mm"; // default geometry length units
163string kDefOptGeomAUnits = "rad"; // default geometry angle units
164string kDefOptGeomTUnits = "ns"; // default geometry time units
165string kDefOptGeomDUnits = "g_cm3"; // default geometry density units
166
167NtpMCFormat_t kDefOptNtpFormat = kNFGHEP; // default event tree format
168string kDefOptEvFilePrefix = "gntp";
169string kDefOptFluxFilePath = "./input-flux.root";
170
171string kDefOptSName = "genie::EventGenerator";
172string kDefOptSConfig = "BeamHNL";
173string kDefOptSTune = "GHNL20_00a_00_000";
174
175//
176Long_t gOptRunNu = 1000; // run number
177int gOptNev = 10; // number of events to generate
178
180
181// ---- this section set in config
182
183double gCfgMassHNL = -1; // HNL mass
184double gCfgECoupling = -1; // |U_e4|^2
185double gCfgMCoupling = -1; // |U_m4|^2
186double gCfgTCoupling = -1; // |U_t4|^2
187bool gCfgIsMajorana = false;
189
190double CoMLifetime = -1; // lifetime in centre-of-mass frame [GeV^-1]
191
192
193HNLProd_t gCfgProdMode = kHNLProdNull; // HNL production mode
195std::vector< HNLDecayMode_t > gCfgIntChannels; // decays to un-inhibit
196
197double gCfgUserOx = -1; // user origin x in beam coords
198double gCfgUserOy = -1; // user origin y in beam coords
199double gCfgUserOz = -1; // user origin z in beam coords
200double gCfgUserAx1 = -1; // left-most extrinsic Euler angle (x)
201double gCfgUserAz = -1; // middle extrinsic Euler angle (z)
202double gCfgUserAx2 = -1; // right-most extrinsic Euler angle (x)
203
204double gCfgBoxLx = -1; // detector length on user x
205double gCfgBoxLy = -1; // detector length on user y
206double gCfgBoxLz = -1; // detector length on user z
207
208double gCfgParentEnergy = -1; // parent energy in GeV
209double gCfgParentTheta = -1; // wrt beam axis
210double gCfgParentPhi = -1; // 0 == x, pi/2 == y
211double gCfgParentOx = -1; // user x of parent origin
212double gCfgParentOy = -1; // user y of parent origin
213double gCfgParentOz = -1; // user z of parent origin
214
215double gCfgHNLCx = -1; // directional cosine for x for HNL traj
216double gCfgHNLCy = -1; // directional cosine for y for HNL traj
217double gCfgHNLCz = -1; // directional cosine for z for HNL traj
218
219// ---- end config section
220
221double gOptEnergyHNL = -1; // HNL energy in GeV
222
223#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
224string gOptFluxFilePath = kDefOptFluxFilePath; // where flux files live
225bool gOptIsUsingDk2nu = false; // using flat dk2nu files?
226#endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
227bool gOptIsMonoEnFlux = true; // do we have monoenergetic flux?
228
229string gOptEvFilePrefix = kDefOptEvFilePrefix; // event file prefix
230bool gOptUsingRootGeom = false; // using root geom?
231string gOptRootGeom; // input ROOT file with realistic detector geometry
232
233string geom;
235double gOptGeomLUnits = 0; // input geometry length units
236double gOptGeomAUnits = 0; // input geometry angle units
237double gOptGeomTUnits = 0; // input geometry time units
238#ifdef __CAN_USE_ROOT_GEOM__
239TGeoManager * gOptRootGeoManager = 0; // the workhorse geometry manager
240TGeoVolume * gOptRootGeoVolume = 0;
241#endif // #ifdef __CAN_USE_ROOT_GEOM__
242string gOptRootGeomTopVol = ""; // input geometry top event generation volume
243
244// Geometry bounding box and origin - read from the input geometry file (if any)
245double fdx = 0; // half-length - x
246double fdy = 0; // half-length - y
247double fdz = 0; // half-length - z
248double fox = 0; // origin - x
249double foy = 0; // origin - y
250double foz = 0; // origin - z
251
252long int gOptRanSeed = -1; // random number seed
253
254//_________________________________________________________________________________________
255int main(int argc, char ** argv)
256{
257 // suppress ROOT Info messages
258 gErrorIgnoreLevel = kWarning;
259
260 // Parse command line arguments
261 GetCommandLineArgs(argc,argv);
262
263 // Get the validation configuration
264 ReadInConfig();
265
266 // Init messenger and random number seed
267 utils::app_init::MesgThresholds(RunOpt::Instance()->MesgThresholdFiles());
269
270 switch( gOptValidationMode ){
271
272 case kValFluxFromDk2nu: return TestFluxFromDk2nu(); break;
273 case kValDecay: return TestDecay(); break;
274 case kValGeom: return TestGeom(); break;
275 default: LOG( "gevald_hnl", pFATAL ) << "I didn't recognise this mode. Goodbye world!"; break;
276 }
277
278 return 0;
279}
280//_________________________________________________________________________________________
281//............................................................................
282#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
283int TestFluxFromDk2nu()
284{
285 assert( !gOptIsMonoEnFlux && gOptIsUsingDk2nu );
286
287 string foutName("test_flux_dk2nu.root");
288
289 LOG( "gevald_hnl", pINFO )
290 << "\n\nTesting flux prediction from dk2nu input files."
291 << "\nWill produce 1 ROOT file (" << foutName << ") with:"
292 << "\n--> Energy spectra for the HNL (total and broken down by parent)"
293 << "\n--> Production vertex locations"
294 << "\n--> Counters for each production mode"
295 << "\n--> Spectrum of acceptance correction as function of parent boost factor"
296 << "\n--> Boost factor spectrum of parents broken down by type";
297
298 const Algorithm * algFluxCreator = AlgFactory::Instance()->GetAlgorithm("genie::hnl::FluxCreator", "Default");
299
300 const FluxCreator * fluxCreator = dynamic_cast< const FluxCreator * >( algFluxCreator );
301
302 fluxCreator->SetInputFluxPath( gOptFluxFilePath );
303 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
304 if (!geom_is_accessible) {
305 LOG("gevald_hnl", pFATAL)
306 << "The specified ROOT geometry doesn't exist! Initialization failed!";
307 exit(1);
308 }
309 fluxCreator->SetGeomFile( gOptRootGeom );
310
311 int maxFluxEntries = -1;
312
313 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
314
315 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
316 assert( top_volume );
317 TGeoShape * ts = top_volume->GetShape();
318 __attribute__((unused)) TGeoBBox * box = (TGeoBBox *)ts;
319
320 TFile * fout = TFile::Open( foutName.c_str(), "RECREATE" );
321 TH1D hEAll, hEPion, hEKaon, hEMuon, hENeuk;
322 TH1D hPop, hImpwt;
323 TH1D hAcceptanceCorr, hAcceptance, hAcceptNoBCorr;
324 TH3D hProdVtxPos;
325 TH1D hCounters;
326 TH1D hBAll, hBPion, hBKaon, hBMuon, hBNeuk;
327 TH1D hParamSpace; // to store mass + couplings
328
329 hEAll = TH1D( "hEAll", "HNL energy - all parents", 1000, 0., 100. );
330 hEPion = TH1D( "hEPion", "HNL energy - pion parent", 1000, 0., 100. );
331 hEKaon = TH1D( "hEKaon", "HNL energy - kaon parent", 1000, 0., 100. );
332 hEMuon = TH1D( "hEMuon", "HNL energy - muon parent", 1000, 0., 100. );
333 hENeuk = TH1D( "hENeuk", "HNL energy - neuk parent", 1000, 0., 100. );
334
335 hPop = TH1D( "hPop", "HNL populations in energy bins", 1000, 0., 100. );
336 hImpwt = TH1D( "hImpwt", "HNL importance weights", 1000, 0., 100. );
337
338 static const Double_t accbins[] = { 0.0, 2.5e-7, 5.0e-7, 7.5e-7, 1.0e-6, 2.5e-6, 5.0e-6, 7.5e-6, 1.0e-5, 2.5e-5, 5.0e-5, 7.5e-5, 1.0e-4, 2.5e-4, 5.0e-4, 7.5e-4, 1.0e-3, 2.5e-3, 5.0e-3, 7.5e-3, 1.0e-2, 2.5e-2, 5.0e-2, 7.5e-2, 1.0e-1, 2.5e-1, 5.0e-1, 7.5e-1, 1.0e+0, 2.5e+0, 5.0e+0, 7.5e+0, 1.0e+1 };
339 const Int_t naccbins = sizeof(accbins)/sizeof(accbins[0]) - 1;
340 hAcceptanceCorr = TH1D( "hAcceptanceCorr", "HNL acceptance correction", naccbins, accbins );
341 hAcceptance = TH1D( "hAcceptance", "HNL acceptance" , 200, 0.0, 100.0 );
342 hAcceptNoBCorr = TH1D( "hAcceptNoBCorr", "HNL SAA * accCorr" , 200, 0.0, 100.0 );
343
344 hProdVtxPos = TH3D( "hProdVtxPos", "HNL production vertex (user coordinates, cm)",
345 200, -100., 100., 200, -100., 100., 1100, -110000., 0.);
346
347 hCounters = TH1D( "hCounters", "HNL production channel counters", 11, 0, 11 );
348
349 hBAll = TH1D( "hBAll", "Boost beta - all parents", 100, 0., 1. );
350 hBPion = TH1D( "hBPion", "Boost beta - pion parent", 100, 0., 1. );
351 hBKaon = TH1D( "hBKaon", "Boost beta - kaon parent", 100, 0., 1. );
352 hBMuon = TH1D( "hBMuon", "Boost beta - muon parent", 100, 0., 1. );
353 hBNeuk = TH1D( "hBNeuk", "Boost beta - neuk parent", 100, 0., 1. );
354
355 hParamSpace = TH1D( "hParamSpace", "Parameter space", 5, 0., 5. );
356
357 int parPDG;
358 TLorentzVector p4HNL;
359 TLorentzVector x4HNL;
360 int nPion2Muon = 0, nPion2Electron = 0, nKaon2Muon = 0,
361 nKaon2Electron = 0, nKaon3Muon = 0, nKaon3Electron = 0,
362 nNeuk3Muon = 0, nNeuk3Electron = 0, nMuon3Numu = 0,
363 nMuon3Nue = 0, nMuon3Nutau = 0;
364 double nPOT = 0;
365 double betaMag;
366 double accCorr;
367 double nimpwt; // hadroproduction importance weight
368
369 int ievent = 0;
370 while(true)
371 {
372 if( gOptNev >= 10000 ){
373 if( ievent % (gOptNev / 1000) == 0 ){
374 int irat = ievent / (gOptNev / 1000);
375 std::cerr << Form("%2.2f", 0.1 * irat) << " % ( " << ievent << " / "
376 << gOptNev << " ) \r" << std::flush;
377 }
378 } else if( gOptNev >= 100 ) {
379 if( ievent % (gOptNev / 10) == 0 ){
380 int irat = ievent / ( gOptNev / 10 );
381 std::cerr << 10.0 * irat << " % " << " ( " << ievent
382 << " / " << gOptNev << " ) \r" << std::flush;
383 }
384 }
385
386 if( ievent == gOptNev ) break;
387
388 EventRecord * event = new EventRecord;
389 event->SetXSec( ievent ); // will be overridden, use as handy container
390
391 fluxCreator->ProcessEventRecord(event);
392
393 // fluxCreator->ProcessEventRecord now tells us how many entries there are
394 maxFluxEntries = fluxCreator->GetNFluxEntries();
395 if( gOptNev > maxFluxEntries ){
396 LOG( "gevgen_hnl", pWARN )
397 << "You have asked for " << gOptNev << " events, but only provided "
398 << maxFluxEntries << " flux entries. Truncating events to " << maxFluxEntries << ".";
399 gOptNev = maxFluxEntries;
400 }
401
402 FluxContainer vgnmf = fluxCreator->RetrieveFluxInfo();
403 FluxContainer * gnmf = &vgnmf;
404
405 // reject nonsense
406 if( gnmf->Ecm < 0 ){
407
408 LOG( "gevald_hnl", pDEBUG )
409 << "Skipping nonsense for event " << ievent << " (was this parent too light?)";
410
411 } else {
412 // now to make stuff from this... i.e. fill histos
413
414 // first get the channel
415 int iChannel = gnmf->prodChan;
416 HNLProd_t pChannel = static_cast<HNLProd_t>(iChannel);
417 int typeMod = (gnmf->pdg > 0) ? 1 : -1;
418
419 parPDG = gnmf->parPdg;
420
421 if( parPDG == 0 || parPDG == -9999 ){ ievent++; continue; }
422
423 double MPar = PDGLibrary::Instance()->Find( parPDG )->Mass();
424 /*
425 TVector3 p3par( gnmf->xpoint, gnmf->ypoint, gnmf->zpoint );
426 double EPar = std::sqrt( p3par.Mag2() + MPar*MPar );
427 */
428 //TLorentzVector p4par( p3par.Px(), p3par.Py(), p3par.Pz(), EPar );
429 TLorentzVector p4par = gnmf->parp4; // NEAR, GeV
430 double EPar = p4par.E();
431
432 TVector3 boost_beta = p4par.BoostVector();
433 betaMag = boost_beta.Mag();
434
435 p4HNL = gnmf->p4; // NEAR coords, GeV
436 TVector3 dkVtx = gnmf->startPoint; // NEAR coords, m
437 double delay = gnmf->delay; // ns
438
439 x4HNL.SetXYZT( dkVtx.X() * units::m / units::cm,
440 dkVtx.Y() * units::m / units::cm,
441 dkVtx.Z() * units::m / units::cm,
442 delay );
443
444 double acceptance = gnmf->acceptance; // full acceptance
445 double bCorr = gnmf->boostCorr; // boost correction
446 accCorr = gnmf->accCorr; // just the acceptance correction
447 nimpwt = gnmf->nimpwt;
448
449 double gam = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
450 double gamStar = gnmf->Ecm / gCfgMassHNL;
451 double betaStar = std::sqrt( 1.0 - 1.0 / ( gamStar * gamStar ) );
452 double bigBeta = betaMag * gam / betaStar;
453
454 double Ox = -1.0 * x4HNL.X();
455 double Oy = -1.0 * x4HNL.Y();
456 double Oz = -1.0 * x4HNL.Z();
457
458 double rootArg = gam*gam*Oz*Oz -
459 (gam*gam - bigBeta*bigBeta)*(Oz*Oz - bigBeta*bigBeta*(Ox*Ox + Oy*Oy));
460
461 double timelikeBit = ( rootArg >= 0.0 ) ? std::sqrt( rootArg ) / ( betaMag * gam * gam * gam ) : 0.0;
462
463 double fullTerm = (1.0 - 1.0 / gam) * Oz / ( betaMag * gam ) - timelikeBit;
464 if( std::abs( fullTerm ) > 100.0 ) fullTerm *= 100.0 / std::abs( fullTerm );
465
466 nPOT = 1.0; // = gnmf->norig;
467
468 // fill the histos!
469 hEAll.Fill( p4HNL.E(), acceptance * nimpwt );
470 hProdVtxPos.Fill( x4HNL.X(), x4HNL.Y(), x4HNL.Z(), nimpwt );
471 hBAll.Fill( betaMag, nimpwt );
472
473 hPop.Fill( p4HNL.E(), 1.0 );
474 hImpwt.Fill( p4HNL.E(), nimpwt );
475 hAcceptanceCorr.Fill( accCorr, nimpwt );
476 hAcceptance.Fill( p4HNL.E(), nimpwt * acceptance );
477 hAcceptNoBCorr.Fill( p4HNL.E(), nimpwt * acceptance / ( bCorr * bCorr ) );
478
479 switch( parPDG ){
480 case kPdgPiP:
481 hEPion.Fill( p4HNL.E(), acceptance * nimpwt );
482 hBPion.Fill( betaMag, nimpwt );
483 break;
484 case kPdgKP:
485 hEKaon.Fill( p4HNL.E(), acceptance * nimpwt );
486 hBKaon.Fill( betaMag, nimpwt );
487 break;
488 case kPdgK0L:
489 hENeuk.Fill( p4HNL.E(), acceptance * nimpwt );
490 hBNeuk.Fill( betaMag, nimpwt );
491 break;
492 case kPdgMuon:
493 hEMuon.Fill( p4HNL.E(), acceptance * nimpwt );
494 hBMuon.Fill( betaMag, nimpwt );
495 break;
496 }
497
498 LOG( "gevald_hnl", pDEBUG )
499 << " *** Output for event no " << ievent << "... ***"
500 << "\nparPDG = " << parPDG
501 << "\np4par = " << utils::print::P4AsString( &p4par ) << " [GeV] "
502 << "\nbetaVec = " << utils::print::Vec3AsString( &boost_beta )
503 << " : mag = " << betaMag
504 << "\np4HNL = " << utils::print::P4AsString( &p4HNL ) << " [GeV] "
505 << "\nx4HNL = " << utils::print::X4AsString( &x4HNL ) << " [cm]"
506 << "\nacceptance = " << acceptance << " : accCorr = " << accCorr
507 << "\nnimpwt = " << nimpwt
508 << "\nProduction channel = " << utils::hnl::ProdAsString( pChannel );
509
510 } // if not nonsense
511
512 // clean up
513 delete event;
514
515 ievent++;
516 }
517
518 // fill hCounters; each bin corresponds to the HNLProd_t with index iBin-1
519 hCounters.SetBinContent( 1, nPion2Muon );
520 hCounters.SetBinContent( 2, nPion2Electron );
521 hCounters.SetBinContent( 3, nKaon2Muon );
522 hCounters.SetBinContent( 4, nKaon2Electron );
523 hCounters.SetBinContent( 5, nKaon3Muon );
524 hCounters.SetBinContent( 6, nKaon3Electron );
525 hCounters.SetBinContent( 7, nNeuk3Muon );
526 hCounters.SetBinContent( 8, nNeuk3Electron );
527 hCounters.SetBinContent( 9, nMuon3Numu );
528 hCounters.SetBinContent( 10, nMuon3Nue );
529 hCounters.SetBinContent( 11, nMuon3Nutau );
530
531 hParamSpace.SetBinContent( 1, 1000.0 * gCfgMassHNL ); // MeV
532 hParamSpace.SetBinContent( 2, gCfgECoupling );
533 hParamSpace.SetBinContent( 3, gCfgMCoupling );
534 hParamSpace.SetBinContent( 4, gCfgTCoupling );
535 hParamSpace.SetBinContent( 5, nPOT );
536
537 fout->Write();
538 fout->Close();
539
540 return 0;
541}
542//............................................................................
543#endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX_
544//_________________________________________________________________________________________
545int TestDecay(void)
546{
547 string foutName("test_decay.root");
548
549 TFile * fout = TFile::Open( foutName.c_str(), "RECREATE" );
550
551 __attribute__((unused)) const EventRecordVisitorI * mcgen = HNLGenerator();
552 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
553 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
554
555 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
556 if (!geom_is_accessible) {
557 LOG("gevald_hnl", pFATAL)
558 << "The specified ROOT geometry doesn't exist! Initialization failed!";
559 exit(1);
560 }
561
562 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
563
564 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
565 assert( top_volume );
566 TGeoShape * ts = top_volume->GetShape();
567 __attribute__((unused)) TGeoBBox * box = (TGeoBBox *)ts;
568
569 LOG( "gevald_hnl", pDEBUG ) << "Imported box.";
570
571 const Algorithm * algVtxGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::VertexGenerator", "Default");
572
573 const VertexGenerator * vtxGen = dynamic_cast< const VertexGenerator * >( algVtxGen );
574 vtxGen->SetGeomFile( gOptRootGeom );
575
576 SimpleHNL sh = SimpleHNL( "HNLInstance", 0, kPdgHNL, kPdgKP,
578 std::map< HNLDecayMode_t, double > valMap = sh.GetValidChannels();
579 //const double CoMLifetime = sh.GetCoMLifetime();
580
581 assert( valMap.size() > 0 ); // must be able to decay to something!
582 assert( (*valMap.begin()).first == kHNLDcyNuNuNu );
583
584 LOG( "gevald_hnl", pINFO )
585 << "\n\nTesting decay modes for the HNL."
586 << "\nWill process gOptNev = " << gOptNev << " x ( N_channels = " << valMap.size()
587 << " ) = " << valMap.size() * gOptNev << " events, 1 for each valid channel."
588 << "\nWill produce 1 ROOT file ( " << foutName << " ) with:"
589 << "\n--> Energy spectrum for the decay products for each channel"
590 << "\n--> Rates of each decay channel";
591
592 // Set GHEP print level
593 GHepRecord::SetPrintLevel(RunOpt::Instance()->EventRecordPrintLevel());
594
595 // first set the 4-momentum of the HNL
596 //gOptEnergyHNL = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-Energy" );
597 gOptEnergyHNL = hnlgen->GetPGunEnergy();
598 double p3HNL = std::sqrt( gOptEnergyHNL * gOptEnergyHNL - gCfgMassHNL * gCfgMassHNL );
599 assert( p3HNL >= 0.0 );
600 TLorentzVector * p4HNL = new TLorentzVector( p3HNL * gCfgHNLCx,
601 p3HNL * gCfgHNLCy,
602 p3HNL * gCfgHNLCz, gOptEnergyHNL );
603
604 LOG( "gevald_hnl", pDEBUG )
605 << "\nUsing HNL with 4-momentum " << utils::print::P4AsString( p4HNL );
608
609 TLorentzVector * x4HNL = new TLorentzVector( 1.0, 2.0, 3.0, 0.0 ); // dummy
610
611 // now build array with indices of valid decay modes for speedy access
613 //double validRates[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
614 std::map< HNLDecayMode_t, double >::iterator vmit = valMap.begin(); int modeIdx = 0;
615 std::ostringstream msts;
616 for( ; vmit != valMap.end(); ++vmit ){
617 validModes[ modeIdx ] = (*vmit).first;
618 //validRates[ modeIdx ] = (*vmit).second;
619 msts << "\n" << utils::hnl::AsString( (*vmit).first );
620 modeIdx++;
621 }
622
623 LOG( "gevald_hnl", pDEBUG ) << "Here are the modes in order : " << msts.str();
624
625 // declare histos
626 // hSpectrum[i][j]: i iterates over HNLDecayMode_t, j over FS particle in same order as event record
627 TH1D hSpectrum[10][3], hCMSpectrum[10][3], hRates;
628 TH1D hParamSpace = TH1D( "hParamSpace", "Parameter space", 5, 0., 5. );
629
630 hParamSpace.SetBinContent( 1, 1000.0 * gCfgMassHNL ); // MeV
631 hParamSpace.SetBinContent( 2, gCfgECoupling );
632 hParamSpace.SetBinContent( 3, gCfgMCoupling );
633 hParamSpace.SetBinContent( 4, gCfgTCoupling );
634
635 hRates = TH1D( "hRates", "Rates of HNL decay channels", 10, 0, 10 );
636
637 std::string shortModes[10] = { "vvv", "vee", "vmue", "pi0v", "pie", "vmumu", "pimu", "pi0pi0v",
638 "pipi0e", "pipi0mu" };
639 std::string part0names[10] = { "v1", "v", "v", "pi0", "pi", "v", "pi", "pi01", "pi", "pi" };
640 std::string part1names[10] = { "v2", "e1", "mu", "v", "e", "mu1", "mu", "pi02", "pi0", "pi0" };
641 std::string part2names[10] = { "v3", "e2", "e", "None", "None", "mu2", "None", "v", "e", "mu" };
642 std::string partNames[3][10] = { part0names, part1names, part2names };
643 for( unsigned int iChan = 0; iChan < valMap.size(); iChan++ ){
644
645 std::string shortMode = shortModes[iChan];
646
647 for( Int_t iPart = 0; iPart < 3; iPart++ ){
648 std::string ParticleName = partNames[iPart][iChan];
649 if( strcmp( ParticleName.c_str(), "None" ) != 0 ){
650 hSpectrum[iChan][iPart] = TH1D( Form( "hSpectrum_%s_%s", shortMode.c_str(), ParticleName.c_str() ),
651 Form( "Fractional energy of particle: %s in decay: %s",
652 ParticleName.c_str(),
653 (utils::hnl::AsString( validModes[iChan] )).c_str() ),
654 100, 0., 1.0 );
655 hCMSpectrum[iChan][iPart] = TH1D( Form( "hCMSpectrum_%s_%s", shortMode.c_str(), ParticleName.c_str() ),
656 Form( "Rest frame energy of particle: %s in decay: %s",
657 ParticleName.c_str(),
658 (utils::hnl::AsString( validModes[iChan] )).c_str() ),
659 100, 0., gCfgMassHNL );
660 } // only declare histos of particles that exist in decay
661 // and are of allowed decays
662 }
663 }
664
665 // fill hRates now
666 double rnununu = ( (*valMap.find( kHNLDcyNuNuNu )) ).second;
667 double rnuee = ( valMap.find( kHNLDcyNuEE ) != valMap.end() ) ? (*(valMap.find( kHNLDcyNuEE ))).second : 0.0;
668 double rnumue = ( valMap.find( kHNLDcyNuMuE ) != valMap.end() ) ? (*(valMap.find( kHNLDcyNuMuE ))).second : 0.0;
669 double rpi0nu = ( valMap.find( kHNLDcyPi0Nu ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPi0Nu ))).second : 0.0;
670 double rpie = ( valMap.find( kHNLDcyPiE ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPiE ))).second : 0.0;
671 double rnumumu = ( valMap.find( kHNLDcyNuMuMu ) != valMap.end() ) ? (*(valMap.find( kHNLDcyNuMuMu ))).second : 0.0;
672 double rpimu = ( valMap.find( kHNLDcyPiMu ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPiMu ))).second : 0.0;
673 double rpi0pi0nu = ( valMap.find( kHNLDcyPi0Pi0Nu ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPi0Pi0Nu ))).second : 0.0;
674 double rpipi0e = ( valMap.find( kHNLDcyPiPi0E ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPiPi0E ))).second : 0.0;
675 double rpipi0mu = ( valMap.find( kHNLDcyPiPi0Mu ) != valMap.end() ) ? (*(valMap.find( kHNLDcyPiPi0Mu ))).second : 0.0;
676
677 hRates.SetBinContent( 1, rpimu );
678 hRates.SetBinContent( 2, rpie );
679 hRates.SetBinContent( 3, rpi0nu );
680 hRates.SetBinContent( 4, rnununu );
681 hRates.SetBinContent( 5, rnumumu );
682 hRates.SetBinContent( 6, rnuee );
683 hRates.SetBinContent( 7, rnumue );
684 hRates.SetBinContent( 8, rpipi0e );
685 hRates.SetBinContent( 9, rpipi0mu );
686 hRates.SetBinContent( 10, rpi0pi0nu );
687
688 int ievent = 0;
689 while( true ){
690
691 if( gOptNev >= 10000 ){
692 if( ievent % (gOptNev / 1000) == 0 ){
693 int irat = ievent / (gOptNev / 1000);
694 std::cerr << Form("%2.2f", 0.1 * irat) << " % ( " << ievent << " / "
695 << gOptNev << " ) \r" << std::flush;
696 }
697 } else if( gOptNev >= 100 ) {
698 if( ievent % (gOptNev / 10) == 0 ){
699 int irat = ievent / ( gOptNev / 10 );
700 std::cerr << 10.0 * irat << " % " << " ( " << ievent
701 << " / " << gOptNev << " ) \r" << std::flush;
702 }
703 }
704
705 if( ievent == gOptNev ){ std::cerr << " \n"; break; }
706
707 ostringstream asts;
708 for( unsigned int iMode = 0; iMode < valMap.size(); iMode++ ){
709 if( ievent == 0 ){
710 asts
711 << "\nDecay mode " << iMode << " is " << utils::hnl::AsString( validModes[ iMode ] );
712 }
713
714 // build an event
715 EventRecord * event = new EventRecord;
716 Interaction * interaction = Interaction::HNL( genie::kPdgHNL, gOptEnergyHNL, validModes[ iMode ] );
717 // set Particle(0) and a dummy vertex
718 GHepParticle ptHNL( kPdgHNL, kIStInitialState, -1, -1, -1, -1, *p4HNL, *x4HNL );
719 event->AddParticle( ptHNL );
720 interaction->InitStatePtr()->SetProbeP4( *p4HNL );
721 event->SetVertex( *x4HNL );
722
723 event->SetProbability( CoMLifetime );
724
725 event->AttachSummary( interaction );
726 LOG( "gevald_hnl", pDEBUG )
727 << "Simulating decay with mode "
728 << utils::hnl::AsString( (HNLDecayMode_t) interaction->ExclTag().DecayMode() );
729
730 // simulate the decay
731 hnlgen->ProcessEventRecord( event );
732
733 // now get a weight.
734 // = exp( - T_{box} / \tau_{HNL} ) = exp( - L_{box} / ( \beta_{HNL} \gamma_{HNL} c ) * h / \Gamma_{tot} )
735 // placing the HNL at a point configured by the user
736 std::vector< double > PGOrigin = hnlgen->GetPGunOrigin();
737 double ox = PGOrigin.at(0), oy = PGOrigin.at(1), oz = PGOrigin.at(2);
738 /*
739 double ox = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginX" );
740 double oy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginY" );
741 double oz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginZ" );
742 */
743 ox *= units::m / units::mm; oy *= units::m / units::mm; oz *= units::m / units::mm;
744 TVector3 startPoint( ox, oy, oz ); TVector3 entryPoint, exitPoint;
745 TLorentzVector tmpVtx( ox, oy, oz, 0.0 );
746 event->SetVertex( tmpVtx );
747
748 vtxGen->ProcessEventRecord(event);
749
750 LOG( "gevald_hnl", pDEBUG ) << *event;
751
752 // now fill the histos!
753 double wgt = event->Weight();
754 hSpectrum[iMode][0].Fill( (event->Particle(1))->E() / gOptEnergyHNL, wgt );
755 hSpectrum[iMode][1].Fill( (event->Particle(2))->E() / gOptEnergyHNL, wgt );
756 if( event->Particle(3) ) hSpectrum[iMode][2].Fill( (event->Particle(3))->E() / gOptEnergyHNL, wgt );
757
758 // let's also fill the CM spectra
759 // get particle 4-momenta and boost back to rest frame!
760 TLorentzVector * p4p1 = (event->Particle(1))->GetP4();
761 TLorentzVector * p4p2 = (event->Particle(2))->GetP4();
762 TLorentzVector * p4p3 = 0;
763 if( event->Particle(3) ) p4p3 = (event->Particle(3))->GetP4();
764
765 TVector3 boostVec = p4HNL->BoostVector();
766
767 p4p1->Boost( -boostVec );
768 p4p2->Boost( -boostVec );
769 if( p4p3 ) p4p3->Boost( -boostVec );
770
771 hCMSpectrum[iMode][0].Fill( p4p1->E(), wgt );
772 hCMSpectrum[iMode][1].Fill( p4p2->E(), wgt );
773 if( p4p3 ) hCMSpectrum[iMode][2].Fill( p4p3->E(), wgt );
774
775 // clean-up
776 delete event;
777
778 } // loop over valid decay channels
779
780 if( ievent == 0 ) LOG( "gevald_hnl", pDEBUG ) << asts.str();
781 LOG( "gevald_hnl", pDEBUG ) << "Finished event: " << ievent;
782
783 ievent++;
784
785 } // event loop
786
787 fout->cd();
788 hParamSpace.Write();
789 hRates.Write();
790 for( unsigned int i = 0; i < valMap.size(); i++ ){
791 for( Int_t j = 0; j < 3; j++ ){
792 std::string ParticleName = partNames[j][i];
793 if( strcmp( ParticleName.c_str(), "None" ) != 0 ){
794 hSpectrum[i][j].Write();
795 hCMSpectrum[i][j].Write();
796 }
797 }
798 }
799 fout->Write();
800 fout->Close();
801
802 delete p4HNL;
803 delete x4HNL;
804 return 0;
805}
806//............................................................................
807#ifdef __CAN_USE_ROOT_GEOM__
808//_________________________________________________________________________________________
809int TestGeom(void)
810{
811 string foutName("test_geom.root");
812
813 TFile * fout = TFile::Open( foutName.c_str(), "RECREATE" );
814
815 LOG( "gevald_hnl", pINFO )
816 << "\n\nTesting ROOT geometry for ROOT file " << gOptRootGeom
817 << "\nWill produce 1 ROOT file ( " << foutName << " ) with:"
818 << "\n--> Specified geometry"
819 << "\n--> TTree containing the following branch structure:"
820 << "\n |"
821 << "\n |---- start x,y,z [mm]"
822 << "\n |"
823 << "\n |---- HNL 4-momentum [GeV]"
824 << "\n |"
825 << "\n |---- did intersect detector?"
826 << "\n |"
827 << "\n |---- entry x,y,z [mm]"
828 << "\n |"
829 << "\n |---- exit x,y,z [mm]"
830 << "\n |"
831 << "\n |---- weight"
832 << "\n |"
833 << "\n |---- HNL lifetime (rest frame) [ns]"
834 << "\n |"
835 << "\n |---- HNL lifetime (lab frame) [ns]"
836 << "\n |"
837 << "\n |---- decay x,y,z [mm]"
838 << "\n--> Weight histogram"
839 << "\n--> Travel-length histogram"
840 << "\n"
841 << "\n(where same coordinate system as user's is used and weight == P(HNL decays in detector) )";
842
843 double dev_start[3] = { -9999.9, -9999.9, -9999.9 };
844 double dev_sphere[2] = { -9999.9, -9999.9 };
845 double use_start[3] = { -9999.9, -9999.9, -9999.9 };
846 double use_entry[3] = { -9999.9, -9999.9, -9999.9 };
847 double use_exit[3] = { -9999.9, -9999.9, -9999.9 };
848 double use_decay[3] = { -9999.9, -9999.9, -9999.9 };
849 double use_momentum[4] = { -9999.9, -9999.9, -9999.9, -9999.9 };
850 double use_wgt = -9999.9;
851 double use_lifetime = -9999.9, use_CMlifetime = -9999.9;
852 bool didIntersectDet = false;
853
854 TTree * outTree = new TTree( "outTree", "Trajectory information tree" );
855 outTree->Branch( "startPoint", use_start, "startPoint[3]/D" );
856 outTree->Branch( "fourMomentum", use_momentum, "fourMomentum[4]/D" );
857 outTree->Branch( "startDeviate", dev_start, "startDeviate[3]/D" );
858 outTree->Branch( "spherDeviate", dev_sphere, "spherDeviate[2]/D" );
859 outTree->Branch( "didIntersect", &didIntersectDet, "didIntersect/O" );
860 outTree->Branch( "entryPoint", use_entry, "entryPoint[3]/D" );
861 outTree->Branch( "exitPoint", use_exit, "exitPoint[3]/D" );
862 outTree->Branch( "decayPoint", use_decay, "decayPoint[3]/D" );
863 outTree->Branch( "weight", &use_wgt, "weight/D" );
864 outTree->Branch( "lifetime_LAB", &use_lifetime, "lifetime_LAB/D" );
865 outTree->Branch( "lifetime_CM", &use_CMlifetime, "lifetime_CM/D" );
866
867 TH1D hWeight( "hWeight", "Log_{10} ( P( decay in detector ) )",
868 160, -15.0, 1.0 );
869 TH1D hLength( "hLength", "Length travelled in detector / max possible length in detector",
870 100, 0., 1.0 );
871
872 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
873 if (!geom_is_accessible) {
874 LOG("gevald_hnl", pFATAL)
875 << "The specified ROOT geometry doesn't exist! Initialization failed!";
876 exit(1);
877 }
878
879 gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
880 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
881 assert( top_volume );
882
883 // Read geometry bounding box - for vertex position generation
884 InitBoundingBox();
885
886 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
887 const Algorithm * algVtxGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::VertexGenerator", "Default");
888
889 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
890 const VertexGenerator * vtxGen = dynamic_cast< const VertexGenerator * >( algVtxGen );
891 vtxGen->SetGeomFile( gOptRootGeom );
892
893 // get SimpleHNL for lifetime
894 SimpleHNL sh = SimpleHNL( "HNLInstance", 0, kPdgHNL, kPdgKP,
896
897 // first set the 4-momentum of the HNL
898 //gOptEnergyHNL = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-Energy" );
899 gOptEnergyHNL = hnlgen->GetPGunEnergy();
900 double p3HNL = std::sqrt( gOptEnergyHNL * gOptEnergyHNL - gCfgMassHNL * gCfgMassHNL );
901 assert( p3HNL >= 0.0 );
902 TLorentzVector * p4HNL = new TLorentzVector( p3HNL * gCfgHNLCx,
903 p3HNL * gCfgHNLCy,
904 p3HNL * gCfgHNLCz, gOptEnergyHNL );
905
906 LOG( "gevald_hnl", pDEBUG )
907 << "\nUsing HNL with 4-momentum " << utils::print::P4AsString( p4HNL );
910
911 double betaMag = p4HNL->P() / p4HNL->E();
912 __attribute__((unused)) double gamma = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
913
914 use_CMlifetime = CoMLifetime / ( units::ns * units::GeV );
915 //sh.GetCoMLifetime() / ( units::ns * units::GeV );
916 use_lifetime = sh.GetLifetime() / ( units::ns * units::GeV ); // ns
917
918 std::vector< double > PGOrigin = hnlgen->GetPGunOrigin();
919 std::vector< double > PGDOrigin = hnlgen->GetPGunDOrigin();
920
921 const double PGox = PGOrigin.at(0), PGoy = PGOrigin.at(1), PGoz = PGOrigin.at(2);
922 const double PGdx = PGDOrigin.at(0), PGdy = PGDOrigin.at(1), PGdz = PGDOrigin.at(2);
923
924 /*
925 const double PGox = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginX" );
926 const double PGoy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginY" );
927 const double PGoz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginZ" ); // m
928
929 const double PGdx = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDX" );
930 const double PGdy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDY" );
931 const double PGdz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDZ" ); // m
932 */
933 assert( PGdx > 0.0 && PGdy > 0.0 && PGdz > 0.0 );
934
935 double c2 = std::sqrt( std::pow( gCfgHNLCx, 2.0 ) + std::pow( gCfgHNLCy, 2.0 ) + std::pow( gCfgHNLCz, 2.0 ) );
936 const double PGcx = gCfgHNLCx / c2;
937 const double PGcy = gCfgHNLCy / c2;
938 const double PGcz = gCfgHNLCz / c2; // unit-normalised
939
940 const double PGtheta = std::acos( PGcz );
941 const double PGphi = ( std::sin( PGtheta ) < controls::kASmallNum ) ? 0.0 :
942 ( PGcy >= 0.0 ) ? std::acos( PGcx / PGcz ) : 2.0 * constants::kPi - std::acos( PGcx / PGcz );
943
944 std::vector< double > PGDeviation = hnlgen->GetPGunDeviation();
945 const double PGdtheta = PGDeviation.at(0) * constants::kPi / 180.0; // rad
946 const double PGdphi = PGDeviation.at(1) * constants::kPi / 180.0; // rad
947 /*
948 const double PGdtheta = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-DTheta" ) * constants::kPi / 180.0;
949 const double PGdphi = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-DPhi" ) * constants::kPi / 180.0; // rad
950 */
951
952 /*
953 * The event loop works out a bit differently here.
954 * It reads in the origin point and momentum from file and treats them as CV
955 * Then it partitions each axis in R^3 (x-y-z, for origin position) and R^2 (theta-phi, for
956 * origin momentum) into either 5 points (x,y,z) or 9 points (theta, phi)
957 * There is exactly one trajectory that matches both origin position and momentum.
958 * For each of these trajectories, the entry and exit points are calculated.
959 * The length to decay is also calculated and a histo is filled with L(to decay) / L(max).
960 */
961
962 // first make the points
963 const int NCARTESIAN = 5;
964 const int NSPHERICAL = 9;
965 const int NMAX = NCARTESIAN * NCARTESIAN * NCARTESIAN * NSPHERICAL * NSPHERICAL;
966
967 double arr_ox[ NCARTESIAN ] = { PGox - PGdx, PGox - PGdx/2.0, PGox, PGox + PGdx/2.0, PGox + PGdx };
968 double arr_oy[ NCARTESIAN ] = { PGoy - PGdy, PGoy - PGdy/2.0, PGoy, PGoy + PGdy/2.0, PGoy + PGdy };
969 double arr_oz[ NCARTESIAN ] = { PGoz - PGdz, PGoz - PGdz/2.0, PGoz, PGoz + PGdz/2.0, PGoz + PGdz };
970
971 double arr_theta[ NSPHERICAL ] = { PGtheta - PGdtheta, PGtheta - 3.0/4.0 * PGdtheta, PGtheta - 1.0/2.0 * PGdtheta, PGtheta - 1.0/4.0 * PGdtheta, PGtheta, PGtheta + 1.0/4.0 * PGdtheta, PGtheta + 1.0/2.0 * PGdtheta, PGtheta + 3.0/4.0 * PGdtheta, PGtheta + PGdtheta };
972 double arr_phi[ NSPHERICAL ] = { PGphi - PGdphi, PGphi - 3.0/4.0 * PGdphi, PGphi - 1.0/2.0 * PGdphi, PGphi - 1.0/4.0 * PGdphi, PGphi, PGphi + 1.0/4.0 * PGdphi, PGphi + 1.0/2.0 * PGdphi, PGphi + 3.0/4.0 * PGdphi, PGphi + PGdphi };
973
974 // so now we have NCARTESIAN ^3 x NSPHERICAL ^2 points to iterate over. That's 10125 events for 5 and 9
975
976 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
977
978 TGeoShape * ts = top_volume->GetShape();
979 __attribute__((unused)) TGeoBBox * box = (TGeoBBox *)ts;
980
981 int ievent = 0;
982 ostringstream asts;
983 while( true ){
984
985 if( ievent == NMAX ) break;
986
987 LOG( "gevald_hnl", pDEBUG )
988 << "*** Building event = " << ievent;
989
990 EventRecord * event = new EventRecord;
992 event->SetProbability( CoMLifetime );
993 event->AttachSummary( interaction );
994
995 /*
996 * Iterate over events as follows:
997 * Least significant --> most significant (with period in brackets)
998 * ox (NCART) --> oy (NCART) --> oz (NCART) --> phi (NSPHE) --> theta (NSPHE)
999 */
1000
1001 int ix = ievent % NCARTESIAN;
1002 int iy = ( ievent / NCARTESIAN ) % NCARTESIAN;
1003 int iz = ( ievent / NCARTESIAN / NCARTESIAN ) % NCARTESIAN;
1004 int ip = ( ievent / NCARTESIAN / NCARTESIAN / NCARTESIAN ) % NSPHERICAL;
1005 int it = ( ievent / NCARTESIAN / NCARTESIAN / NCARTESIAN / NSPHERICAL ) % NSPHERICAL;
1006
1007 double use_ox = arr_ox[ ix ] * units::m / units::mm;
1008 double use_oy = arr_oy[ iy ] * units::m / units::mm;
1009 double use_oz = arr_oz[ iz ] * units::m / units::mm;
1010
1011 dev_start[0] = use_ox - PGox * units::m / units::mm;
1012 dev_start[1] = use_oy - PGoy * units::m / units::mm;
1013 dev_start[2] = use_oz - PGoz * units::m / units::mm;
1014
1015 double use_theta = arr_theta[ it ];
1016 double use_phi = arr_phi[ ip ];
1017
1018 dev_sphere[0] = (use_theta - PGtheta) * 180.0 / constants::kPi; // deg
1019 dev_sphere[1] = (use_phi - PGphi) * 180.0 / constants::kPi;
1020
1021 double use_cx = std::cos( use_phi ) * std::sin( use_theta );
1022 double use_cy = std::sin( use_phi ) * std::sin( use_theta );
1023 double use_cz = std::cos( use_theta );
1024
1025 // now, we set the correct start point and momentum.
1026 p4HNL->SetPxPyPzE( p3HNL * use_cx, p3HNL * use_cy, p3HNL * use_cz, gOptEnergyHNL );
1027
1028 TVector3 startPoint, momentum;
1029 TVector3 entryPoint, exitPoint, decayPoint;
1030
1031 startPoint.SetXYZ( use_ox, use_oy, use_oz );
1032 momentum.SetXYZ( p4HNL->Px(), p4HNL->Py(), p4HNL->Pz() );
1033
1034 use_start[0] = use_ox;
1035 use_start[1] = use_oy;
1036 use_start[2] = use_oz;
1037
1038 use_momentum[0] = p4HNL->Px();
1039 use_momentum[1] = p4HNL->Py();
1040 use_momentum[2] = p4HNL->Pz();
1041 use_momentum[3] = p4HNL->E();
1042
1043 LOG( "gevald_hnl", pDEBUG )
1044 << "Set start point for this trajectory = " << utils::print::Vec3AsString( &startPoint )
1045 << " [mm]";
1046 LOG( "gevald_hnl", pDEBUG )
1047 << "Set momentum for this trajectory = " << utils::print::Vec3AsString( &momentum )
1048 << " [GeV/c]";
1049
1050 TLorentzVector tmpVtx( use_ox, use_oy, use_oz, 0.0);
1051 event->SetVertex( tmpVtx );
1052 TLorentzVector tmpMom = *p4HNL;
1053 GHepParticle ptHNL( genie::kPdgHNL, kIStInitialState, -1, -1, -1, -1, tmpMom, tmpVtx );
1054 event->AddParticle( ptHNL );
1055 LOG( "gevald_hnl", pDEBUG )
1056 << "\nProbe p4 = " << utils::print::P4AsString( event->Particle(0)->P4() );
1057
1058 vtxGen->ProcessEventRecord(event);
1059
1060 if( event->Vertex()->T() != -999.9 ){
1061 decayPoint.SetXYZ( event->Vertex()->X(), event->Vertex()->Y(), event->Vertex()->Z() );
1062 entryPoint.SetXYZ( event->Particle(1)->Vx(), event->Particle(1)->Vy(), event->Particle(1)->Vz() );
1063 exitPoint.SetXYZ( event->Particle(2)->Vx(), event->Particle(2)->Vy(), event->Particle(2)->Vz() );
1064 use_wgt = event->Weight();
1065
1066 // set the branch entries now
1067 use_entry[0] = entryPoint.X();
1068 use_entry[1] = entryPoint.Y();
1069 use_entry[2] = entryPoint.Z();
1070
1071 use_exit[0] = exitPoint.X();
1072 use_exit[1] = exitPoint.Y();
1073 use_exit[2] = exitPoint.Z();
1074
1075 use_decay[0] = decayPoint.X();
1076 use_decay[1] = decayPoint.Y();
1077 use_decay[2] = decayPoint.Z();
1078
1079 double devX = decayPoint.X() * units::m / units::mm - entryPoint.X();
1080 double devY = decayPoint.Y() * units::m / units::mm - entryPoint.Y();
1081 double devZ = decayPoint.Z() * units::m / units::mm - entryPoint.Z();
1082
1083 double mdeX = exitPoint.X() - entryPoint.X();
1084 double mdeY = exitPoint.Y() - entryPoint.Y();
1085 double mdeZ = exitPoint.Z() - entryPoint.Z();
1086
1087 double elapsedLength = std::sqrt( devX * devX + devY * devY + devZ * devZ );
1088 double maxLength = std::sqrt( mdeX * mdeX + mdeY * mdeY + mdeZ * mdeZ );
1089
1090 // also fill the histos
1091 hWeight.Fill( -1.0 * std::log10( use_wgt ), 1.0 );
1092 hLength.Fill( elapsedLength / maxLength );
1093 didIntersectDet = true;
1094
1095 } else { // didn't intersect vertex, use nonsense
1096
1097 use_entry[0] = -999.9;
1098 use_entry[1] = -999.9;
1099 use_entry[2] = -999.9;
1100
1101 use_exit[0] = -999.9;
1102 use_exit[1] = -999.9;
1103 use_exit[2] = -999.9;
1104
1105 use_decay[0] = -999.9;
1106 use_decay[1] = -999.9;
1107 use_decay[2] = -999.9;
1108
1109 didIntersectDet = false;
1110 }
1111 outTree->Fill();
1112 ievent++;
1113 }
1114
1115 // save to file and exit
1116
1117 fout->cd();
1118 outTree->Write();
1119 hWeight.Write();
1120 hLength.Write();
1121 //top_volume->Write();
1122 fout->Close();
1123
1124 return 0;
1125}
1126//_________________________________________________________________________________________
1127void InitBoundingBox(void)
1128{
1129// Initialise geometry bounding box, used for generating HNL vertex positions
1130
1131 LOG("gevald_hnl", pINFO)
1132 << "Initialising geometry bounding box.";
1133
1134 fdx = 0; // half-length - x
1135 fdy = 0; // half-length - y
1136 fdz = 0; // half-length - z
1137 fox = 0; // origin - x
1138 foy = 0; // origin - y
1139 foz = 0; // origin - z
1140
1141 if(!gOptUsingRootGeom) return;
1142
1143 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
1144 if (!geom_is_accessible) {
1145 LOG("gevald_hnl", pFATAL)
1146 << "The specified ROOT geometry doesn't exist! Initialization failed!";
1147 exit(1);
1148 }
1149
1150 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
1151
1152 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
1153 assert( top_volume );
1154 TGeoShape * ts = top_volume->GetShape();
1155 TGeoBBox * box = (TGeoBBox *)ts;
1156
1157 //get box origin and dimensions (in the same units as the geometry)
1158 fdx = box->GetDX();
1159 fdy = box->GetDY();
1160 fdz = box->GetDZ();
1161 fox = (box->GetOrigin())[0];
1162 foy = (box->GetOrigin())[1];
1163 foz = (box->GetOrigin())[2];
1164
1165 LOG("gevald_hnl", pINFO)
1166 << "Before conversion the bounding box has:"
1167 << "\nOrigin = ( " << fox << " , " << foy << " , " << foz << " )"
1168 << "\nDimensions = " << fdx << " x " << fdy << " x " << fdz
1169 << "\n1cm = 1.0 unit";
1170
1171 // Convert from local to SI units
1178
1179 LOG("gevald_hnl", pINFO)
1180 << "Initialised bounding box successfully.";
1181
1182}
1183//_________________________________________________________________________________________
1184#endif // #ifdef __CAN_USE_ROOT_GEOM__
1185//............................................................................
1186//_________________________________________________________________________________________
1188{
1189 //string sname = "genie::EventGenerator";
1190 //string sconfig = "BeamHNL";
1192
1193 LOG("gevald_hnl", pINFO)
1194 << "Instantiating HNL generator.";
1195
1196 const Algorithm * algmcgen = algf->GetAlgorithm(kDefOptSName, kDefOptSConfig);
1197 LOG("gevald_hnl", pDEBUG)
1198 << "Got algorithm " << kDefOptSName.c_str() << "/" << kDefOptSConfig.c_str();;
1199
1200 const EventRecordVisitorI * mcgen =
1201 dynamic_cast< const EventRecordVisitorI * >( algmcgen );
1202 if(!mcgen) {
1203 LOG("gevald_hnl", pFATAL) << "Couldn't instantiate the HNL generator";
1204 gAbortingInErr = true;
1205 exit(1);
1206 }
1207
1208 LOG("gevald_hnl", pINFO)
1209 << "HNL generator instantiated successfully.";
1210
1211 return mcgen;
1212}
1213//_________________________________________________________________________________________
1214void GetCommandLineArgs(int argc, char ** argv)
1215{
1216 LOG("gevald_hnl", pINFO) << "Parsing command line arguments";
1217
1218 // Parse run options for this app
1219
1220 CmdLnArgParser parser(argc,argv);
1221
1222 // help?
1223 bool help = parser.OptionExists('h');
1224 if(help) {
1225 PrintSyntax();
1226 exit(0);
1227 }
1228
1229 // force the app to look at HNL tune by default
1230 // if user passes --tune argument, look at the user input tune instead
1231 char * expargv[ argc + 2 ];
1232 bool didFindUserInputTune = false;
1233 std::string stExtraTuneBit = kDefOptSTune;
1234
1235 if( parser.OptionExists("tune") ){
1236 didFindUserInputTune = true;
1237 stExtraTuneBit = parser.ArgAsString("tune");
1238 LOG( "gevgen_hnl", pWARN )
1239 << "Using input HNL tune " << parser.ArgAsString("tune");
1240 } else {
1241 LOG( "gevgen_hnl", pWARN )
1242 << "Using default HNL tune " << kDefOptSTune;
1243 }
1244 // append this to argv
1245 for( int iArg = 0; iArg < argc; iArg++ ){
1246 expargv[iArg] = argv[iArg];
1247 }
1248 if( !didFindUserInputTune ){
1249 char * chBit = const_cast< char * >( stExtraTuneBit.c_str() ); // ugh. Ugly.
1250 std::string stune("--tune"); char * tBit = const_cast< char * >( stune.c_str() );
1251 expargv[argc] = tBit;
1252 expargv[argc+1] = chBit;
1253 }
1254
1255 // Common run options.
1256 int expargc = ( didFindUserInputTune ) ? argc : argc+2;
1257 std::string stnull(""); char * nBit = const_cast< char * >( stnull.c_str() );
1258 expargv[expargc] = nBit;
1259
1260 RunOpt::Instance()->ReadFromCommandLine(expargc,expargv);
1261
1262 // run number
1263 if( parser.OptionExists('r') ) {
1264 LOG("gevald_hnl", pDEBUG) << "Reading MC run number";
1265 gOptRunNu = parser.ArgAsLong('r');
1266 } else {
1267 LOG("gevald_hnl", pDEBUG) << "Unspecified run number - Using default";
1268 gOptRunNu = 1000;
1269 } //-r
1270
1271 // number of events
1272 if( parser.OptionExists('n') ) {
1273 LOG("gevald_hnl", pDEBUG)
1274 << "Reading number of events to generate";
1275 gOptNev = parser.ArgAsInt('n');
1276 } else {
1277 LOG("gevald_hnl", pFATAL)
1278 << "You need to specify the number of events";
1279 PrintSyntax();
1280 exit(0);
1281 } //-n
1282
1283 if( parser.OptionExists('M') ) {
1284 LOG("gevald_hnl", pDEBUG)
1285 << "Detecting mode. . .";
1287 } else {
1288 LOG("gevald_hnl", pFATAL)
1289 << "You must specify a validation mode.";
1290 PrintSyntax();
1291 exit(0);
1292 } // -M
1293
1294 bool isMonoEnergeticFlux = true;
1295#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
1296 if( parser.OptionExists('f') ) {
1297 LOG("gevald_hnl", pDEBUG)
1298 << "A flux has been offered. Searching this path: " << parser.ArgAsString('f');
1299 isMonoEnergeticFlux = false;
1300 gOptFluxFilePath = parser.ArgAsString('f');
1301
1302 // check if this is dk2nu
1303 //if( gOptFluxFilePath.find( "dk2nu" ) != string::npos ){
1304 if( gSystem->OpenDirectory( gOptFluxFilePath.c_str() ) != NULL ){
1305 gOptIsUsingDk2nu = true;
1306 LOG("gevald_hnl", pDEBUG)
1307 << "dk2nu flux files detected. Will create flux spectrum dynamically.";
1308 } else {
1309 LOG("gevald_hnl", pFATAL)
1310 << "Invalid flux file path " << gOptFluxFilePath;
1311 exit(1);
1312 }
1313 } else {
1314 // we need the 'E' option! Log it and pass below
1315 LOG("gevald_hnl", pINFO)
1316 << "No flux file offered. Assuming monoenergetic flux.";
1317 } //-f
1318 gOptIsMonoEnFlux = isMonoEnergeticFlux;
1319#endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
1320
1321#ifdef __CAN_USE_ROOT_GEOM__
1322 if( parser.OptionExists('g') ) {
1323 LOG("gevald_hnl", pDEBUG) << "Getting input geometry";
1324 geom = parser.ArgAsString('g');
1325
1326 // is it a ROOT file that contains a ROOT geometry?
1327 bool accessible_geom_file =
1328 ! (gSystem->AccessPathName(geom.c_str()));
1329 if (accessible_geom_file) {
1331 gOptUsingRootGeom = true;
1332 } else {
1333 LOG("gevald_hnl", pFATAL)
1334 << "Geometry option is not a ROOT file. Please use ROOT geom.";
1335 PrintSyntax();
1336 exit(1);
1337 }
1338 } else if( gOptValidationMode == kValGeom ) {
1339
1340 LOG("gevald_hnl", pFATAL)
1341 << "No geometry option specified - Exiting";
1342 PrintSyntax();
1343 exit(1);
1344 } //-g
1345
1346 if( parser.OptionExists('L') ) {
1347 lunits = parser.ArgAsString('L');
1348 LOG("gevald_hnl", pDEBUG) << "Setting length units to " << lunits.c_str();
1349 } else {
1350 LOG("gevald_hnl", pDEBUG) << "Using default geometry length units";
1352 } // -L
1354
1355 if( parser.OptionExists('A') ) {
1356 aunits = parser.ArgAsString('A');
1357 LOG("gevald_hnl", pDEBUG) << "Setting angle units to " << aunits.c_str();
1358 } else {
1359 LOG("gevald_hnl", pDEBUG) << "Using default angle length units";
1361 } // -A
1363
1364 if( parser.OptionExists('T') ) {
1365 tunits = parser.ArgAsString('T');
1366 LOG("gevald_hnl", pDEBUG) << "Setting time units to " << tunits.c_str();
1367 } else {
1368 LOG("gevald_hnl", pDEBUG) << "Using default geometry time units";
1370 } // -T
1372
1373#endif // #ifdef __CAN_USE_ROOT_GEOM__
1374
1375 // event file prefix
1376 if( parser.OptionExists('o') ) {
1377 LOG("gevald_hnl", pDEBUG) << "Reading the event filename prefix";
1378 gOptEvFilePrefix = parser.ArgAsString('o');
1379 } else {
1380 LOG("gevald_hnl", pDEBUG)
1381 << "Will set the default event filename prefix";
1383 } //-o
1384
1385 // random number seed
1386 if( parser.OptionExists("seed") ) {
1387 LOG("gevald_hnl", pINFO) << "Reading random number seed";
1388 gOptRanSeed = parser.ArgAsLong("seed");
1389 } else {
1390 LOG("gevald_hnl", pINFO) << "Unspecified random number seed - Using default";
1391 gOptRanSeed = -1;
1392 }
1393
1394 //
1395 // >>> print the command line options
1396 //
1397
1398 ostringstream gminfo;
1399 if (gOptUsingRootGeom) {
1400 gminfo << "Using ROOT geometry - file: " << gOptRootGeom
1401 << ", top volume: "
1402 << ((gOptRootGeomTopVol.size()==0) ? "<master volume>" : gOptRootGeomTopVol)
1403 << ", length units: " << lunits;
1404 // << ", density units: " << dunits;
1405 }
1406
1407 LOG("gevald_hnl", pNOTICE)
1408 << "\n\n"
1409 << utils::print::PrintFramedMesg("gevald_hnl job configuration");
1410
1411 LOG("gevald_hnl", pNOTICE)
1412 << "\n @@ Run number : " << gOptRunNu
1413 << "\n @@ Random seed : " << gOptRanSeed
1414 << "\n @@ HNL mass : " << gCfgMassHNL << " GeV"
1415 << "\n @@ Decay channel : " << utils::hnl::AsString(gCfgDecayMode)
1416 << "\n @@ Flux path : " << gOptFluxFilePath
1417 << "\n @@ Geometry : " << gminfo.str()
1418 << "\n @@ Statistics : " << gOptNev << " events";
1419}
1420//_________________________________________________________________________________________
1422{
1423 LOG("gevald_hnl", pFATAL)
1424 << "Reading in validation configuration. . .";
1425
1426 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
1427 __attribute__((unused)) const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
1428
1429 CoMLifetime = hnlgen->GetHNLLifetime();
1430
1431 gCfgMassHNL = hnlgen->GetHNLMass();
1432 std::vector<double> U4l2s = hnlgen->GetHNLCouplings();
1433 gCfgECoupling = U4l2s.at(0);
1434 gCfgMCoupling = U4l2s.at(1);
1435 gCfgTCoupling = U4l2s.at(2);
1436 gCfgIsMajorana = hnlgen->IsHNLMajorana();
1437
1438 //gOptEnergyHNL = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-Energy" );
1439 gOptEnergyHNL = hnlgen->GetPGunEnergy();
1440
1441 std::vector< double > PGDirection = hnlgen->GetPGunDirection();
1442 gCfgHNLCx = PGDirection.at(0), gCfgHNLCy = PGDirection.at(1), gCfgHNLCz = PGDirection.at(2);
1443 /*
1444 gCfgHNLCx = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cx" );
1445 gCfgHNLCy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cy" );
1446 gCfgHNLCz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cz" );
1447 */
1448
1449 double dircosMag2 = std::pow( gCfgHNLCx, 2.0 ) +
1450 std::pow( gCfgHNLCy, 2.0 ) +
1451 std::pow( gCfgHNLCz, 2.0 );
1452 double invdircosmag = 1.0 / std::sqrt( dircosMag2 );
1453 gCfgHNLCx *= invdircosmag;
1454 gCfgHNLCy *= invdircosmag;
1455 gCfgHNLCz *= invdircosmag;
1456
1457 std::string stIntChannels = hnlgen->GetHNLInterestingChannels(); int iChan = -1;
1458 if( gCfgIntChannels.size() > 0 ) gCfgIntChannels.clear();
1459 while( stIntChannels.size() > 0 ){ // read channels from right (lowest mass) to left (highest mass)
1460 iChan++;
1461 HNLDecayMode_t md = static_cast< HNLDecayMode_t >( iChan );
1462 std::string tmpSt = stIntChannels.substr( stIntChannels.size()-1, stIntChannels.size() );
1463 if( std::strcmp( tmpSt.c_str(), "1" ) == 0 )
1464 gCfgIntChannels.emplace_back( md );
1465
1466 stIntChannels.erase( stIntChannels.end()-1, stIntChannels.end() );
1467 }
1468
1469 const Algorithm * algFluxCreator = AlgFactory::Instance()->GetAlgorithm("genie::hnl::FluxCreator", "Default");
1470 __attribute__((unused)) const FluxCreator * fluxCreator = dynamic_cast< const FluxCreator * >( algFluxCreator );
1471
1472 std::vector< double > b2uTranslation = fluxCreator->GetB2UTranslation();
1473 gCfgUserOx = b2uTranslation.at(0); gCfgUserOy = b2uTranslation.at(1); gCfgUserOz = b2uTranslation.at(2);
1474 std::vector< double > b2uRotation = fluxCreator->GetB2URotation();
1475 gCfgUserAx1 = b2uRotation.at(0); gCfgUserAz = b2uRotation.at(1); gCfgUserAx2 = b2uRotation.at(2);
1476
1477 // now transform the lengths and angles to the correct units
1481
1485
1486 ostringstream csts;
1487 csts << "Read out the following config:"
1488 << "\n"
1489 << "\nHNL mass = " << gCfgMassHNL << " [GeV]"
1490 << "\n|U_e4|^2 = " << gCfgECoupling
1491 << "\n|U_m4|^2 = " << gCfgMCoupling
1492 << "\n|U_t4|^2 = " << gCfgTCoupling
1493 << "\n"
1494 << "\nInteresting decay channels:";
1495 for( std::vector< HNLDecayMode_t >::iterator chit = gCfgIntChannels.begin();
1496 chit != gCfgIntChannels.end(); ++chit ){ csts << "\n\t" << utils::hnl::AsString(*chit); }
1497 csts << "\n"
1498 << "\nUser origin in beam coordinates = ( " << gCfgUserOx
1499 << ", " << gCfgUserOy << ", " << gCfgUserOz << " ) [" << lunits.c_str() << "]"
1500 << "\nEuler extrinsic x-z-x rotation = ( " << gCfgUserAx1
1501 << ", " << gCfgUserAz << ", " << gCfgUserAx2 << " ) [" << aunits.c_str() << "]"
1502 << "\nHNL particle-gun directional cosines: ( " << gCfgHNLCx << ", " << gCfgHNLCy
1503 << ", " << gCfgHNLCz << ") [ GeV / GeV ]";
1504
1505 LOG("gevald_hnl", pDEBUG) << csts.str();
1506
1507}
1508//_________________________________________________________________________________________
1509void PrintSyntax(void)
1510{
1511 LOG("gevald_hnl", pFATAL)
1512 << "\n **Syntax**"
1513 << "\n gevald_hnl [-h] "
1514 << "\n [-r run#]"
1515 << "\n -n n_of_events"
1516 << "\n [-f path_to_flux_files]"
1517 << "\n [-g geometry_file]"
1518 << "\n -M mode:"
1519 << "\n 1: Flux prediction from dk2nu files. Needs -f option"
1520 << "\n 2: HNL decay validation. Specify an origin point and 4-momentum"
1521 << "\n in the \"ParticleGun\" section in config. Needs -g option."
1522 << "\n 3: Custom geometry file validation. Needs -g option"
1523 << "\n Specify origin, momentum, and wiggle room for both of these in the"
1524 << "\n \"ParticleGun\" section in config"
1525 << "\n Regardless of how many events you ask for, this will evaluate 125x81"
1526 << "\n events: 5^3 from wiggling origin and 9^2 from wiggling momentum direction"
1527 << "\n 4: Full simulation (like gevgen_hnl but with lots of debug!)"
1528 << "\n"
1529 << "\n The configuration file lives at $GENIE/config/CommonHNL.xml - see"
1530 << " <param_set name=\"Validation\">"
1531 << "\n"
1532 << "\n Please also read the detailed documentation at http://www.genie-mc.org"
1533 << "\n or look at the source code: $GENIE/src/Apps/gBeamHNLValidationApp.cxx"
1534 << "\n";
1535}
1536//_________________________________________________________________________________________
#define pNOTICE
Definition Messenger.h:61
#define pINFO
Definition Messenger.h:62
#define pFATAL
Definition Messenger.h:56
#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.
int main()
The GENIE Algorithm Factory.
Definition AlgFactory.h:39
const Algorithm * GetAlgorithm(const AlgId &algid)
static AlgFactory * Instance()
Algorithm abstract base class.
Definition Algorithm.h:54
Command line argument parser.
string ArgAsString(char opt)
bool OptionExists(char opt)
was option set?
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the 'Visito...
Generated Event Record. It is a GHepRecord object that can accept / be visited by EventRecordVisitorI...
Definition EventRecord.h:37
STDHEP-like event record entry that can fit a particle or a nucleus.
virtual void SetXSec(double xsec)
Definition GHepRecord.h:132
static void SetPrintLevel(int print_level)
void SetProbeP4(const TLorentzVector &P4)
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
static Interaction * HNL(int probe, double E=0, int decayed_mode=-1)
static PDGLibrary * Instance(void)
TParticlePDG * Find(int pdgc, bool must_exist=true)
void ReadFromCommandLine(int argc, char **argv)
Definition RunOpt.cxx:99
static RunOpt * Instance(void)
Definition RunOpt.cxx:54
int DecayMode(void) const
Definition XclsTag.h:70
Heavy Neutral Lepton final-state product generator.
Definition HNLDecayer.h:41
std::vector< double > GetPGunDirection() const
std::vector< double > GetPGunDeviation() const
std::string GetHNLInterestingChannels() const
double GetHNLMass() const
void ProcessEventRecord(GHepRecord *event) const
double GetHNLLifetime() const
bool IsHNLMajorana() const
double GetPGunEnergy() const
std::vector< double > GetPGunDOrigin() const
std::vector< double > GetPGunOrigin() const
std::vector< double > GetHNLCouplings() const
A GENIE flux container specific for HNL containers. Based on the dk2nu flux paradigm and genie::flux:...
double nimpwt
Weight of parent.
double Ecm
Parent rest-frame energy of HNL [GeV].
double delay
delay HNL would have wrt SMv [ns]
int prodChan
Decay mode that produced HNL.
TLorentzVector parp4
parent momentum at HNL production in NEAR coords [GeV/c]
int parPdg
parent PDG code
double accCorr
acceptance correction (collimation effect. SM v == 1)
double boostCorr
boost correction wrt parent rest-frame (ELAB = ECM * boostCorr)
TVector3 startPoint
parent decay vertex in NEAR coords [m]
TLorentzVector p4
HNL momentum in NEAR coords [GeV/c].
double acceptance
full acceptance == XYWgt * boostCorr^2 * accCorr
Calculates HNL production kinematics & production vertex. Is a concrete implementation of the FluxRec...
void ProcessEventRecord(GHepRecord *event_rec) const
FluxContainer RetrieveFluxInfo() const
void SetGeomFile(string geomfile) const
std::vector< double > GetB2URotation() const
std::vector< double > GetB2UTranslation() const
void SetInputFluxPath(std::string finpath) const
void SetMomentumDirection(double ux, double uy, double uz)
Definition SimpleHNL.h:231
std::map< genie::hnl::HNLDecayMode_t, double > GetValidChannels()
Definition SimpleHNL.h:154
void SetEnergy(const double E)
Definition SimpleHNL.h:183
Heavy Neutral Lepton decay vertex generator given production vertex and momentum ***.
void SetGeomFile(std::string geomfile) const
void ProcessEventRecord(GHepRecord *event_rec) const
long int gOptRanSeed
double gOptGeomLUnits
string kDefOptEvFilePrefix
string kDefOptGeomLUnits
NtpMCFormat_t kDefOptNtpFormat
bool gOptUsingRootGeom
Long_t gOptRunNu
string kDefOptGeomDUnits
int gOptNev
string gOptRootGeom
string gOptEvFilePrefix
string gOptRootGeomTopVol
double foy
double fdz
double foz
double fox
bool gOptIsMonoEnFlux
double gOptEnergyHNL
double fdy
double fdx
string kDefOptFluxFilePath
string kDefOptSTune
double CoMLifetime
string kDefOptSName
string kDefOptSConfig
double gCfgUserOx
double gCfgUserOz
double gCfgParentOx
double gCfgTCoupling
double gCfgBoxLx
enum t_HNLValidation HNLValidation_t
double gOptGeomTUnits
HNLValidation_t gOptValidationMode
HNLDecayMode_t gCfgDecayMode
double gCfgParentOy
double gCfgUserOy
string lunits
double gCfgUserAx1
bool gCfgIsMajorana
double gCfgMCoupling
double gCfgParentEnergy
double gCfgBoxLz
const EventRecordVisitorI * HNLGenerator(void)
HNLProd_t gCfgProdMode
double gCfgBoxLy
string aunits
string geom
void GetCommandLineArgs(int argc, char **argv)
int TestDecay(void)
void PrintSyntax(void)
double gCfgHNLCz
string kDefOptGeomTUnits
double gCfgECoupling
std::vector< HNLDecayMode_t > gCfgIntChannels
void ReadInConfig(void)
double gCfgParentTheta
double gCfgHNLCx
double gOptGeomAUnits
double gCfgUserAz
double gCfgParentOz
string kDefOptGeomAUnits
double gCfgMassHNL
double gCfgUserAx2
double gCfgParentPhi
double gCfgHNLCy
string tunits
Basic constants.
static const double kASmallNum
Definition Controls.h:40
enum genie::hnl::t_HNLProd HNLProd_t
enum genie::hnl::EHNLDecayMode HNLDecayMode_t
static constexpr double cm
Definition Units.h:68
static constexpr double m
Definition Units.h:71
static constexpr double ns
Definition Units.h:98
static constexpr double GeV
Definition Units.h:28
static constexpr double mm
Definition Units.h:65
static constexpr double rad
Definition Units.h:164
void RandGen(long int seed)
Definition AppInit.cxx:30
void MesgThresholds(string inpfile)
Definition AppInit.cxx:99
string ProdAsString(genie::hnl::HNLProd_t hnlprod)
string AsString(genie::hnl::HNLDecayMode_t hnldm)
string Vec3AsString(const TVector3 *vec)
string PrintFramedMesg(string mesg, unsigned int nl=1, const char f=' *')
string X4AsString(const TLorentzVector *x)
string P4AsString(const TLorentzVector *p)
double UnitFromString(string u)
Definition UnitUtils.cxx:18
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25
@ kIStInitialState
Definition GHepStatus.h:29
bool gAbortingInErr
Definition Messenger.cxx:34
const int kPdgK0L
Definition PDGCodes.h:176
const int kPdgKP
Definition PDGCodes.h:172
@ kNFGHEP
Definition NtpMCFormat.h:30
const int kPdgHNL
Definition PDGCodes.h:224
const int kPdgPiP
Definition PDGCodes.h:158
const int kPdgMuon
Definition PDGCodes.h:37
enum genie::ENtpMCFormat NtpMCFormat_t