112using std::ostringstream;
114using namespace genie;
118#ifdef __GENIE_FLUX_DRIVERS_ENABLED__
119#define __CAN_GENERATE_EVENTS_USING_A_FLUX__
124#ifdef __GENIE_GEOM_DRIVERS_ENABLED__
125#define __CAN_USE_ROOT_GEOM__
126#include <TGeoVolume.h>
127#include <TGeoManager.h>
128#include <TGeoShape.h>
139#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
140void GenerateEventsUsingFlux (
void);
146#ifdef __CAN_USE_ROOT_GEOM__
147void InitBoundingBox (
void);
173#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
176bool gOptIsUsingDk2nu =
false;
177int gOptFirstEvent = 0;
188#ifdef __CAN_USE_ROOT_GEOM__
189TGeoManager * gOptRootGeoManager = 0;
190TGeoVolume * gOptRootGeoVolume = 0;
219int main(
int argc,
char ** argv)
222 gErrorIgnoreLevel = kWarning;
242 const Decayer * hnlgen =
dynamic_cast< const Decayer *
>( algHNLGen );
258 while( stIntChannels.size() > 0 ){
261 std::string tmpSt = stIntChannels.substr( stIntChannels.size()-1, stIntChannels.size() );
262 if( std::strcmp( tmpSt.c_str(),
"1" ) == 0 )
265 stIntChannels.erase( stIntChannels.end()-1, stIntChannels.end() );
277 if( gOptIsUsingDk2nu ) {
282 FillFluxNonsense( gnmf );
284 "genie::hnl::FluxContainer",
286 flux->SetAutoDelete(kFALSE);
290 <<
"Initialised Ntuple Writer";
304 <<
"Initialised MC job monitor";
309#ifdef __CAN_USE_ROOT_GEOM__
318 <<
"Using input flux files. These are *flat dk2nu-like ROOT trees, so far...*";
322 int iflux = (gOptFirstEvent < 0) ? 0 : gOptFirstEvent;
int ievent = iflux;
323 int maxFluxEntries = -1;
329 bool tooManyEntries =
false;
332 if( tooManyEntries ){
334 if( (ievent-gOptFirstEvent) % (
gOptNev / 1000) == 0 ){
335 int irat = (iflux-gOptFirstEvent) / (
gOptNev / 1000 );
336 std::cerr << 0.1 * irat <<
" % " <<
" ( " << (iflux-gOptFirstEvent)
337 <<
" seen ), ( " << (ievent-gOptFirstEvent) <<
" / " <<
gOptNev <<
" processed ) \r" << std::flush;
340 if( (ievent-gOptFirstEvent) % (
gOptNev / 10) == 0 ){
341 int irat = (iflux-gOptFirstEvent) / (
gOptNev / 10 );
342 std::cerr << 10.0 * irat <<
" % " <<
" ( " << (iflux-gOptFirstEvent)
343 <<
" seen ), ( " << (ievent-gOptFirstEvent) <<
" / " <<
gOptNev <<
" processed ) \r" << std::flush;
348 if( (ievent-gOptFirstEvent) % (
gOptNev / 1000) == 0 ){
349 int irat = (ievent-gOptFirstEvent) / (
gOptNev / 1000 );
350 std::cerr << 0.1 * irat <<
" % " <<
" ( " << (iflux-gOptFirstEvent)
351 <<
" seen ), ( " << (ievent-gOptFirstEvent) <<
" / " <<
gOptNev <<
" processed ) \r" << std::flush;
354 if( (ievent-gOptFirstEvent) % (
gOptNev / 10) == 0 ){
355 int irat = (ievent-gOptFirstEvent) / (
gOptNev / 10 );
356 std::cerr << 10.0 * irat <<
" % " <<
" ( " << (iflux-gOptFirstEvent)
357 <<
" seen ), ( " << (ievent-gOptFirstEvent) <<
" / " <<
gOptNev <<
" processed ) \r" << std::flush;
362 if( tooManyEntries && ((iflux-gOptFirstEvent) ==
gOptNev) )
break;
363 else if( (ievent-gOptFirstEvent) ==
gOptNev )
break;
365 if( ievent < gOptFirstEvent ){ ievent++;
continue; }
367 assert( ievent >= gOptFirstEvent && gOptFirstEvent >= 0 );
370 <<
" *** Generating event............ " << (ievent-gOptFirstEvent);
375 event->SetXSec( iflux );
383 if(
gOptNev > maxFluxEntries - gOptFirstEvent ){
385 <<
"You have asked for " <<
gOptNev <<
" events, but only provided "
386 << maxFluxEntries - gOptFirstEvent <<
" flux entries. Truncating events to " << maxFluxEntries - gOptFirstEvent <<
".";
387 gOptNev = maxFluxEntries - gOptFirstEvent;
388 tooManyEntries =
true;
390 if( iflux >= maxFluxEntries - 1 ){
392 <<
"Reached end of flux input (iflux = " << iflux <<
"), about to stop.";
397 FillFlux( gnmf, retGnmf );
400 if( ! event->Particle(0) ){ iflux++;
delete event;
continue; }
409 TLorentzVector v4( 0.0, 0.0, 0.0, 0.0 );
411 event->AddParticle( ptHNL );
419 else if( event->Particle(0)->Pdg() > 0 ) typeMod = 1;
420 else if( event->Particle(0)->Pdg() < 0 ) typeMod = -1;
437 <<
"No decay mode specified - sampling from all available modes.";
446 if( event->Particle(0) ){
453 event->AttachSummary(interaction);
461 NTP_FS0_E = ((
event->Particle(1))->P4())->E();
462 NTP_FS0_PX = ((
event->Particle(1))->P4())->Px();
463 NTP_FS0_PY = ((
event->Particle(1))->P4())->Py();
464 NTP_FS0_PZ = ((
event->Particle(1))->P4())->Pz();
466 NTP_FS1_E = ((
event->Particle(2))->P4())->E();
467 NTP_FS1_PX = ((
event->Particle(2))->P4())->Px();
468 NTP_FS1_PY = ((
event->Particle(2))->P4())->Py();
469 NTP_FS1_PZ = ((
event->Particle(2))->P4())->Pz();
470 if( event->Particle(3) ){
472 NTP_FS2_E = ((
event->Particle(3))->P4())->E();
473 NTP_FS2_PX = ((
event->Particle(3))->P4())->Px();
474 NTP_FS2_PY = ((
event->Particle(3))->P4())->Py();
475 NTP_FS2_PZ = ((
event->Particle(3))->P4())->Pz();
489 TLorentzVector * p4HNL =
event->Particle(0)->GetP4();
492 x4mm = *(
event->Vertex());
503 event->SetWeight(
evWeight / 1.0e+20 );
506 event->Particle(2)->SetPolarization( 1.0,
decayMod );
514 <<
"Generated event: " << *event;
518 mcjmonitor.
Update(ievent,event);
534#ifdef __CAN_USE_ROOT_GEOM__
535void InitBoundingBox(
void)
540 <<
"Initialising geometry bounding box.";
551 <<
"No geometry file input detected, making a unit-m side box volume.";
553 TGeoManager *
geom =
new TGeoManager(
"box1",
"A simple box detector" );
556 TGeoMaterial *matVacuum =
new TGeoMaterial(
"Vacuum", 0,0,0);
557 TGeoMaterial *matAl =
new TGeoMaterial(
"Al", 26.98,13,2.7);
559 TGeoMedium *Vacuum =
new TGeoMedium(
"Vacuum",1, matVacuum);
560 TGeoMedium *Al =
new TGeoMedium(
"Root Material",2, matAl);
567 TGeoVolume * topvol =
geom->MakeBox(
"TOP", Vacuum, 101.0, 101.0, 101.0 );
568 geom->SetTopVolume( topvol );
571 TGeoVolume * boxvol =
geom->MakeBox(
"VOL", Vacuum, 100.5, 100.5, 100.5 );
572 boxvol->SetVisibility(kFALSE);
575 TGeoVolume * box =
geom->MakeBox(
"BOX", Al, 100.0, 100.0, 100.0 );
577 TGeoRotation * rot0 =
new TGeoRotation(
"rot0", 90.0, 0.0, 90.0, 90.0, 0.0, 0.0 );
580 topvol->AddNode( box, 1, rot0 );
582 gOptRootGeoManager =
geom;
587 bool geom_is_accessible = ! (gSystem->AccessPathName(
gOptRootGeom.c_str()));
588 if (!geom_is_accessible) {
590 <<
"The specified ROOT geometry doesn't exist! Initialization failed!";
594 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(
gOptRootGeom.c_str());
596 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
597 assert( top_volume );
598 TGeoShape * ts = top_volume->GetShape();
600 TGeoBBox * box = (TGeoBBox *)ts;
606 fox = (box->GetOrigin())[0];
607 foy = (box->GetOrigin())[1];
608 foz = (box->GetOrigin())[2];
611 <<
"Before conversion the bounding box has:"
612 <<
"\nOrigin = ( " <<
fox <<
" , " <<
foy <<
" , " <<
foz <<
" )"
613 <<
"\nDimensions = " <<
fdx <<
" x " <<
fdy <<
" x " <<
fdz
614 <<
"\n1cm = 1.0 unit";
625 <<
"Initialised bounding box successfully.";
632#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
645 ggn.
startPoint.SetXYZ(-9999.9, -9999.9, -9999.9);
651 ggn.
polz.SetXYZ(-9999.9, -9999.9, -9999.9);
653 ggn.
p4.SetPxPyPzE(-9999.9, -9999.9, -9999.9, -9999.9);
654 ggn.
parp4.SetPxPyPzE(-9999.9, -9999.9, -9999.9, -9999.9);
655 ggn.
p4User.SetPxPyPzE(-9999.9, -9999.9, -9999.9, -9999.9);
656 ggn.
parp4User.SetPxPyPzE(-9999.9, -9999.9, -9999.9, -9999.9);
714 TRandom3 & rnd_geo = rnd->
RndGeom();
716 double rndx = 2 * (rnd_geo.Rndm() - 0.5);
717 double rndy = 2 * (rnd_geo.Rndm() - 0.5);
718 double rndz = 2 * (rnd_geo.Rndm() - 0.5);
721 double x_gen =
fox + rndx *
fdx;
722 double y_gen =
foy + rndy *
fdy;
723 double z_gen =
foz + rndz *
fdz;
725 TLorentzVector pos(x_gen, y_gen, z_gen, t_gen);
736 <<
"Instantiating HNL generator.";
745 LOG(
"gevgen_hnl",
pFATAL) <<
"Couldn't instantiate the HNL generator";
751 <<
"HNL generator instantiated successfully.";
765 std::vector< HNLDecayMode_t > intAndValidChannels;
766 for( std::vector< HNLDecayMode_t >::iterator it = intChannels->begin(); it != intChannels->end(); ++it ){
772 intAndValidChannels.emplace_back( mode );
773 auto mapG = gammaMap.find( mode );
774 double theGamma = mapG->second;
779 if( intAndValidChannels.size() == 0 ){
781 <<
"None of the channels specified as interesting are kinematically allowed. Please either increase the HNL mass or change interesting channels in config.";
785 std::map< HNLDecayMode_t, double > intMap =
791 double gammaAll = 0.0, gammaInt = 0.0;
792 for( std::map< HNLDecayMode_t, double >::const_iterator itall = gammaMap.begin() ;
793 itall != gammaMap.end() ; ++itall ){
794 gammaAll += (*itall).second;
796 for( std::map< HNLDecayMode_t, double >::iterator itint = intMap.begin() ;
797 itint != intMap.end() ; ++itint ){
798 gammaInt += (*itint).second;
800 assert( gammaInt > 0.0 && gammaAll >= gammaInt );
804 std::map< HNLDecayMode_t, double > PMap =
809 double ranThrow = rnd->
RndGen().Uniform( 0., 1. );
814 int decay = ( int ) selectedDecayChan;
820 LOG(
"gevgen_hnl",
pINFO) <<
"Parsing command line arguments";
828 char * expargv[ argc + 2 ];
829 bool didFindUserInputTune =
false;
833 didFindUserInputTune =
true;
836 <<
"Using input HNL tune " << parser.
ArgAsString(
"tune");
842 for(
int iArg = 0; iArg < argc; iArg++ ){
843 expargv[iArg] = argv[iArg];
845 if( !didFindUserInputTune ){
846 char * chBit =
const_cast< char *
>( stExtraTuneBit.c_str() );
847 std::string stune(
"--tune");
char * tBit =
const_cast< char *
>( stune.c_str() );
848 expargv[argc] = tBit;
849 expargv[argc+1] = chBit;
853 int expargc = ( didFindUserInputTune ) ? argc : argc+2;
854 std::string stnull(
"");
char * nBit =
const_cast< char *
>( stnull.c_str() );
855 expargv[expargc] = nBit;
868 LOG(
"gevgen_hnl",
pDEBUG) <<
"Reading MC run number";
871 LOG(
"gevgen_hnl",
pDEBUG) <<
"Unspecified run number - Using default";
878 <<
"Reading number of events to generate";
882 <<
"You need to specify the number of events";
889 const Decayer * hnlgen =
dynamic_cast< const Decayer *
>( algHNLGen );
892 bool isMonoEnergeticFlux =
true;
893#ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX__
896 <<
"A flux has been offered. Searching this path: " << parser.
ArgAsString(
'f');
897 isMonoEnergeticFlux =
false;
901 if( gSystem->OpenDirectory( gOptFluxFilePath.c_str() ) != NULL ){
902 gOptIsUsingDk2nu =
true;
904 <<
"dk2nu flux files detected. Will create flux spectrum dynamically.";
907 <<
"Invalid flux file path " << gOptFluxFilePath;
913 <<
"No flux file offered. Assuming monoenergetic flux.";
919 if( isMonoEnergeticFlux ){
922 <<
"Reading HNL energy";
926 <<
"You need to specify the HNL energy";
937 gOptFirstEvent = parser.
ArgAsInt(
"firstEvent");
939 <<
"Starting flux readin at first event = " << gOptFirstEvent;
946 <<
"Reading HNL decay mode";
950 <<
"No decay mode specified - will sample from allowed decay modes";
957 <<
"Specified decay is not allowed kinematically for the given HNL mass";
968#ifdef __CAN_USE_ROOT_GEOM__
971 LOG(
"gevgen_hnl",
pDEBUG) <<
"Getting input geometry";
975 bool accessible_geom_file =
976 ! (gSystem->AccessPathName(
geom.c_str()));
977 if (accessible_geom_file) {
982 <<
"Geometry option is not a ROOT file. Please use ROOT geom.";
999 <<
"Checking for input geometry length units";
1002 LOG(
"gevgen_hnl",
pDEBUG) <<
"Using default geometry length units";
1022 LOG(
"gevgen_hnl",
pDEBUG) <<
"Reading the event filename prefix";
1026 <<
"Will set the default event filename prefix";
1032 LOG(
"gevgen_hnl",
pINFO) <<
"Reading random number seed";
1035 LOG(
"gevgen_hnl",
pINFO) <<
"Unspecified random number seed - Using default";
1043 ostringstream gminfo;
1045 gminfo <<
"Using ROOT geometry - file: " <<
gOptRootGeom
1048 <<
", length units: " <<
lunits;
1061 <<
"\n @@ Geometry : " << gminfo.str()
1062 <<
"\n @@ Statistics : " <<
gOptNev <<
" events";
1069 <<
"\n gevgen_hnl [-h] "
1071 <<
"\n -n n_of_events"
1072 <<
"\n -f path/to/flux/files"
1073 <<
"\n [-E hnl_energy]"
1074 <<
"\n [--firstEvent first_event_for_dk2nu_readin]"
1075 <<
"\n [-m decay_mode]"
1076 <<
"\n [-g geometry (ROOT file)]"
1077 <<
"\n [-L length_units_at_geom]"
1078 <<
"\n [-o output_event_file_prefix]"
1079 <<
"\n [--seed random_number_seed]"
1080 <<
"\n [--message-thresholds xml_file]"
1081 <<
"\n [--event-record-print-level level]"
1082 <<
"\n [--mc-job-status-refresh-rate rate]"
1084 <<
" Please also read the detailed documentation at http://www.genie-mc.org"
1085 <<
" or look at the source code: $GENIE/src/Apps/gBeamHNLEvGen.cxx"
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE,...
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils.
The GENIE Algorithm Factory.
const Algorithm * GetAlgorithm(const AlgId &algid)
static AlgFactory * Instance()
Algorithm abstract base class.
Command line argument parser.
string ArgAsString(char opt)
double ArgAsDouble(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...
STDHEP-like event record entry that can fit a particle or a nucleus.
GENIE's GHEP MC event record.
virtual void SetWeight(double wght)
static void SetPrintLevel(int print_level)
Simple class to create & update MC job status files and env. vars. This is used to be able to keep tr...
void Update(int iev, const EventRecord *event)
void SetRefreshRate(int rate)
void SetProbePdg(int pdg_code)
void SetProbeP4(const TLorentzVector &P4)
Summary information for an interaction.
InitialState * InitStatePtr(void) const
static Interaction * HNL(int probe, double E=0, int decayed_mode=-1)
A utility class to facilitate creating the GENIE MC Ntuple from the output GENIE GHEP event records.
void Initialize(void)
add event
void Save(void)
get the even tree
void AddEventRecord(int ievent, const EventRecord *ev_rec)
save the event tree
void CustomizeFilenamePrefix(string prefix)
A singleton holding random number generator classes. All random number generation in GENIE should tak...
TRandom3 & RndGeom(void) const
rnd number generator used by geometry drivers
static RandomGen * Instance()
Access instance.
TRandom3 & RndGen(void) const
rnd number generator for generic usage
void ReadFromCommandLine(int argc, char **argv)
static RunOpt * Instance(void)
Heavy Neutral Lepton final-state product generator.
std::string GetHNLInterestingChannels() const
double GetHNLMass() const
void ProcessEventRecord(GHepRecord *event) const
double GetHNLLifetime() const
bool IsHNLMajorana() 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 zetaPlus
maximum angular deviation from parent momentum to reach detector [deg]
double Ecm
Parent rest-frame energy of HNL [GeV].
double delay
delay HNL would have wrt SMv [ns]
int nuPdg
PDG code of SM neutrino that would have been produced.
int prodChan
Decay mode that produced HNL.
TVector3 polz
HNL polarisation vector, in HNL rest frame, in NEAR coords.
TLorentzVector parp4
parent momentum at HNL production in NEAR coords [GeV/c]
double zetaMinus
minimum angular deviation from parent momentum to reach detector [deg]
TVector3 targetPoint
point in detector HNL is forced towards in NEAR coords [m]
int nuProdChan
Decay mode that would have produced SM neutrino.
int parPdg
parent PDG code
TLorentzVector parp4User
parent momentum at HNL production in USER coords [GeV/c]
TLorentzVector p4User
HNL momentum in USER coords [GeV/c].
double accCorr
acceptance correction (collimation effect. SM v == 1)
TVector3 startPointUser
parent decay vertex in USER coords [m]
double nuEcm
Parent rest-frame energy of equivalent SM neutrino [GeV].
double XYWgt
geometric acceptance (angular size of detector in parent rest frame)
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].
TVector3 targetPointUser
point in detector HNL is forced towards in USER coords [m]
double acceptance
full acceptance == XYWgt * boostCorr^2 * accCorr
int lepPdg
PDG code of lepton produced with HNL on parent decay.
Calculates HNL production kinematics & production vertex. Is a concrete implementation of the FluxRec...
void SetFirstFluxEntry(int iFirst) const
int GetNFluxEntries() const
void ProcessEventRecord(GHepRecord *event_rec) const
FluxContainer RetrieveFluxInfo() const
void SetGeomFile(string geomfile) const
void SetInputFluxPath(std::string finpath) const
void SetInterestingChannels(const std::map< genie::hnl::HNLDecayMode_t, double > gammaMap)
std::map< genie::hnl::HNLDecayMode_t, double > GetValidChannels()
Heavy Neutral Lepton decay vertex generator given production vertex and momentum ***.
void SetGeomFile(std::string geomfile) const
void ProcessEventRecord(GHepRecord *event_rec) const
string kDefOptEvFilePrefix
NtpMCFormat_t kDefOptNtpFormat
string gOptRootGeomTopVol
TLorentzVector GeneratePosition(GHepRecord *event)
HNLDecayMode_t gOptDecayMode
std::vector< HNLDecayMode_t > gOptIntChannels
const EventRecordVisitorI * HNLGenerator(void)
int SelectDecayMode(std::vector< HNLDecayMode_t > *intChannels, SimpleHNL sh)
string kDefOptFluxFilePath
void GetCommandLineArgs(int argc, char **argv)
map< string, string > gOptFluxShortNames
genie::hnl::HNLDecayMode_t SelectChannelInclusive(std::map< genie::hnl::HNLDecayMode_t, double > Pmap, double ranThrow)
std::map< genie::hnl::HNLDecayMode_t, double > SetInterestingChannels(std::vector< genie::hnl::HNLDecayMode_t > intChannels, std::map< genie::hnl::HNLDecayMode_t, double > gammaMap)
std::map< genie::hnl::HNLDecayMode_t, double > GetProbabilities(std::map< genie::hnl::HNLDecayMode_t, double > gammaMap)
enum genie::hnl::EHNLDecayMode HNLDecayMode_t
void RandGen(long int seed)
void MesgThresholds(string inpfile)
string AsString(genie::hnl::HNLDecayMode_t hnldm)
bool IsKinematicallyAllowed(genie::hnl::HNLDecayMode_t hnldm, double Mhnl)
string PrintFramedMesg(string mesg, unsigned int nl=1, const char f=' *')
string P4AsString(const TLorentzVector *p)
double UnitFromString(string u)
THE MAIN GENIE PROJECT NAMESPACE
enum genie::ENtpMCFormat NtpMCFormat_t