115 using std::ostringstream;
117 using namespace genie;
118 using namespace genie::hnl;
120 #ifdef __GENIE_FLUX_DRIVERS_ENABLED__
121 #define __CAN_GENERATE_EVENTS_USING_A_FLUX__
124 #endif // #ifdef __GENIE_FLUX_DRIVERS_ENABLED__
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__
150 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
151 int TestFluxFromDk2nu (
void);
156 #ifdef __CAN_USE_ROOT_GEOM__
158 void InitBoundingBox (
void);
159 #endif // #ifdef __CAN_USE_ROOT_GEOM__
223 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
225 bool gOptIsUsingDk2nu =
false;
226 #endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
238 #ifdef __CAN_USE_ROOT_GEOM__
239 TGeoManager * gOptRootGeoManager = 0;
240 TGeoVolume * gOptRootGeoVolume = 0;
241 #endif // #ifdef __CAN_USE_ROOT_GEOM__
255 int main(
int argc,
char ** argv)
258 gErrorIgnoreLevel = kWarning;
274 case kValGeom:
return TestGeom();
break;
275 default:
LOG(
"gevald_hnl",
pFATAL ) <<
"I didn't recognise this mode. Goodbye world!";
break;
282 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
283 int TestFluxFromDk2nu()
287 string foutName(
"test_flux_dk2nu.root");
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";
303 bool geom_is_accessible = ! (gSystem->AccessPathName(
gOptRootGeom.c_str()));
304 if (!geom_is_accessible) {
306 <<
"The specified ROOT geometry doesn't exist! Initialization failed!";
311 int maxFluxEntries = -1;
313 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
315 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
316 assert( top_volume );
317 TGeoShape * ts = top_volume->GetShape();
320 TFile * fout = TFile::Open( foutName.c_str(), "RECREATE" );
321 TH1D hEAll, hEPion, hEKaon, hEMuon, hENeuk;
323 TH1D hAcceptanceCorr, hAcceptance, hAcceptNoBCorr;
326 TH1D hBAll, hBPion, hBKaon, hBMuon, hBNeuk;
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. );
335 hPop = TH1D( "hPop", "HNL populations in energy bins", 1000, 0., 100. );
336 hImpwt = TH1D( "hImpwt", "HNL importance weights", 1000, 0., 100. );
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 );
344 hProdVtxPos = TH3D(
"hProdVtxPos",
"HNL production vertex (user coordinates, cm)",
345 200, -100., 100., 200, -100., 100., 1100, -110000., 0.);
347 hCounters = TH1D(
"hCounters",
"HNL production channel counters", 11, 0, 11 );
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. );
355 hParamSpace = TH1D(
"hParamSpace",
"Parameter space", 5, 0., 5. );
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;
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;
379 if( ievent % (
gOptNev / 10) == 0 ){
380 int irat = ievent / (
gOptNev / 10 );
381 std::cerr << 10.0 * irat <<
" % " <<
" ( " << ievent
382 <<
" / " <<
gOptNev <<
" ) \r" << std::flush;
395 if(
gOptNev > maxFluxEntries ){
397 <<
"You have asked for " <<
gOptNev <<
" events, but only provided "
398 << maxFluxEntries <<
" flux entries. Truncating events to " << maxFluxEntries <<
".";
409 <<
"Skipping nonsense for event " << ievent <<
" (was this parent too light?)";
417 int typeMod = (gnmf->
pdg > 0) ? 1 : -1;
421 if( parPDG == 0 || parPDG == -9999 ){ ievent++;
continue; }
429 TLorentzVector p4par = gnmf->
parp4;
430 double EPar = p4par.E();
432 TVector3 boost_beta = p4par.BoostVector();
433 betaMag = boost_beta.Mag();
437 double delay = gnmf->
delay;
449 double gam = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
451 double betaStar = std::sqrt( 1.0 - 1.0 / ( gamStar * gamStar ) );
452 double bigBeta = betaMag * gam / betaStar;
454 double Ox = -1.0 * x4HNL.X();
455 double Oy = -1.0 * x4HNL.Y();
456 double Oz = -1.0 * x4HNL.Z();
458 double rootArg = gam*gam*Oz*Oz -
459 (gam*gam - bigBeta*bigBeta)*(Oz*Oz - bigBeta*bigBeta*(Ox*Ox + Oy*Oy));
461 double timelikeBit = ( rootArg >= 0.0 ) ? std::sqrt( rootArg ) / ( betaMag * gam * gam * gam ) : 0.0;
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 );
469 hEAll.Fill( p4HNL.E(), acceptance * nimpwt );
470 hProdVtxPos.Fill( x4HNL.X(), x4HNL.Y(), x4HNL.Z(), nimpwt );
471 hBAll.Fill( betaMag, nimpwt );
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 ) );
481 hEPion.Fill( p4HNL.E(), acceptance * nimpwt );
482 hBPion.Fill( betaMag, nimpwt );
485 hEKaon.Fill( p4HNL.E(), acceptance * nimpwt );
486 hBKaon.Fill( betaMag, nimpwt );
489 hENeuk.Fill( p4HNL.E(), acceptance * nimpwt );
490 hBNeuk.Fill( betaMag, nimpwt );
493 hEMuon.Fill( p4HNL.E(), acceptance * nimpwt );
494 hBMuon.Fill( betaMag, nimpwt );
499 <<
" *** Output for event no " << ievent <<
"... ***"
500 <<
"\nparPDG = " << parPDG
503 <<
" : mag = " << betaMag
506 <<
"\nacceptance = " << acceptance <<
" : accCorr = " << accCorr
507 <<
"\nnimpwt = " << nimpwt
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 );
531 hParamSpace.SetBinContent( 1, 1000.0 *
gCfgMassHNL );
535 hParamSpace.SetBinContent( 5, nPOT );
543 #endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX_
547 string foutName(
"test_decay.root");
549 TFile * fout = TFile::Open( foutName.c_str(),
"RECREATE" );
553 const Decayer * hnlgen =
dynamic_cast< const Decayer *
>( algHNLGen );
555 bool geom_is_accessible = ! (gSystem->AccessPathName(
gOptRootGeom.c_str()));
556 if (!geom_is_accessible) {
558 <<
"The specified ROOT geometry doesn't exist! Initialization failed!";
562 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
564 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
565 assert( top_volume );
566 TGeoShape * ts = top_volume->GetShape();
569 LOG(
"gevald_hnl",
pDEBUG ) <<
"Imported box.";
581 assert( valMap.size() > 0 );
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";
599 assert( p3HNL >= 0.0 );
600 TLorentzVector * p4HNL =
new TLorentzVector( p3HNL *
gCfgHNLCx,
609 TLorentzVector * x4HNL =
new TLorentzVector( 1.0, 2.0, 3.0, 0.0 );
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;
623 LOG(
"gevald_hnl",
pDEBUG ) <<
"Here are the modes in order : " << msts.str();
627 TH1D hSpectrum[10][3], hCMSpectrum[10][3], hRates;
628 TH1D hParamSpace = TH1D(
"hParamSpace",
"Parameter space", 5, 0., 5. );
630 hParamSpace.SetBinContent( 1, 1000.0 * gCfgMassHNL );
635 hRates = TH1D(
"hRates",
"Rates of HNL decay channels", 10, 0, 10 );
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++ ){
645 std::string shortMode = shortModes[iChan];
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(),
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(),
659 100, 0., gCfgMassHNL );
667 double rnuee = ( valMap.find(
kHNLDcyNuEE ) != valMap.end() ) ? (*(valMap.find(
kHNLDcyNuEE ))).second : 0.0;
670 double rpie = ( valMap.find(
kHNLDcyPiE ) != valMap.end() ) ? (*(valMap.find(
kHNLDcyPiE ))).second : 0.0;
672 double rpimu = ( valMap.find(
kHNLDcyPiMu ) != valMap.end() ) ? (*(valMap.find(
kHNLDcyPiMu ))).second : 0.0;
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 );
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;
698 if( ievent % (
gOptNev / 10) == 0 ){
699 int irat = ievent / (
gOptNev / 10 );
700 std::cerr << 10.0 * irat <<
" % " <<
" ( " << ievent
701 <<
" / " <<
gOptNev <<
" ) \r" << std::flush;
705 if( ievent ==
gOptNev ){ std::cerr <<
" \n";
break; }
708 for(
unsigned int iMode = 0; iMode < valMap.size(); iMode++ ){
719 event->AddParticle( ptHNL );
721 event->SetVertex( *x4HNL );
725 event->AttachSummary( interaction );
727 <<
"Simulating decay with mode "
737 double ox = PGOrigin.at(0), oy = PGOrigin.at(1), oz = PGOrigin.at(2);
744 TVector3 startPoint( ox, oy, oz ); TVector3 entryPoint, exitPoint;
745 TLorentzVector tmpVtx( ox, oy, oz, 0.0 );
746 event->SetVertex( tmpVtx );
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 );
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();
765 TVector3 boostVec = p4HNL->BoostVector();
767 p4p1->Boost( -boostVec );
768 p4p2->Boost( -boostVec );
769 if( p4p3 ) p4p3->Boost( -boostVec );
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 );
780 if( ievent == 0 )
LOG(
"gevald_hnl",
pDEBUG ) << asts.str();
781 LOG(
"gevald_hnl",
pDEBUG ) <<
"Finished event: " << ievent;
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();
807 #ifdef __CAN_USE_ROOT_GEOM__
811 string foutName(
"test_geom.root");
813 TFile * fout = TFile::Open( foutName.c_str(),
"RECREATE" );
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:"
821 <<
"\n |---- start x,y,z [mm]"
823 <<
"\n |---- HNL 4-momentum [GeV]"
825 <<
"\n |---- did intersect detector?"
827 <<
"\n |---- entry x,y,z [mm]"
829 <<
"\n |---- exit x,y,z [mm]"
833 <<
"\n |---- HNL lifetime (rest frame) [ns]"
835 <<
"\n |---- HNL lifetime (lab frame) [ns]"
837 <<
"\n |---- decay x,y,z [mm]"
838 <<
"\n--> Weight histogram"
839 <<
"\n--> Travel-length histogram"
841 <<
"\n(where same coordinate system as user's is used and weight == P(HNL decays in detector) )";
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;
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" );
867 TH1D hWeight(
"hWeight",
"Log_{10} ( P( decay in detector ) )",
869 TH1D hLength(
"hLength",
"Length travelled in detector / max possible length in detector",
872 bool geom_is_accessible = ! (gSystem->AccessPathName(
gOptRootGeom.c_str()));
873 if (!geom_is_accessible) {
875 <<
"The specified ROOT geometry doesn't exist! Initialization failed!";
879 gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
880 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
881 assert( top_volume );
889 const Decayer * hnlgen =
dynamic_cast< const Decayer *
>( algHNLGen );
901 assert( p3HNL >= 0.0 );
902 TLorentzVector * p4HNL =
new TLorentzVector( p3HNL *
gCfgHNLCx,
911 double betaMag = p4HNL->P() / p4HNL->E();
912 __attribute__((unused)) double gamma = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
916 use_lifetime = sh.GetLifetime() / ( units::
ns * units::GeV );
918 std::vector<
double > PGOrigin = hnlgen->GetPGunOrigin();
919 std::vector<
double > PGDOrigin = hnlgen->GetPGunDOrigin();
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);
933 assert( PGdx > 0.0 && PGdy > 0.0 && PGdz > 0.0 );
936 const
double PGcx = gCfgHNLCx / c2;
937 const
double PGcy = gCfgHNLCy / c2;
938 const
double PGcz = gCfgHNLCz / c2;
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 );
944 std::vector<
double > PGDeviation = hnlgen->GetPGunDeviation();
945 const
double PGdtheta = PGDeviation.at(0) * constants::
kPi / 180.0;
946 const
double PGdphi = PGDeviation.at(1) * constants::kPi / 180.0;
963 const
int NCARTESIAN = 5;
964 const
int NSPHERICAL = 9;
965 const
int NMAX = NCARTESIAN * NCARTESIAN * NCARTESIAN * NSPHERICAL * NSPHERICAL;
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 };
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 };
976 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
978 TGeoShape * ts = top_volume->GetShape();
985 if( ievent == NMAX )
break;
988 <<
"*** Building event = " << ievent;
993 event->AttachSummary( interaction );
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;
1015 double use_theta = arr_theta[ it ];
1016 double use_phi = arr_phi[ ip ];
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 );
1026 p4HNL->SetPxPyPzE( p3HNL * use_cx, p3HNL * use_cy, p3HNL * use_cz,
gOptEnergyHNL );
1028 TVector3 startPoint, momentum;
1029 TVector3 entryPoint, exitPoint, decayPoint;
1031 startPoint.SetXYZ( use_ox, use_oy, use_oz );
1032 momentum.SetXYZ( p4HNL->Px(), p4HNL->Py(), p4HNL->Pz() );
1034 use_start[0] = use_ox;
1035 use_start[1] = use_oy;
1036 use_start[2] = use_oz;
1038 use_momentum[0] = p4HNL->Px();
1039 use_momentum[1] = p4HNL->Py();
1040 use_momentum[2] = p4HNL->Pz();
1041 use_momentum[3] = p4HNL->E();
1050 TLorentzVector tmpVtx( use_ox, use_oy, use_oz, 0.0);
1051 event->SetVertex( tmpVtx );
1052 TLorentzVector tmpMom = *p4HNL;
1054 event->AddParticle( ptHNL );
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();
1067 use_entry[0] = entryPoint.X();
1068 use_entry[1] = entryPoint.Y();
1069 use_entry[2] = entryPoint.Z();
1071 use_exit[0] = exitPoint.X();
1072 use_exit[1] = exitPoint.Y();
1073 use_exit[2] = exitPoint.Z();
1075 use_decay[0] = decayPoint.X();
1076 use_decay[1] = decayPoint.Y();
1077 use_decay[2] = decayPoint.Z();
1083 double mdeX = exitPoint.X() - entryPoint.X();
1084 double mdeY = exitPoint.Y() - entryPoint.Y();
1085 double mdeZ = exitPoint.Z() - entryPoint.Z();
1087 double elapsedLength = std::sqrt( devX * devX + devY * devY + devZ * devZ );
1088 double maxLength = std::sqrt( mdeX * mdeX + mdeY * mdeY + mdeZ * mdeZ );
1091 hWeight.Fill( -1.0 * std::log10( use_wgt ), 1.0 );
1092 hLength.Fill( elapsedLength / maxLength );
1093 didIntersectDet =
true;
1097 use_entry[0] = -999.9;
1098 use_entry[1] = -999.9;
1099 use_entry[2] = -999.9;
1101 use_exit[0] = -999.9;
1102 use_exit[1] = -999.9;
1103 use_exit[2] = -999.9;
1105 use_decay[0] = -999.9;
1106 use_decay[1] = -999.9;
1107 use_decay[2] = -999.9;
1109 didIntersectDet =
false;
1127 void InitBoundingBox(
void)
1132 <<
"Initialising geometry bounding box.";
1143 bool geom_is_accessible = ! (gSystem->AccessPathName(
gOptRootGeom.c_str()));
1144 if (!geom_is_accessible) {
1146 <<
"The specified ROOT geometry doesn't exist! Initialization failed!";
1150 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
1152 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
1153 assert( top_volume );
1154 TGeoShape * ts = top_volume->GetShape();
1155 TGeoBBox * box = (TGeoBBox *)ts;
1161 fox = (box->GetOrigin())[0];
1162 foy = (box->GetOrigin())[1];
1163 foz = (box->GetOrigin())[2];
1166 <<
"Before conversion the bounding box has:"
1167 <<
"\nOrigin = ( " <<
fox <<
" , " <<
foy <<
" , " <<
foz <<
" )"
1168 <<
"\nDimensions = " <<
fdx <<
" x " <<
fdy <<
" x " <<
fdz
1169 <<
"\n1cm = 1.0 unit";
1180 <<
"Initialised bounding box successfully.";
1184 #endif // #ifdef __CAN_USE_ROOT_GEOM__
1194 <<
"Instantiating HNL generator.";
1203 LOG(
"gevald_hnl",
pFATAL) <<
"Couldn't instantiate the HNL generator";
1209 <<
"HNL generator instantiated successfully.";
1216 LOG(
"gevald_hnl",
pINFO) <<
"Parsing command line arguments";
1223 bool help = parser.OptionExists(
'h');
1231 char * expargv[ argc + 2 ];
1232 bool didFindUserInputTune =
false;
1235 if( parser.OptionExists(
"tune") ){
1236 didFindUserInputTune =
true;
1237 stExtraTuneBit = parser.ArgAsString(
"tune");
1239 <<
"Using input HNL tune " << parser.ArgAsString(
"tune");
1245 for(
int iArg = 0; iArg < argc; iArg++ ){
1246 expargv[iArg] = argv[iArg];
1248 if( !didFindUserInputTune ){
1249 char * chBit =
const_cast< char *
>( stExtraTuneBit.c_str() );
1250 std::string stune(
"--tune");
char * tBit =
const_cast< char *
>( stune.c_str() );
1251 expargv[argc] = tBit;
1252 expargv[argc+1] = chBit;
1256 int expargc = ( didFindUserInputTune ) ? argc : argc+2;
1257 std::string stnull(
"");
char * nBit =
const_cast< char *
>( stnull.c_str() );
1258 expargv[expargc] = nBit;
1263 if( parser.OptionExists(
'r') ) {
1264 LOG(
"gevald_hnl",
pDEBUG) <<
"Reading MC run number";
1267 LOG(
"gevald_hnl",
pDEBUG) <<
"Unspecified run number - Using default";
1272 if( parser.OptionExists(
'n') ) {
1274 <<
"Reading number of events to generate";
1275 gOptNev = parser.ArgAsInt(
'n');
1278 <<
"You need to specify the number of events";
1283 if( parser.OptionExists(
'M') ) {
1285 <<
"Detecting mode. . .";
1289 <<
"You must specify a validation mode.";
1294 bool isMonoEnergeticFlux =
true;
1295 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
1296 if( parser.OptionExists(
'f') ) {
1298 <<
"A flux has been offered. Searching this path: " << parser.ArgAsString(
'f');
1299 isMonoEnergeticFlux =
false;
1300 gOptFluxFilePath = parser.ArgAsString(
'f');
1304 if( gSystem->OpenDirectory( gOptFluxFilePath.c_str() ) != NULL ){
1305 gOptIsUsingDk2nu =
true;
1307 <<
"dk2nu flux files detected. Will create flux spectrum dynamically.";
1310 <<
"Invalid flux file path " << gOptFluxFilePath;
1316 <<
"No flux file offered. Assuming monoenergetic flux.";
1319 #endif // #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
1321 #ifdef __CAN_USE_ROOT_GEOM__
1322 if( parser.OptionExists(
'g') ) {
1323 LOG(
"gevald_hnl",
pDEBUG) <<
"Getting input geometry";
1324 geom = parser.ArgAsString(
'g');
1327 bool accessible_geom_file =
1328 ! (gSystem->AccessPathName(
geom.c_str()));
1329 if (accessible_geom_file) {
1334 <<
"Geometry option is not a ROOT file. Please use ROOT geom.";
1341 <<
"No geometry option specified - Exiting";
1346 if( parser.OptionExists(
'L') ) {
1347 lunits = parser.ArgAsString(
'L');
1348 LOG(
"gevald_hnl",
pDEBUG) <<
"Setting length units to " <<
lunits.c_str();
1350 LOG(
"gevald_hnl",
pDEBUG) <<
"Using default geometry length units";
1355 if( parser.OptionExists(
'A') ) {
1356 aunits = parser.ArgAsString(
'A');
1357 LOG(
"gevald_hnl",
pDEBUG) <<
"Setting angle units to " <<
aunits.c_str();
1359 LOG(
"gevald_hnl",
pDEBUG) <<
"Using default angle length units";
1364 if( parser.OptionExists(
'T') ) {
1365 tunits = parser.ArgAsString(
'T');
1366 LOG(
"gevald_hnl",
pDEBUG) <<
"Setting time units to " <<
tunits.c_str();
1368 LOG(
"gevald_hnl",
pDEBUG) <<
"Using default geometry time units";
1373 #endif // #ifdef __CAN_USE_ROOT_GEOM__
1376 if( parser.OptionExists(
'o') ) {
1377 LOG(
"gevald_hnl",
pDEBUG) <<
"Reading the event filename prefix";
1381 <<
"Will set the default event filename prefix";
1386 if( parser.OptionExists(
"seed") ) {
1387 LOG(
"gevald_hnl",
pINFO) <<
"Reading random number seed";
1390 LOG(
"gevald_hnl",
pINFO) <<
"Unspecified random number seed - Using default";
1398 ostringstream gminfo;
1400 gminfo <<
"Using ROOT geometry - file: " <<
gOptRootGeom
1403 <<
", length units: " <<
lunits;
1416 <<
"\n @@ Flux path : " << gOptFluxFilePath
1417 <<
"\n @@ Geometry : " << gminfo.str()
1418 <<
"\n @@ Statistics : " <<
gOptNev <<
" events";
1424 <<
"Reading in validation configuration. . .";
1449 double dircosMag2 = std::pow(
gCfgHNLCx, 2.0 ) +
1452 double invdircosmag = 1.0 / std::sqrt( dircosMag2 );
1459 while( stIntChannels.size() > 0 ){
1462 std::string tmpSt = stIntChannels.substr( stIntChannels.size()-1, stIntChannels.size() );
1463 if( std::strcmp( tmpSt.c_str(),
"1" ) == 0 )
1466 stIntChannels.erase( stIntChannels.end()-1, stIntChannels.end() );
1474 std::vector< double > b2uRotation = fluxCreator->
GetB2URotation();
1487 csts <<
"Read out the following config:"
1494 <<
"\nInteresting decay channels:";
1495 for( std::vector< HNLDecayMode_t >::iterator chit =
gCfgIntChannels.begin();
1498 <<
"\nUser origin in beam coordinates = ( " <<
gCfgUserOx
1500 <<
"\nEuler extrinsic x-z-x rotation = ( " <<
gCfgUserAx1
1503 <<
", " <<
gCfgHNLCz <<
") [ GeV / GeV ]";
1505 LOG(
"gevald_hnl",
pDEBUG) << csts.str();
1513 <<
"\n gevald_hnl [-h] "
1515 <<
"\n -n n_of_events"
1516 <<
"\n [-f path_to_flux_files]"
1517 <<
"\n [-g geometry_file]"
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!)"
1529 <<
"\n The configuration file lives at $GENIE/config/CommonHNL.xml - see"
1530 <<
" <param_set name=\"Validation\">"
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"
static constexpr double cm
enum genie::hnl::t_HNLProd HNLProd_t
TLorentzVector parp4
parent momentum at HNL production in NEAR coords [GeV/c]
bool IsHNLMajorana() const
void RandGen(long int seed)
static void SetPrintLevel(int print_level)
virtual void SetXSec(double xsec)
static constexpr double rad
double Ecm
Parent rest-frame energy of HNL [GeV].
Heavy Neutral Lepton final-state product generator.
Heavy Neutral Lepton decay vertex generator given production vertex and momentum ***.
void SetProbeP4(const TLorentzVector &P4)
double delay
delay HNL would have wrt SMv [ns]
void ProcessEventRecord(GHepRecord *event_rec) const
string AsString(genie::hnl::HNLDecayMode_t hnldm)
Defines the EventRecordVisitorI interface. Concrete implementations of this interface use the 'Visito...
void ReadFromCommandLine(int argc, char **argv)
TVector3 startPoint
parent decay vertex in NEAR coords [m]
int GetNFluxEntries() const
int parPdg
parent PDG code
A GENIE flux container specific for HNL containers. Based on the dk2nu flux paradigm and genie::flux:...
string P4AsString(const TLorentzVector *p)
std::vector< HNLDecayMode_t > gCfgIntChannels
Algorithm abstract base class.
static constexpr double ns
HNLDecayMode_t gCfgDecayMode
int main(int argc, char **argv)
double GetHNLMass() const
string kDefOptEvFilePrefix
Summary information for an interaction.
double GetPGunEnergy() const
Calculates HNL production kinematics & production vertex. Is a concrete implementation of the FluxRec...
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
TLorentzVector p4
HNL momentum in NEAR coords [GeV/c].
void SetMomentumDirection(double ux, double uy, double uz)
string gOptRootGeomTopVol
void ProcessEventRecord(GHepRecord *event_rec) const
static constexpr double GeV
std::vector< double > GetPGunDirection() const
double GetHNLLifetime() const
double UnitFromString(string u)
int prodChan
Decay mode that produced HNL.
const Algorithm * GetAlgorithm(const AlgId &algid)
int DecayMode(void) const
std::map< genie::hnl::HNLDecayMode_t, double > GetValidChannels()
enum genie::hnl::EHNLDecayMode HNLDecayMode_t
static const double kASmallNum
FluxContainer RetrieveFluxInfo() const
string ProdAsString(genie::hnl::HNLProd_t hnlprod)
double acceptance
full acceptance == XYWgt * boostCorr^2 * accCorr
std::vector< double > GetPGunOrigin() const
std::vector< double > GetB2URotation() const
void SetEnergy(const double E)
double nimpwt
Weight of parent.
std::string GetHNLInterestingChannels() const
Generated Event Record. It is a GHepRecord object that can accept / be visited by EventRecordVisitorI...
double accCorr
acceptance correction (collimation effect. SM v == 1)
static PDGLibrary * Instance(void)
string kDefOptFluxFilePath
static RunOpt * Instance(void)
static AlgFactory * Instance()
static __attribute__((unused)) double fDecayGammas[]
std::vector< double > GetB2UTranslation() const
const XclsTag & ExclTag(void) const
std::vector< double > GetHNLCouplings() const
static constexpr double mm
NtpMCFormat_t kDefOptNtpFormat
InitialState * InitStatePtr(void) const
string PrintFramedMesg(string mesg, unsigned int nl=1, const char f='*')
HNLValidation_t gOptValidationMode
void MesgThresholds(string inpfile)
const EventRecordVisitorI * HNLGenerator(void)
TParticlePDG * Find(int pdgc, bool must_exist=true)
Command line argument parser.
enum genie::ENtpMCFormat NtpMCFormat_t
double boostCorr
boost correction wrt parent rest-frame (ELAB = ECM * boostCorr)
void GetCommandLineArgs(int argc, char **argv)
The GENIE Algorithm Factory.
void ProcessEventRecord(GHepRecord *event) const
string X4AsString(const TLorentzVector *x)
void SetGeomFile(std::string geomfile) const
static constexpr double m
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils...
STDHEP-like event record entry that can fit a particle or a nucleus.
string Vec3AsString(const TVector3 *vec)
void SetInputFluxPath(std::string finpath) const
enum t_HNLValidation HNLValidation_t
void SetGeomFile(string geomfile) const
static Interaction * HNL(int probe, double E=0, int decayed_mode=-1)