gEvGenDM.cxx
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*!
3 
4 \program gevgen_dm
5 
6 \brief A simple 'generic' GENIE DM+A event generation driver (gevgen_dm).
7 
8  It handles:
9  a) event generation for a fixed init state (DM+A) at fixed energy, or
10  b) event generation for simple fluxes (specified either via some
11  functional form, tabular text file or a ROOT histogram) and for
12  simple 'geometries' (a target mix with its corresponding weights)
13 
14  See the GENIE manual for other apps handling experiment-specific
15  event generation cases using the outputs of detailed dark matter flux
16  simulations and realistic detector geometry descriptions.
17 
18  Syntax :
19  gevgen_dm [-h]
20  [-r run#]
21  -n nev
22  -e energy (or energy range)
23  -m mass
24  -t target_pdg
25  [-g zp_coupling]
26  [-z med_ratio]
27  [-f flux_description]
28  [-o outfile_name]
29  [-w]
30  [--seed random_number_seed]
31  [--cross-sections xml_file]
32  [--event-generator-list list_name]
33  [--tune genie_tune]
34  [--message-thresholds xml_file]
35  [--unphysical-event-mask mask]
36  [--event-record-print-level level]
37  [--mc-job-status-refresh-rate rate]
38  [--cache-file root_file]
39 
40  Options :
41  [] Denotes an optional argument.
42  -h
43  Prints-out help on using gevgen_dm and exits.
44  -n
45  Specifies the number of events to generate.
46  -r
47  Specifies the MC run number.
48  -e
49  Specifies the dark matter energy.
50  If what follows the -e option is a comma separated pair of values
51  it will be interpreted as an energy range for the flux specified
52  via the -f option (see below).
53  -m
54  Specifies the dark matter mass.
55  -t
56  Specifies the target PDG code (pdg format: 10LZZZAAAI) _or_ a target
57  mix (pdg codes with corresponding weights) typed as a comma-separated
58  list of pdg codes with the corresponding weight fractions in brackets,
59  eg code1[fraction1],code2[fraction2],...
60  For example, to use a target mix of 95% O16 and 5% H type:
61  `-t 1000080160[0.95],1000010010[0.05]'.
62  -z
63  Specifies the ratio of the mediator mass to dark matter mass.
64  Default: 0.5
65  -g
66  Specifies the Z' coupling constant
67  Default: Value in UserPhysicsOptions.xml
68  -f
69  Specifies the dark matter flux spectrum.
70  It can be any of:
71  -- A function:
72  eg ` -f x*x+4*exp(-x)'
73  -- A vector file:
74  The vector file should contain 2 columns corresponding to
75  energy,flux (see $GENIE/data/flux/ for few examples).
76  -- A 1-D ROOT histogram (TH1D):
77  The general syntax is `-f /full/path/file.root,object_name'
78  -o
79  Specifies the name of the output file events will be saved in.
80  -w
81  Forces generation of weighted events.
82  This option is relevant only if a dark matter flux is specified.
83  Note that 'weighted' refers to the selection of the primary
84  flux dark matter + target that were forced to interact. A weighting
85  scheme for the generated kinematics of individual processes can
86  still be in effect if enabled..
87  ** Only use that option if you understand what it means **
88  --seed
89  Random number seed.
90  --cross-sections
91  Name (incl. full path) of an XML file with pre-computed
92  cross-section values used for constructing splines.
93  --event-generator-list
94  List of event generators to load in event generation drivers.
95  [default: "Default"].
96  --tune
97  Specifies a GENIE comprehensive dark matter interaction model tune.
98  [default: "Default"].
99  --message-thresholds
100  Allows users to customize the message stream thresholds.
101  The thresholds are specified using an XML file.
102  See $GENIE/config/Messenger.xml for the XML schema.
103  --unphysical-event-mask
104  Allows users to specify a 16-bit mask to allow certain types of
105  unphysical events to be written in the output file.
106  [default: all unphysical events are rejected]
107  --event-record-print-level
108  Allows users to set the level of information shown when the event
109  record is printed in the screen. See GHepRecord::Print().
110  --mc-job-status-refresh-rate
111  Allows users to customize the refresh rate of the status file.
112  --cache-file
113  Allows users to specify a cache file so that the cache can be
114  re-used in subsequent MC jobs.
115 
116  *** See the User Manual for more details and examples. ***
117 
118 \author Joshua Berger <jberger \at physics.wisc.edu>
119  University of Wisconsin-Madison
120  Costas Andreopoulos <constantinos.andreopoulos \at cern.ch>
121  University of Liverpool & STFC Rutherford Appleton Laboratory
122 
123 \created September 1, 2017
124 
125 \cpright Copyright (c) 2003-2020, The GENIE Collaboration
126  For the full text of the license visit http://copyright.genie-mc.org
127 
128 */
129 //____________________________________________________________________________
130 
131 #include <cstdlib>
132 #include <cassert>
133 #include <sstream>
134 #include <string>
135 #include <vector>
136 #include <map>
137 
138 #if defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT)
139 #include <fenv.h> // for `feenableexcept`
140 #endif
141 
142 #include <TFile.h>
143 #include <TTree.h>
144 #include <TSystem.h>
145 #include <TVector3.h>
146 #include <TH1.h>
147 #include <TF1.h>
148 
149 
152 #include "Framework/Conventions/GBuild.h"
170 #include "Framework/Utils/AppInit.h"
171 #include "Framework/Utils/RunOpt.h"
177 
178 #ifdef __GENIE_FLUX_DRIVERS_ENABLED__
179 #ifdef __GENIE_GEOM_DRIVERS_ENABLED__
180 #define __CAN_GENERATE_EVENTS_USING_A_FLUX_OR_TGTMIX__
184 #endif
185 #endif
186 
187 using std::string;
188 using std::vector;
189 using std::map;
190 using std::ostringstream;
191 
192 using namespace genie;
193 using namespace genie::controls;
194 using namespace genie::constants;
195 using namespace genie::units;
196 
197 void GetCommandLineArgs (int argc, char ** argv);
198 void Initialize (void);
199 void PrintSyntax (void);
200 bool CheckUnitarityLimit(void);
201 
202 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX_OR_TGTMIX__
203 void GenerateEventsUsingFluxOrTgtMix();
204 GeomAnalyzerI * GeomDriver (void);
205 GFluxI * FluxDriver (void);
206 GFluxI * MonoEnergeticFluxDriver (void);
207 GFluxI * TH1FluxDriver (void);
208 #endif
209 
211 
212 //Default options (override them using the command line arguments):
213 int kDefOptNevents = 0; // n-events to generate
215 Long_t kDefOptRunNu = 0; // default run number
216 
217 //User-specified options:
218 int gOptNevents; // n-events to generate
219 double gOptDMEnergy; // dark matter E, or min dark matter energy in spectrum
220 double gOptDMEnergyRange;// energy range in input spectrum
221 double gOptDMMass; // dark matter mass
222 double gOptZpCoupling; // mediator coupling
223 map<int,double> gOptTgtMix; // target mix (each with its relative weight)
224 double gOptMedRatio; // ratio of mediator to DM mass
225 Long_t gOptRunNu; // run number
226 string gOptFlux; //
227 bool gOptWeighted; //
229 long int gOptRanSeed; // random number seed
230 string gOptInpXSecFile; // cross-section splines
231 string gOptOutFileName; // Optional outfile name
232 string gOptStatFileName; // Status file name, set if gOptOutFileName was set.
233 
234 //____________________________________________________________________________
235 int main(int argc, char ** argv)
236 {
237  GetCommandLineArgs(argc,argv);
239  if (gOptZpCoupling > 0.) {
240  Registry * r = AlgConfigPool::Instance()->CommonList("Param", "BoostedDarkMatter");
241  r->UnLock();
242  r->Set("ZpCoupling", gOptZpCoupling);
243  r->Lock();
244  }
245  Initialize();
246 
247 
248  // throw on NaNs and Infs...
249 #if defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT)
250  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
251 #endif
252  //
253  // Generate dark matter events
254  //
255 
257 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX_OR_TGTMIX__
258  GenerateEventsUsingFluxOrTgtMix();
259 #else
260  LOG("gevgen_dm", pERROR)
261  << "\n To be able to generate dark matter events from a flux and/or a target mix"
262  << "\n you need to add the following config options at your GENIE installation:"
263  << "\n --enable-flux-drivers --enable-geom-drivers \n" ;
264 #endif
265  } else {
267  }
268  return 0;
269 }
270 //____________________________________________________________________________
272 {
273 
274  if ( ! RunOpt::Instance()->Tune() ) {
275  LOG("gmkspl", pFATAL) << " No TuneId in RunOption";
276  exit(-1);
277  }
279 
280  // Initialization of random number generators, cross-section table,
281  // messenger thresholds, cache file
282  utils::app_init::MesgThresholds(RunOpt::Instance()->MesgThresholdFiles());
286 
287  // Set GHEP print level
288  GHepRecord::SetPrintLevel(RunOpt::Instance()->EventRecordPrintLevel());
289 }
290 //____________________________________________________________________________
292 {
293  int dark_matter = kPdgDarkMatter;
294  int target = gOptTgtMix.begin()->first;
295  double Ed = gOptDMEnergy;
296  double Md = gOptDMMass;
297  double pd = TMath::Sqrt(Ed*Ed - Md*Md);
298  assert(pd>=0.);
299  TLorentzVector dm_p4(0.,0.,pd,Ed); // px,py,pz,E (GeV)
300 
301  // Create init state
302  InitialState init_state(target, dark_matter);
303 
304  bool unitary = CheckUnitarityLimit();
305  if (!unitary) {
306  LOG("gevgen_dm", pFATAL)
307  << "Cross-section risks exceeding unitarity limit - Exiting";
308  exit(1);
309  }
310 
311 
312  // Create/config event generation driver
313  GEVGDriver evg_driver;
315  evg_driver.SetUnphysEventMask(*RunOpt::Instance()->UnphysEventMask());
316  evg_driver.Configure(init_state);
317 
318  // Initialize an Ntuple Writer
320 
321  // If an output file name has been specified... use it
322  if (!gOptOutFileName.empty()){
324  }
325  ntpw.Initialize();
326 
327 
328  // Create an MC Job Monitor
329  GMCJMonitor mcjmonitor(gOptRunNu);
330  mcjmonitor.SetRefreshRate(RunOpt::Instance()->MCJobStatusRefreshRate());
331 
332  // If a status file name has been given... use it
333  if (!gOptStatFileName.empty()){
335  }
336 
337 
338  LOG("gevgen_dm", pNOTICE)
339  << "\n ** Will generate " << gOptNevents << " events for \n"
340  << init_state << " at Ev = " << Ed << " GeV";
341 
342  // Generate events / print the GHEP record / add it to the ntuple
343  int ievent = 0;
344  while (ievent < gOptNevents) {
345  LOG("gevgen_dm", pNOTICE)
346  << " *** Generating event............ " << ievent;
347 
348  // generate a single event
349  EventRecord * event = evg_driver.GenerateEvent(dm_p4);
350 
351  if(!event) {
352  LOG("gevgen_dm", pNOTICE)
353  << "Last attempt failed. Re-trying....";
354  continue;
355  }
356 
357  LOG("gevgen_dm", pNOTICE)
358  << "Generated Event GHEP Record: " << *event;
359 
360  // add event at the output ntuple, refresh the mc job monitor & clean up
361  ntpw.AddEventRecord(ievent, event);
362  mcjmonitor.Update(ievent,event);
363  ievent++;
364  delete event;
365  }
366 
367  // Save the generated MC events
368  ntpw.Save();
369 }
370 //____________________________________________________________________________
371 
372 #ifdef __CAN_GENERATE_EVENTS_USING_A_FLUX_OR_TGTMIX__
373 //............................................................................
374 void GenerateEventsUsingFluxOrTgtMix(void)
375 {
376  // Get flux and geom drivers
377  GFluxI * flux_driver = FluxDriver();
378  GeomAnalyzerI * geom_driver = GeomDriver();
379 
380  // Create the monte carlo job driver
381  GMCJDriver * mcj_driver = new GMCJDriver;
383  mcj_driver->SetUnphysEventMask(*RunOpt::Instance()->UnphysEventMask());
384  mcj_driver->UseFluxDriver(flux_driver);
385  mcj_driver->UseGeomAnalyzer(geom_driver);
386  mcj_driver->Configure();
387  mcj_driver->UseSplines();
388  if(!gOptWeighted)
389  mcj_driver->ForceSingleProbScale();
390 
391  // Initialize an Ntuple Writer to save GHEP records into a TTree
393 
394  // If an output file name has been specified... use it
395  if (!gOptOutFileName.empty()){
397  }
398  ntpw.Initialize();
399 
400  // Create an MC Job Monitor
401  GMCJMonitor mcjmonitor(gOptRunNu);
402  mcjmonitor.SetRefreshRate(RunOpt::Instance()->MCJobStatusRefreshRate());
403 
404  // If a status file name has been given... use it
405  if (!gOptStatFileName.empty()){
407  }
408 
409 
410  // Generate events / print the GHEP record / add it to the ntuple
411  int ievent = 0;
412  while ( ievent < gOptNevents) {
413 
414  LOG("gevgen_dm", pNOTICE) << " *** Generating event............ " << ievent;
415 
416  // generate a single event for dark matter particles coming from the specified flux
417  EventRecord * event = mcj_driver->GenerateEvent();
418 
419  LOG("gevgen_dm", pNOTICE) << "Generated Event GHEP Record: " << *event;
420 
421  // add event at the output ntuple, refresh the mc job monitor & clean-up
422  ntpw.AddEventRecord(ievent, event);
423  mcjmonitor.Update(ievent,event);
424  ievent++;
425  delete event;
426  }
427 
428  // Save the generated MC events
429  ntpw.Save();
430 
431  delete flux_driver;
432  delete geom_driver;
433  delete mcj_driver;;
434 }
435 //____________________________________________________________________________
436 GeomAnalyzerI * GeomDriver(void)
437 {
438 // create a trivial point geometry with the specified target or target mix
439 
440  GeomAnalyzerI * geom_driver = new geometry::PointGeomAnalyzer(gOptTgtMix);
441  return geom_driver;
442 }
443 //____________________________________________________________________________
444 GFluxI * FluxDriver(void)
445 {
446 // create & configure one of the generic flux drivers
447 //
448  GFluxI * flux_driver = 0;
449 
450  if(gOptDMEnergyRange<0) flux_driver = MonoEnergeticFluxDriver();
451  else flux_driver = TH1FluxDriver();
452 
453  return flux_driver;
454 }
455 //____________________________________________________________________________
456 GFluxI * MonoEnergeticFluxDriver(void)
457 {
458 //
459 //
460  flux::GMonoEnergeticFlux * flux =
462  GFluxI * flux_driver = dynamic_cast<GFluxI *>(flux);
463  return flux_driver;
464 }
465 //____________________________________________________________________________
466 GFluxI * TH1FluxDriver(void)
467 {
468 //
469 //
471  TH1D * spectrum = 0;
472 
473  int flux_entries = 100000;
474 
475  double emin = gOptDMEnergy;
476  double emax = gOptDMEnergy+gOptDMEnergyRange;
477  double de = gOptDMEnergyRange;
478 
479  // check whether the input flux is a file or a functional form
480  //
481  bool input_is_text_file = ! gSystem->AccessPathName(gOptFlux.c_str());
482  bool input_is_root_file = gOptFlux.find(".root") != string::npos &&
483  gOptFlux.find(",") != string::npos;
484  if(input_is_text_file) {
485  //
486  // ** generate the flux histogram from the x,y pairs in the input text file
487  //
488  Spline * input_flux = new Spline(gOptFlux.c_str());
489  int n = 100;
490  double estep = (emax-emin)/(n-1);
491  double ymax = -1, ry = -1, gy = -1, e = -1;
492  for(int i=0; i<n; i++) {
493  e = emin + i*estep;
494  ymax = TMath::Max(ymax, input_flux->Evaluate(e));
495  }
496  ymax *= 1.3;
497 
499  spectrum = new TH1D("spectrum","dark matter flux", 300, emin, emax);
500  spectrum->SetDirectory(0);
501 
502  for(int ientry=0; ientry<flux_entries; ientry++) {
503  bool accept = false;
504  unsigned int iter=0;
505  while(!accept) {
506  iter++;
507  if(iter > kRjMaxIterations) {
508  LOG("gevgen_dm", pFATAL) << "Couldn't generate a flux histogram";
509  exit(1);
510  }
511  e = emin + de * r->RndGen().Rndm();
512  gy = ymax * r->RndGen().Rndm();
513  ry = input_flux->Evaluate(e);
514  accept = gy < ry;
515  if(accept) spectrum->Fill(e);
516  }
517  }
518  delete input_flux;
519  }
520  else if(input_is_root_file) {
521  //
522  // ** extract specified flux histogram from the input root file
523  //
524  vector<string> fv = utils::str::Split(gOptFlux,",");
525  assert(fv.size()==2);
526  assert( !gSystem->AccessPathName(fv[0].c_str()) );
527 
528  LOG("gevgen_dm", pNOTICE) << "Getting input flux from root file: " << fv[0];
529  TFile * flux_file = new TFile(fv[0].c_str(),"read");
530 
531  LOG("gevgen_dm", pNOTICE) << "Flux name: " << fv[1];
532  TH1D * hst = (TH1D *)flux_file->Get(fv[1].c_str());
533  assert(hst);
534 
535  LOG("gevgen_dm", pNOTICE) << hst->GetEntries();
536 
537  // Copy in the flux histogram from the root file and remove bins outside the emin,emax range
538  spectrum = (TH1D*)hst->Clone();
539  spectrum->SetNameTitle("spectrum","dark_matter_flux");
540  spectrum->SetDirectory(0);
541  for(int ibin = 1; ibin <= hst->GetNbinsX(); ibin++) {
542  if(hst->GetBinLowEdge(ibin) + hst->GetBinWidth(ibin) > emax ||
543  hst->GetBinLowEdge(ibin) < emin) {
544  spectrum->SetBinContent(ibin, 0);
545  }
546  }
547 
548  LOG("gevgen_dm", pNOTICE) << spectrum->GetEntries();
549 
550  flux_file->Close();
551  delete flux_file;
552 
553  LOG("gevgen_dm", pNOTICE) << spectrum->GetEntries();
554 
555  } else {
556  //
557  // ** generate the flux histogram from the input functional form
558  //
559  TF1 * input_func = new TF1("input_func", gOptFlux.c_str(), emin, emax);
560  spectrum = new TH1D("spectrum","dark matter flux", 300, emin, emax);
561  spectrum->SetDirectory(0);
562  spectrum->FillRandom("input_func", flux_entries);
563  delete input_func;
564  }
565  // save input flux
566 
567  TFile f("./input-flux.root","recreate");
568  spectrum->Write();
569  f.Close();
570 
571  TVector3 bdir (0,0,1);
572  TVector3 bspot(0,0,0);
573 
574  flux->SetNuDirection (bdir);
575  flux->SetBeamSpot (bspot);
576  flux->SetTransverseRadius (-1);
577  flux->AddEnergySpectrum (kPdgDarkMatter, spectrum);
578 
579  GFluxI * flux_driver = dynamic_cast<GFluxI *>(flux);
580  return flux_driver;
581 }
582 //............................................................................
583 #endif
584 
585 //____________________________________________________________________________
586 void GetCommandLineArgs(int argc, char ** argv)
587 {
588  LOG("gevgen_dm", pINFO) << "Parsing command line arguments";
589 
590  // Common run options. Set defaults and read.
593 
594  // Parse run options for this app
595 
596  CmdLnArgParser parser(argc,argv);
597 
598  // help?
599  bool help = parser.OptionExists('h');
600  if(help) {
601  PrintSyntax();
602  exit(0);
603  }
604 
605  if ( ! parser.OptionExists("tune") ) {
606  LOG("gevgen_dm", pFATAL) << "No Dark Matter tune selected, please select one ";
607  LOG("gevgen_dm", pFATAL) << "Exiting ";
608  exit( 0 ) ;
609  }
610 
611  // number of events
612  if( parser.OptionExists('n') ) {
613  LOG("gevgen_dm", pINFO) << "Reading number of events to generate";
614  gOptNevents = parser.ArgAsInt('n');
615  } else {
616  LOG("gevgen_dm", pINFO)
617  << "Unspecified number of events to generate - Using default";
619  }
620 
621  // run number
622  if( parser.OptionExists('r') ) {
623  LOG("gevgen_dm", pINFO) << "Reading MC run number";
624  gOptRunNu = parser.ArgAsLong('r');
625  } else {
626  LOG("gevgen_dm", pINFO) << "Unspecified run number - Using default";
628  }
629 
630  // Output file name
631  if( parser.OptionExists('o') ) {
632  LOG("gevgen_dm", pINFO) << "Reading output file name";
633  gOptOutFileName = parser.ArgAsString('o');
634 
636  // strip the output file format and replace with .status
637  if (gOptOutFileName.find_last_of(".") != string::npos)
639  gOptStatFileName.substr(0, gOptOutFileName.find_last_of("."));
640  gOptStatFileName .append(".status");
641  }
642 
643  // flux functional form
644  bool using_flux = false;
645  if( parser.OptionExists('f') ) {
646  LOG("gevgen_dm", pINFO) << "Reading flux function";
647  gOptFlux = parser.ArgAsString('f');
648  using_flux = true;
649  }
650 
651  if(parser.OptionExists('s')) {
652  LOG("gevgen_dm", pWARN)
653  << "-s option no longer available. Please read the revised code documentation";
654  gAbortingInErr = true;
655  exit(1);
656  }
657 
658 
659  // generate weighted events option (only relevant if using a flux)
660  gOptWeighted = parser.OptionExists('w');
661 
662  // dark matter energy
663  if( parser.OptionExists('e') ) {
664  LOG("gevgen_dm", pINFO) << "Reading dark matter energy";
665  string dme = parser.ArgAsString('e');
666 
667  // is it just a value or a range (comma separated set of values)
668  if(dme.find(",") != string::npos) {
669  // split the comma separated list
670  vector<string> nurange = utils::str::Split(dme, ",");
671  assert(nurange.size() == 2);
672  double emin = atof(nurange[0].c_str());
673  double emax = atof(nurange[1].c_str());
674  assert(emax>emin && emin>=0);
675  gOptDMEnergy = emin;
676  gOptDMEnergyRange = emax-emin;
677  if(!using_flux) {
678  LOG("gevgen_dm", pWARN)
679  << "No flux was specified but an energy range was input!";
680  LOG("gevgen_dm", pWARN)
681  << "Events will be generated at fixed E = " << gOptDMEnergy << " GeV";
682  gOptDMEnergyRange = -1;
683  }
684  } else {
685  gOptDMEnergy = atof(dme.c_str());
686  gOptDMEnergyRange = -1;
687  }
688  } else {
689  LOG("gevgen_dm", pFATAL) << "Unspecified dark matter energy - Exiting";
690  PrintSyntax();
691  exit(1);
692  }
693 
694  // dark matter mass
695  if( parser.OptionExists('m') ) {
696  LOG("gevgen_dm", pINFO) << "Reading dark matter mass";
697  gOptDMMass = parser.ArgAsDouble('m');
698  } else {
699  LOG("gevgen_dm", pFATAL) << "Unspecified dark matter mass - Exiting";
700  PrintSyntax();
701  exit(1);
702  }
703 
704  // mediator coupling
705  if( parser.OptionExists('g') ) {
706  LOG("gevgen_dm", pINFO) << "Reading mediator coupling";
707  gOptZpCoupling = parser.ArgAsDouble('g');
708  } else {
709  LOG("gevgen_dm", pINFO) << "Unspecified mediator coupling - Using value from config file";
710  gOptZpCoupling = -1.;
711  }
712 
713  // target mix (their PDG codes with their corresponding weights)
714  bool using_tgtmix = false;
715  if( parser.OptionExists('t') ) {
716  LOG("gevgen_dm", pINFO) << "Reading target mix";
717  string stgtmix = parser.ArgAsString('t');
718  gOptTgtMix.clear();
719  vector<string> tgtmix = utils::str::Split(stgtmix,",");
720  if(tgtmix.size()==1) {
721  int pdg = atoi(tgtmix[0].c_str());
722  double wgt = 1.0;
723  gOptTgtMix.insert(map<int, double>::value_type(pdg, wgt));
724  } else {
725  using_tgtmix = true;
726  vector<string>::const_iterator tgtmix_iter = tgtmix.begin();
727  for( ; tgtmix_iter != tgtmix.end(); ++tgtmix_iter) {
728  string tgt_with_wgt = *tgtmix_iter;
729  string::size_type open_bracket = tgt_with_wgt.find("[");
730  string::size_type close_bracket = tgt_with_wgt.find("]");
731  string::size_type ibeg = 0;
732  string::size_type iend = open_bracket;
733  string::size_type jbeg = open_bracket+1;
734  string::size_type jend = close_bracket-1;
735  int pdg = atoi(tgt_with_wgt.substr(ibeg,iend).c_str());
736  double wgt = atof(tgt_with_wgt.substr(jbeg,jend).c_str());
737  LOG("Main", pNOTICE)
738  << "Adding to target mix: pdg = " << pdg << ", wgt = " << wgt;
739  gOptTgtMix.insert(map<int, double>::value_type(pdg, wgt));
740  }//tgtmix_iter
741  }//>1
742 
743  } else {
744  LOG("gevgen_dm", pFATAL) << "Unspecified target PDG code - Exiting";
745  PrintSyntax();
746  exit(1);
747  }
748 
749  // mediator mass ratio
750  if( parser.OptionExists('z') ) {
751  LOG("gevgen_dm", pINFO) << "Reading mediator mass ratio";
752  gOptMedRatio = parser.ArgAsDouble('z');
753  } else {
754  LOG("gevgen_dm", pINFO) << "Unspecified mediator mass ratio - Using default";
755  gOptMedRatio = 0.5;
756  }
757 
758  gOptUsingFluxOrTgtMix = using_flux || using_tgtmix;
759 
760  // random number seed
761  if( parser.OptionExists("seed") ) {
762  LOG("gevgen_dm", pINFO) << "Reading random number seed";
763  gOptRanSeed = parser.ArgAsLong("seed");
764  } else {
765  LOG("gevgen_dm", pINFO) << "Unspecified random number seed - Using default";
766  gOptRanSeed = -1;
767  }
768 
769  // input cross-section file
770  if( parser.OptionExists("cross-sections") ) {
771  LOG("gevgen_dm", pINFO) << "Reading cross-section file";
772  gOptInpXSecFile = parser.ArgAsString("cross-sections");
773  } else {
774  LOG("gevgen_dm", pINFO) << "Unspecified cross-section file";
775  gOptInpXSecFile = "";
776  }
777 
778  //
779  // print-out the command line options
780  //
781  LOG("gevgen_dm", pNOTICE)
782  << "\n"
783  << utils::print::PrintFramedMesg("gevgen_dm job configuration");
784  LOG("gevgen_dm", pNOTICE)
785  << "MC Run Number: " << gOptRunNu;
786  if(gOptRanSeed != -1) {
787  LOG("gevgen_dm", pNOTICE)
788  << "Random number seed: " << gOptRanSeed;
789  } else {
790  LOG("gevgen_dm", pNOTICE)
791  << "Random number seed was not set, using default";
792  }
793  LOG("gevgen_dm", pNOTICE)
794  << "Number of events requested: " << gOptNevents;
795  if(gOptInpXSecFile.size() > 0) {
796  LOG("gevgen_dm", pNOTICE)
797  << "Using cross-section splines read from: " << gOptInpXSecFile;
798  } else {
799  LOG("gevgen_dm", pNOTICE)
800  << "No input cross-section spline file";
801  }
802  LOG("gevgen_dm", pNOTICE)
803  << "Flux: " << gOptFlux;
804  LOG("gevgen_dm", pNOTICE)
805  << "Generate weighted events? " << gOptWeighted;
806  if(gOptDMEnergyRange>0) {
807  LOG("gevgen_dm", pNOTICE)
808  << "Dark matter energy: ["
809  << gOptDMEnergy << ", " << gOptDMEnergy+gOptDMEnergyRange << "]";
810  } else {
811  LOG("gevgen_dm", pNOTICE)
812  << "Dark matter energy: " << gOptDMEnergy;
813  }
814  LOG("gevgen_dm", pNOTICE)
815  << "Dark matter mass: " << gOptDMMass;
816  LOG("gevgen_dm", pNOTICE)
817  << "Target code (PDG) & weight fraction (in case of multiple targets): ";
818  LOG("gevgen_dm", pNOTICE)
819  << "Mediator mass ratio: " << gOptMedRatio;
821  for(iter = gOptTgtMix.begin(); iter != gOptTgtMix.end(); ++iter) {
822  int tgtpdgc = iter->first;
823  double wgt = iter->second;
824  LOG("gevgen_dm", pNOTICE)
825  << " >> " << tgtpdgc << " (weight fraction = " << wgt << ")";
826  }
827  LOG("gevgen_dm", pNOTICE) << "\n";
828 
829  LOG("gevgen_dm", pNOTICE) << *RunOpt::Instance();
830 
831 }
832 //____________________________________________________________________________
833 void PrintSyntax(void)
834 {
835  LOG("gevgen_dm", pNOTICE)
836  << "\n\n" << "Syntax:" << "\n"
837  << "\n gevgen_dm [-h]"
838  << "\n [-r run#]"
839  << "\n -n nev"
840  << "\n -e energy (or energy range) "
841  << "\n -m mass"
842  << "\n -t target_pdg "
843  << "\n [-g zp_coupling]"
844  << "\n [-z med_ratio]"
845  << "\n [-f flux_description]"
846  << "\n [-o outfile_name]"
847  << "\n [-w]"
848  << "\n [--seed random_number_seed]"
849  << "\n [--cross-sections xml_file]"
850  << "\n [--event-generator-list list_name]"
851  << "\n [--message-thresholds xml_file]"
852  << "\n [--unphysical-event-mask mask]"
853  << "\n [--event-record-print-level level]"
854  << "\n [--mc-job-status-refresh-rate rate]"
855  << "\n [--cache-file root_file]"
856  << "\n";
857 }
858 //____________________________________________________________________________
860 {
861  // Before generating the events, perform a simple sanity check
862  // We estimate the leading divergent piece of the cross-section
863  // We make sure it does not exceed the unitarity limit
864  double gzp;
865  Registry * r = AlgConfigPool::Instance()->CommonList("Param", "BoostedDarkMatter");
866  r->Get("ZpCoupling", gzp);
867  double gzp4 = TMath::Power(gzp,4);
868  double Mzp = gOptMedRatio * gOptDMMass;
869  double Mzp2 = Mzp*Mzp;
870  // The leading, forward-dominated piece is the same for both DM models
871  double xsec_est = gzp4 / (4. * kPi * Mzp2);
872  double ml = gOptDMMass;
873  double ml2 = ml*ml;
874  double M = kNucleonMass;
875  double M2 = M*M;
876  double Ed = gOptDMEnergy;
877  double Ed2 = Ed*Ed;
878  double pcm2 = M2 * (Ed2 - ml2) / (ml2 + M2 + 2.*M*Ed);
879  double xsec_lim = kPi / pcm2;
880  bool unitary = xsec_lim > xsec_est;
881  if (!unitary) {
882  LOG("gevgen_dm", pWARN)
883  << "Estimated a cross-section " << xsec_est/cm2 << " cm^2";
884  LOG("gevgen_dm", pWARN)
885  << "Unitarity limit set to " << xsec_lim/cm2 << " cm^2";
886  }
887  return unitary;
888 }
889 //____________________________________________________________________________
void RandGen(long int seed)
Definition: AppInit.cxx:30
static void SetPrintLevel(int print_level)
Definition: GHepRecord.cxx:948
void XSecTable(string inpfile, bool require_table)
Definition: AppInit.cxx:38
void GenerateEventsAtFixedInitState(void)
Definition: gEvGenDM.cxx:291
long ArgAsLong(char opt)
void SetUnphysEventMask(const TBits &mask)
Definition: GMCJDriver.cxx:74
Basic constants.
double ArgAsDouble(char opt)
Physical System of Units.
string ArgAsString(char opt)
THE MAIN GENIE PROJECT NAMESPACE
Definition: AlgCmp.h:25
#define pERROR
Definition: Messenger.h:59
bool CheckUnitarityLimit(void)
Definition: gEvGenDM.cxx:859
double gOptDMMass
Definition: gEvGenDM.cxx:221
void AddDarkMatter(double mass, double med_ratio)
Definition: PDGLibrary.cxx:142
static const double kNucleonMass
Definition: Constants.h:77
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:71
void SetEventGeneratorList(string listname)
Definition: GMCJDriver.cxx:66
void CustomizeFilename(string filename)
Definition: NtpWriter.cxx:128
std::string string
Definition: nybbler.cc:12
Long_t gOptRunNu
Definition: gEvGenDM.cxx:225
void ReadFromCommandLine(int argc, char **argv)
Definition: RunOpt.cxx:99
double gOptMedRatio
Definition: gEvGenDM.cxx:224
A numeric analysis tool class for interpolating 1-D functions.
Definition: Spline.h:46
#define pFATAL
Definition: Messenger.h:56
const int kPdgDarkMatter
Definition: PDGCodes.h:218
double gOptZpCoupling
Definition: gEvGenDM.cxx:222
struct vector vector
int main(int argc, char **argv)
Definition: gEvGenDM.cxx:235
double gOptDMEnergy
Definition: gEvGenDM.cxx:219
void Update(int iev, const EventRecord *event)
Definition: GMCJMonitor.cxx:48
void CustomizeFilename(string filename)
Definition: GMCJMonitor.cxx:97
intermediate_table::const_iterator const_iterator
double Evaluate(double x) const
Definition: Spline.cxx:361
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition: RandomGen.h:29
string gOptOutFileName
Definition: gEvGenDM.cxx:231
int gOptNevents
Definition: gEvGenDM.cxx:218
Registry * CommonList(const string &file_id, const string &set_name) const
string gOptStatFileName
Definition: gEvGenDM.cxx:232
void SetRefreshRate(int rate)
Definition: GMCJMonitor.cxx:43
Long_t kDefOptRunNu
Definition: gEvGenDM.cxx:215
void UseFluxDriver(GFluxI *flux)
Definition: GMCJDriver.cxx:83
long int gOptRanSeed
Definition: gEvGenDM.cxx:229
Simple class to create & update MC job status files and env. vars. This is used to be able to keep tr...
Definition: GMCJMonitor.h:31
A GENIE `MC Job Driver&#39;. Can be used for setting up complicated event generation cases involving deta...
Definition: GMCJDriver.h:46
void Get(RgKey key, const RegistryItemI *&item) const
Definition: Registry.cxx:325
const double e
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:96
void SetEventGeneratorList(string listname)
Definition: GEVGDriver.cxx:348
static constexpr double cm2
Definition: Units.h:69
void ForceSingleProbScale(void)
Definition: GMCJDriver.cxx:172
std::void_t< T > n
A generic GENIE flux driver. Generates a &#39;cylindrical&#39; neutrino beam along the input direction...
string gOptInpXSecFile
Definition: gEvGenDM.cxx:230
A simple GENIE flux driver for monoenergetic neutrinos along the z direction. Can handle a mix of neu...
NtpMCFormat_t kDefOptNtpFormat
Definition: gEvGenDM.cxx:214
void GetCommandLineArgs(int argc, char **argv)
Definition: gEvGenDM.cxx:586
void Configure(bool calc_prob_scales=true)
Definition: GMCJDriver.cxx:399
void Save(void)
get the even tree
Definition: NtpWriter.cxx:225
GENIE Event Generation Driver. A minimalist user interface object for generating neutrino interaction...
Definition: GEVGDriver.h:54
#define pINFO
Definition: Messenger.h:62
void Lock(void)
locks the registry
Definition: Registry.cxx:148
void AddEventRecord(int ievent, const EventRecord *ev_rec)
save the event tree
Definition: NtpWriter.cxx:57
void SetTransverseRadius(double Rt)
Misc GENIE control constants.
void SetNuDirection(const TVector3 &direction)
map< int, double > gOptTgtMix
Definition: gEvGenDM.cxx:223
void BuildTune()
build tune and inform XSecSplineList
Definition: RunOpt.cxx:92
#define pWARN
Definition: Messenger.h:60
EventRecord * GenerateEvent(void)
Definition: GMCJDriver.cxx:812
double gOptDMEnergyRange
Definition: gEvGenDM.cxx:220
void UnLock(void)
unlocks the registry (doesn&#39;t unlock items)
Definition: Registry.cxx:153
Generated Event Record. It is a GHepRecord object that can accept / be visited by EventRecordVisitorI...
Definition: EventRecord.h:37
void Initialize(void)
add event
Definition: NtpWriter.cxx:83
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:57
static RunOpt * Instance(void)
Definition: RunOpt.cxx:54
vector< string > Split(string input, string delim)
Definition: StringUtils.cxx:36
A utility class to facilitate creating the GENIE MC Ntuple from the output GENIE GHEP event records...
Definition: NtpWriter.h:39
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
void Initialize(void)
Definition: gEvGenDM.cxx:271
TRandom3 & RndGen(void) const
rnd number generator for generic usage
Definition: RandomGen.h:80
int kDefOptNevents
Definition: gEvGenDM.cxx:213
string gOptFlux
Definition: gEvGenDM.cxx:226
void Configure(int nu_pdgc, int Z, int A)
Definition: GEVGDriver.cxx:137
bool gOptUsingFluxOrTgtMix
Definition: gEvGenDM.cxx:228
string PrintFramedMesg(string mesg, unsigned int nl=1, const char f='*')
Definition: PrintUtils.cxx:164
A vector of EventGeneratorI objects.
bool gOptWeighted
Definition: gEvGenDM.cxx:227
void SetBeamSpot(const TVector3 &spot)
void MesgThresholds(string inpfile)
Definition: AppInit.cxx:99
void AddEnergySpectrum(int nu_pdgc, TH1D *spectrum)
Command line argument parser.
enum genie::ENtpMCFormat NtpMCFormat_t
#define pNOTICE
Definition: Messenger.h:61
Defines the GENIE Geometry Analyzer Interface.
Definition: GeomAnalyzerI.h:29
static const unsigned int kRjMaxIterations
Definition: Controls.h:26
void SetUnphysEventMask(const TBits &mask)
Definition: GEVGDriver.cxx:219
bool gAbortingInErr
Definition: Messenger.cxx:34
void Set(RgIMapPair entry)
Definition: Registry.cxx:267
static const double kPi
Definition: Constants.h:37
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils...
void UseGeomAnalyzer(GeomAnalyzerI *geom)
Definition: GMCJDriver.cxx:88
void UseSplines(bool useLogE=true)
Definition: GMCJDriver.cxx:93
The PointGeomAnalyzer class is the simplest implementation of the GeomAnalyserI interface and defines...
bool OptionExists(char opt)
was option set?
void CacheFile(string inpfile)
Definition: AppInit.cxx:117
void EnableBareXSecPreCalc(bool flag)
Definition: RunOpt.h:60
Event finding and building.
static AlgConfigPool * Instance()
Initial State information.
Definition: InitialState.h:48
GENIE Interface for user-defined flux classes.
Definition: GFluxI.h:29
EventRecord * GenerateEvent(const TLorentzVector &nu4p)
Definition: GEVGDriver.cxx:228
void PrintSyntax(void)
Definition: gEvGenDM.cxx:833