GENIEGenerator
Loading...
Searching...
No Matches
gBeamHNLParticleGun.cxx
Go to the documentation of this file.
1//________________________________________________________________________________________
2/*!
3
4\program gevgen_pghnl
5
6\brief A particle gun for long-lived HNL.
7
8 *** Synopsis :
9
10 gevgen_pghnl [-h]
11 [-r run#]
12 -n n_of_events
13 [-m decay_mode]
14 [-g geometry (ROOT file)]
15 [-L geometry_length_units]
16 [-t geometry_top_volume_name]
17 [-o output_event_file_prefix]
18 [--seed random_number_seed]
19 [--message-thresholds xml_file]
20 [--event-record-print-level level]
21 [--mc-job-status-refresh-rate rate]
22
23 *** Options :
24
25 [] Denotes an optional argument
26
27 -h
28 Prints out the gevgen_pghnl syntax and exits.
29 -r
30 Specifies the MC run number [default: 1000].
31 -n
32 Specifies how many events to generate.
33 -m
34 HNL decay mode ID:
35 -g
36 Input detector geometry.
37 If a geometry is specified, HNL decay vertices will be distributed
38 in the desired detector volume.
39 Using this argument, you can pass a ROOT file containing your
40 detector geometry description.
41 -L
42 Input geometry length units, eg 'm', 'cm', 'mm', ...
43 [default: 'mm']
44 -o
45 Sets the prefix of the output event file.
46 The output filename is built as:
47 [prefix].[run_number].[event_tree_format].[file_format]
48 The default output filename is:
49 gntp.[run_number].ghep.root
50 This cmd line arguments lets you override 'gntp'
51 --seed
52 Random number seed.
53
54\author Costas Andreopoulos <c.andreopoulos \at cern.ch>
55 University of Liverpool
56 John Plows <komninos-john.plows \at physics.ox.ac.uk>
57 University of Oxford
58
59\created May 27th, 2022
60
61\cpright Copyright (c) 2003-2025, The GENIE Collaboration
62 For the full text of the license visit http://copyright.genie-mc.org
63
64*/
65//_________________________________________________________________________________________
66
67#include <cassert>
68#include <cstdlib>
69#include <string>
70#include <vector>
71#include <sstream>
72
73#include <TSystem.h>
74
100
101using std::string;
102using std::vector;
103using std::ostringstream;
104
105using namespace genie;
106using namespace genie::hnl;
107using namespace genie::hnl::enums;
108
109#ifdef __GENIE_GEOM_DRIVERS_ENABLED__
110#define __CAN_USE_ROOT_GEOM__
111#include <TGeoVolume.h>
112#include <TGeoManager.h>
113#include <TGeoShape.h>
114#include <TGeoBBox.h>
115#endif // #ifdef __GENIE_GEOM_DRIVERS_ENABLED__
116
117// function prototypes
118void GetCommandLineArgs (int argc, char ** argv);
119void PrintSyntax (void);
120
121int SelectDecayMode (std::vector<HNLDecayMode_t> *intChannels, SimpleHNL sh);
123
124TLorentzVector * GenerateOriginPosition( GHepRecord * event );
125TLorentzVector * GenerateOriginMomentum( GHepRecord * event );
126
127TLorentzVector GeneratePosition( GHepRecord * event );
128#ifdef __CAN_USE_ROOT_GEOM__
129void InitBoundingBox (void);
130#endif // #ifdef __CAN_USE_ROOT_GEOM__
131
132//
133string kDefOptGeomLUnits = "mm"; // default geometry length units
134string kDefOptGeomDUnits = "g_cm3"; // default geometry density units
135NtpMCFormat_t kDefOptNtpFormat = kNFGHEP; // default event tree format
136string kDefOptEvFilePrefix = "gntp";
137
138string kDefOptSName = "genie::EventGenerator";
139string kDefOptSConfig = "BeamHNL";
140string kDefOptSTune = "GHNL20_00a_00_000";
141
142//
143Long_t gOptRunNu = 1000; // run number
144int gOptNev = 10; // number of events to generate
145
146double gOptEnergyHNL = -1; // HNL energy
147double gOptMassHNL = -1; // HNL mass
148double gOptECoupling = -1; // |U_e4|^2
149double gOptMCoupling = -1; // |U_m4|^2
150double gOptTCoupling = -1; // |U_t4|^2
151
152bool gOptIsMajorana = false; // is this Majorana?
153int gOptHNLKind = -1; // 0 = nu, 1 = nubar, 2 = mix
154
156std::vector< HNLDecayMode_t > gOptIntChannels; // decays to un-inhibit
157
158string gOptEvFilePrefix = kDefOptEvFilePrefix; // event file prefix
159bool gOptUsingRootGeom = false; // using root geom or target mix?
160string gOptRootGeom; // input ROOT file with realistic detector geometry
161
162#ifdef __CAN_USE_ROOT_GEOM__
163TGeoManager * gOptRootGeoManager = 0; // the workhorse geometry manager
164TGeoVolume * gOptRootGeoVolume = 0;
165#endif // #ifdef __CAN_USE_ROOT_GEOM__
166
167string gOptRootGeomTopVol = ""; // input geometry top event generation volume
168double gOptGeomLUnits = 0; // input geometry length units
169long int gOptRanSeed = -1; // random number seed
170
171// Geometry bounding box and origin - read from the input geometry file (if any)
172double fdx = 0; // half-length - x
173double fdy = 0; // half-length - y
174double fdz = 0; // half-length - z
175double fox = 0; // origin - x
176double foy = 0; // origin - y
177double foz = 0; // origin - z
178
179double NTP_IS_E = 0., NTP_IS_PX = 0., NTP_IS_PY = 0., NTP_IS_PZ = 0.;
180double NTP_FS0_E = 0., NTP_FS0_PX = 0., NTP_FS0_PY = 0., NTP_FS0_PZ = 0.;
181double NTP_FS1_E = 0., NTP_FS1_PX = 0., NTP_FS1_PY = 0., NTP_FS1_PZ = 0.;
182double NTP_FS2_E = 0., NTP_FS2_PX = 0., NTP_FS2_PY = 0., NTP_FS2_PZ = 0.;
184
185//Decayer * hnlgen = 0;
186// HNL lifetime in rest frame
187double CoMLifetime = -1.0; // GeV^{-1}
188// an array to keep production vertex
189double evProdVtx[3] = {0.0, 0.0, 0.0}; // mm
190// event weight
191double evWeight = 1.0;
192
193//_________________________________________________________________________________________
194int main(int argc, char ** argv)
195{
196 // suppress ROOT Info messages
197 gErrorIgnoreLevel = kWarning;
198
199 // Parse command line arguments
200 GetCommandLineArgs(argc,argv);
201
202 // Init messenger and random number seed
203 utils::app_init::MesgThresholds(RunOpt::Instance()->MesgThresholdFiles());
205
206 __attribute__((unused)) RandomGen * rnd = RandomGen::Instance();
207
208 // Get the HNL generator first to load config
209 // config loaded upon instantiation of HNLGenerator algorithm
210 // ==> Decayer::LoadConfig()
211 __attribute__((unused)) const EventRecordVisitorI * mcgen = HNLGenerator();
212 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
213 const Algorithm * algVtxGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::VertexGenerator", "Default");
214
215 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
216 const VertexGenerator * vtxGen = dynamic_cast< const VertexGenerator * >( algVtxGen );
217
218 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
219 if (!geom_is_accessible) {
220 LOG("gevgen_pghnl", pFATAL)
221 << "The specified ROOT geometry doesn't exist! Initialization failed!";
222 exit(1);
223 }
224 vtxGen->SetGeomFile( gOptRootGeom );
225
226 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
227
228 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
229 assert( top_volume );
230 __attribute__((unused)) TGeoShape * ts = top_volume->GetShape();
231
232 //TGeoBBox * box = (TGeoBBox *)ts;
233
234 string confString = kDefOptSName + kDefOptSConfig;
235
236 CoMLifetime = hnlgen->GetHNLLifetime();
237
238 gOptMassHNL = hnlgen->GetHNLMass();
239 std::vector< double > U4l2s = hnlgen->GetHNLCouplings();
240 gOptECoupling = U4l2s.at(0);
241 gOptMCoupling = U4l2s.at(1);
242 gOptTCoupling = U4l2s.at(2);
243 gOptIsMajorana = hnlgen->IsHNLMajorana();
244
245 std::string stIntChannels = hnlgen->GetHNLInterestingChannels(); int iChan = -1;
246 if( gOptIntChannels.size() > 0 ) gOptIntChannels.clear();
247 while( stIntChannels.size() > 0 ){ // read channels from right (lowest mass) to left (highest mass)
248 iChan++;
249 HNLDecayMode_t md = static_cast< HNLDecayMode_t >( iChan );
250 std::string tmpSt = stIntChannels.substr( stIntChannels.size()-1, stIntChannels.size() );
251 if( std::strcmp( tmpSt.c_str(), "1" ) == 0 )
252 gOptIntChannels.emplace_back( md );
253
254 stIntChannels.erase( stIntChannels.end()-1, stIntChannels.end() );
255 }
256
257 assert( gOptECoupling >= 0.0 && gOptMCoupling >= 0.0 && gOptTCoupling >= 0.0 );
258
259 // Initialize an Ntuple Writer to save GHEP records into a TTree
262 ntpw.Initialize();
263
264 LOG("gevgen_pghnl", pNOTICE)
265 << "Initialised Ntuple Writer";
266
267 // add another few branches to tree.
268 ntpw.EventTree()->Branch("hnl_mass", &gOptMassHNL, "gOptMassHNL/D");
269 ntpw.EventTree()->Branch("hnl_coup_e", &gOptECoupling, "gOptECoupling/D");
270 ntpw.EventTree()->Branch("hnl_coup_m", &gOptMCoupling, "gOptMCoupling/D");
271 ntpw.EventTree()->Branch("hnl_coup_t", &gOptTCoupling, "gOptTCoupling/D");
272 ntpw.EventTree()->Branch("hnl_ismaj", &gOptIsMajorana, "gOptIsMajorana/I");
273
274 // let's make HNL-specific FS branches until we get gntpc sorted out
275 ntpw.EventTree()->Branch("hnl_IS_E", &NTP_IS_E, "NTP_IS_E/D");
276 ntpw.EventTree()->Branch("hnl_IS_PX", &NTP_IS_PX, "NTP_IS_PX/D");
277 ntpw.EventTree()->Branch("hnl_IS_PY", &NTP_IS_PY, "NTP_IS_PY/D");
278 ntpw.EventTree()->Branch("hnl_IS_PZ", &NTP_IS_PZ, "NTP_IS_PZ/D");
279 ntpw.EventTree()->Branch("hnl_FS0_PDG", &NTP_FS0_PDG, "NTP_FS0_PDG/I");
280 ntpw.EventTree()->Branch("hnl_FS0_E", &NTP_FS0_E, "NTP_FS0_E/D");
281 ntpw.EventTree()->Branch("hnl_FS0_PX", &NTP_FS0_PX, "NTP_FS0_PX/D");
282 ntpw.EventTree()->Branch("hnl_FS0_PY", &NTP_FS0_PY, "NTP_FS0_PY/D");
283 ntpw.EventTree()->Branch("hnl_FS0_PZ", &NTP_FS0_PZ, "NTP_FS0_PZ/D");
284 ntpw.EventTree()->Branch("hnl_FS1_PDG", &NTP_FS1_PDG, "NTP_FS1_PDG/I");
285 ntpw.EventTree()->Branch("hnl_FS1_E", &NTP_FS1_E, "NTP_FS1_E/D");
286 ntpw.EventTree()->Branch("hnl_FS1_PX", &NTP_FS1_PX, "NTP_FS1_PX/D");
287 ntpw.EventTree()->Branch("hnl_FS1_PY", &NTP_FS1_PY, "NTP_FS1_PY/D");
288 ntpw.EventTree()->Branch("hnl_FS1_PZ", &NTP_FS1_PZ, "NTP_FS1_PZ/D");
289 ntpw.EventTree()->Branch("hnl_FS2_PDG", &NTP_FS2_PDG, "NTP_FS2_PDG/I");
290 ntpw.EventTree()->Branch("hnl_FS2_E", &NTP_FS2_E, "NTP_FS2_E/D");
291 ntpw.EventTree()->Branch("hnl_FS2_PX", &NTP_FS2_PX, "NTP_FS2_PX/D");
292 ntpw.EventTree()->Branch("hnl_FS2_PY", &NTP_FS2_PY, "NTP_FS2_PY/D");
293 ntpw.EventTree()->Branch("hnl_FS2_PZ", &NTP_FS2_PZ, "NTP_FS2_PZ/D");
294
295 // Create a MC job monitor for a periodically updated status file
296 GMCJMonitor mcjmonitor(gOptRunNu);
297 mcjmonitor.SetRefreshRate(RunOpt::Instance()->MCJobStatusRefreshRate());
298
299 LOG("gevgen_pghnl", pNOTICE)
300 << "Initialised MC job monitor";
301
302 // Set GHEP print level
303 GHepRecord::SetPrintLevel(RunOpt::Instance()->EventRecordPrintLevel());
304
305#ifdef __CAN_USE_ROOT_GEOM__
306 // Read geometry bounding box - for vertex position generation
307 if( gOptUsingRootGeom ){
308 InitBoundingBox();
309 }
310#endif // #ifdef __CAN_USE_ROOT_GEOM__
311
312 // read in energy. This is always constant
313 //gOptEnergyHNL = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-Energy" );
314 gOptEnergyHNL = hnlgen->GetPGunEnergy();
315 if( gOptEnergyHNL <= gOptMassHNL ){
316 LOG( "gevgen_pghnl", pFATAL )
317 << "\nInsufficient energy " << gOptEnergyHNL << " GeV for HNL of mass " << gOptMassHNL << " GeV. Exiting."
318 << "\nPlease check ${GENIE}/config/CommonHNL.xml sections \"ParamSpace\" and \"ParticleGun\"";
319 exit(1);
320 }
321 assert( gOptEnergyHNL > gOptMassHNL );
322
323 // Event loop
324 int ievent = 0;
325
326 while (1)
327 {
328 if( gOptNev >= 10000 ){
329 if( ievent % (gOptNev / 1000 ) == 0 ){
330 int irat = ievent / ( gOptNev / 1000 );
331 std::cerr << 0.1 * irat << " % " << " ( " << ievent
332 << " / " << gOptNev << " ) \r" << std::flush;
333 }
334 } else if( gOptNev >= 100 ){
335 if( ievent % (gOptNev / 10 ) == 0 ){
336 int irat = ievent / ( gOptNev / 10 );
337 std::cerr << 10.0 * irat << " % " << " ( " << ievent
338 << " / " << gOptNev << " ) \r" << std::flush;
339 }
340 }
341
342 if((ievent) == gOptNev) break;
343
344 LOG("gevgen_pghnl", pNOTICE)
345 << " *** Generating event............ " << ievent;
346
347 int hpdg = genie::kPdgHNL;
348 EventRecord * event = new EventRecord;
349
350 event->SetProbability( CoMLifetime );
351
352 int decay = (int) gOptDecayMode;
353
354 SimpleHNL sh( "HNL", ievent, hpdg, genie::kPdgKP,
356
357 const std::map< HNLDecayMode_t, double > gammaMap = sh.GetValidChannels();
359
360 if( gOptDecayMode == kHNLDcyNull ){ // select from available modes
361 LOG("gevgen_pghnl", pNOTICE)
362 << "No decay mode specified - sampling from all available modes.";
363
364 std::vector< HNLDecayMode_t > * intChannels = &gOptIntChannels;
365
366 decay = SelectDecayMode( intChannels, sh );
367 }
368
370 event->AttachSummary(interaction);
371
372 // generate origin position and momentum direction for this HNL
373 TLorentzVector * x4orig = GenerateOriginPosition( event );
374 TLorentzVector * p4HNL = GenerateOriginMomentum( event );
375
376 // and add as Particle(0)
377 GHepParticle ptHNL( kPdgHNL, kIStInitialState, -1, -1, -1, -1, *p4HNL, *x4orig );
378 event->AddParticle( ptHNL );
379
380 LOG("gevgen_pghnl", pDEBUG)
381 << "Note decay mode is " << utils::hnl::AsString(gOptDecayMode);
382
383 // Simulate decay
384 hnlgen->ProcessEventRecord(event);
385 vtxGen->ProcessEventRecord(event);
386
387 // add the FS 4-momenta to special branches
388 // Quite inelegant. Gets the job done, though
389 NTP_FS0_PDG = (event->Particle(1))->Pdg();
390 NTP_FS0_E = ((event->Particle(1))->P4())->E();
391 NTP_FS0_PX = ((event->Particle(1))->P4())->Px();
392 NTP_FS0_PY = ((event->Particle(1))->P4())->Py();
393 NTP_FS0_PZ = ((event->Particle(1))->P4())->Pz();
394 NTP_FS1_PDG = (event->Particle(2))->Pdg();
395 NTP_FS1_E = ((event->Particle(2))->P4())->E();
396 NTP_FS1_PX = ((event->Particle(2))->P4())->Px();
397 NTP_FS1_PY = ((event->Particle(2))->P4())->Py();
398 NTP_FS1_PZ = ((event->Particle(2))->P4())->Pz();
399 if( event->Particle(3) ){
400 NTP_FS2_PDG = (event->Particle(3))->Pdg();
401 NTP_FS2_E = ((event->Particle(3))->P4())->E();
402 NTP_FS2_PX = ((event->Particle(3))->P4())->Px();
403 NTP_FS2_PY = ((event->Particle(3))->P4())->Py();
404 NTP_FS2_PZ = ((event->Particle(3))->P4())->Pz();
405 }
406 else{
407 NTP_FS2_PDG = 0;
408 NTP_FS2_E = 0.0;
409 NTP_FS2_PX = 0.0;
410 NTP_FS2_PY = 0.0;
411 NTP_FS2_PZ = 0.0;
412 }
413
414 // Generate (or read) a position for the decay vertex
415 // also currently handles the event weight
416 TLorentzVector x4mm = GeneratePosition( event );
417 event->SetWeight( evWeight );
418
419 // why does InitState show the wrong p4 here?
420 interaction->InitStatePtr()->SetProbeP4( *(event->Particle(0)->P4()) );
421
422 LOG("gevgen_pghnl", pINFO)
423 << "Generated event: " << *event;
424
425 // Add event at the output ntuple, refresh the mc job monitor & clean-up
426 ntpw.AddEventRecord(ievent, event);
427 mcjmonitor.Update(ievent,event);
428 delete event;
429
430 ievent++;
431 } // event loop
432
433 // Save the generated event tree & close the output file
434 ntpw.Save();
435
436 LOG("gevgen_pghnl", pNOTICE) << "Done!";
437
438 return 0;
439}
440//_________________________________________________________________________________________
441//............................................................................
442#ifdef __CAN_USE_ROOT_GEOM__
443void InitBoundingBox(void)
444{
445// Initialise geometry bounding box, used for generating HNL vertex positions
446
447 LOG("gevgen_pghnl", pINFO)
448 << "Initialising geometry bounding box.";
449
450 fdx = 0; // half-length - x
451 fdy = 0; // half-length - y
452 fdz = 0; // half-length - z
453 fox = 0; // origin - x
454 foy = 0; // origin - y
455 foz = 0; // origin - z
456
457 if(!gOptUsingRootGeom) return;
458
459 bool geom_is_accessible = ! (gSystem->AccessPathName(gOptRootGeom.c_str()));
460 if (!geom_is_accessible) {
461 LOG("gevgen_pghnl", pFATAL)
462 << "The specified ROOT geometry doesn't exist! Initialization failed!";
463 exit(1);
464 }
465
466 if( !gOptRootGeoManager ) gOptRootGeoManager = TGeoManager::Import(gOptRootGeom.c_str());
467
468 TGeoVolume * top_volume = gOptRootGeoManager->GetTopVolume();
469 assert( top_volume );
470 TGeoShape * ts = top_volume->GetShape();
471
472 TGeoBBox * box = (TGeoBBox *)ts;
473
474 //const Algorithm * algVtxGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::VertexGenerator", "Default");
475
476 //const VertexGenerator * vtxGen = dynamic_cast< const VertexGenerator * >( algVtxGen );
477
478 //get box origin and dimensions (in the same units as the geometry)
479 fdx = box->GetDX();
480 fdy = box->GetDY();
481 fdz = box->GetDZ();
482 fox = (box->GetOrigin())[0];
483 foy = (box->GetOrigin())[1];
484 foz = (box->GetOrigin())[2];
485
486 LOG("gevgen_pghnl", pINFO)
487 << "Before conversion the bounding box has:"
488 << "\nOrigin = ( " << fox << " , " << foy << " , " << foz << " )"
489 << "\nDimensions = " << fdx << " x " << fdy << " x " << fdz
490 << "\n1cm = 1.0 unit";
491
492 // Convert from local to SI units
499
500 LOG("gevgen_pghnl", pINFO)
501 << "Initialised bounding box successfully.";
502
503}
504#endif // #ifdef __CAN_USE_ROOT_GEOM__
505//............................................................................
506//_________________________________________________________________________________________
507TLorentzVector * GenerateOriginMomentum( GHepRecord * event )
508{
509 double E = gOptEnergyHNL;
510 double M = gOptMassHNL;
511 double pMag = std::sqrt( E*E - M*M );
512
513 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
514 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
515
516 // first map directional cosines to unit sphere
517 /*
518 double cx = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cx" );
519 double cy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cy" );
520 double cz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-cz" );
521 */
522 std::vector< double > PGDirection = hnlgen->GetPGunDirection();
523 double cx = PGDirection.at(0), cy = PGDirection.at(1), cz = PGDirection.at(2);
524 double c2 = std::sqrt( cx*cx + cy*cy + cz*cz );
525 assert( c2 > 0.0 );
526
527 cx *= 1.0 / c2; cy *= 1.0 / c2; cz *= 1.0 / c2;
528
529 double theta = TMath::ACos( cz / c2 );
530 double phi = ( TMath::Sin( theta ) != 0.0 ) ? TMath::ACos( cx / ( c2 * TMath::Sin( theta ) ) ) : 0.0;
531
532 // apply uniform random deviation
533 std::vector< double > PGunDeviation = hnlgen->GetPGunDeviation();
534 /*
535 double dthetaDeg = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-DTheta" );
536 double dphiDeg = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-DPhi" );
537 */
538 double dthetaDeg = PGunDeviation.at(0), dphiDeg = PGunDeviation.at(1);
539 double dThetaMax = dthetaDeg * constants::kPi / 180.0;
540 double dPhiMax = dphiDeg * constants::kPi / 180.0;
541
543 double dTheta = rng->RndGen().Uniform( -dThetaMax, dThetaMax );
544 double dPhi = rng->RndGen().Uniform( -dPhiMax, dPhiMax );
545
546 std::ostringstream asts;
547 asts
548 << "Output details for the momentum:"
549 << "\nDirectional cosines: ( " << cx << ", " << cy << ", " << cz << " )"
550 << "\nMapped to ( " << theta * 180.0 / constants::kPi
551 << ", " << phi * 180.0 / constants::kPi << " ) [deg] on unit sphere"
552 << "\nApplied deviation: dTheta = " << dTheta * 180.0 / constants::kPi
553 << ", dPhi = " << dPhi * 180.0 / constants::kPi << " [deg]";
554
555 // make momentum
556 theta += dTheta; phi += dPhi;
557 TLorentzVector * p4HNL = new TLorentzVector();
558 p4HNL->SetPxPyPzE( pMag * TMath::Sin( theta ) * TMath::Cos( phi ),
559 pMag * TMath::Sin( theta ) * TMath::Sin( phi ),
560 pMag * TMath::Cos( theta ), E );
561
562 asts << "\nMomentum = " << utils::print::P4AsString( p4HNL );
563
564 Interaction * interaction = event->Summary();
565 interaction->InitStatePtr()->SetProbeP4( *p4HNL );
566
567 LOG( "gevgen_pghnl", pDEBUG ) << asts.str();
568
569 //delete rng;
570 return p4HNL;
571}
572//_________________________________________________________________________________________
573TLorentzVector * GenerateOriginPosition( GHepRecord * event )
574{
575 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
576 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
577
578 // get centre of box from config
579 std::vector< double > PGOrigin = hnlgen->GetPGunOrigin();
580 /*
581 double ox = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginX" );
582 double oy = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginY" );
583 double oz = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginZ" );
584 */
585 double ox = PGOrigin.at(0), oy = PGOrigin.at(1), oz = PGOrigin.at(2);
586
587 // allow uniform deviation
588 std::vector< double > PGDOrigin = hnlgen->GetPGunDOrigin();
589 /*
590 double Dxmax = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDX" );
591 double Dymax = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDY" );
592 double Dzmax = utils::hnl::GetCfgDouble( "HNL", "ParticleGun", "PG-OriginDZ" );
593 */
594 double Dxmax = PGDOrigin.at(0), Dymax = PGDOrigin.at(1), Dzmax = PGDOrigin.at(2);
595
597 double dx = rng->RndGen().Uniform( -Dxmax, Dxmax );
598 double dy = rng->RndGen().Uniform( -Dymax, Dymax );
599 double dz = rng->RndGen().Uniform( -Dzmax, Dzmax );
600
601 // make position
602 ox += dx; oy += dy; oz += dz;
603 TLorentzVector * x4HNL = new TLorentzVector();
604 x4HNL->SetXYZT( ox, oy, oz, 0.0 );
605
606 event->SetVertex( *x4HNL );
607 //delete rng;
608 return x4HNL;
609}
610//_________________________________________________________________________________________
611TLorentzVector GeneratePosition( GHepRecord * event )
612{
613 if( gOptUsingRootGeom ){
614
615 const Algorithm * algVtxGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::VertexGenerator", "Default");
616
617 const VertexGenerator * vtxGen = dynamic_cast< const VertexGenerator * >( algVtxGen );
618 vtxGen->ProcessEventRecord( event );
619
620 TLorentzVector x4 = *(event->Vertex());
621 return x4;
622 }
623 else{
624 __attribute__((unused)) RandomGen * rnd = RandomGen::Instance();
625 TRandom3 & rnd_geo = rnd->RndGeom();
626
627 double rndx = 2 * (rnd_geo.Rndm() - 0.5); // [-1,1]
628 double rndy = 2 * (rnd_geo.Rndm() - 0.5); // [-1,1]
629 double rndz = 2 * (rnd_geo.Rndm() - 0.5); // [-1,1]
630
631 double t_gen = 0;
632 double x_gen = fox + rndx * fdx;
633 double y_gen = foy + rndy * fdy;
634 double z_gen = foz + rndz * fdz;
635
636 TLorentzVector pos(x_gen, y_gen, z_gen, t_gen);
637 return pos;
638 }
639
640 return TLorentzVector( 0, 0, 0, 0);
641}
642//_________________________________________________________________________________________
644{
645 //string sname = "genie::EventGenerator";
646 //string sconfig = "BeamHNL";
648
649 LOG("gevgen_pghnl", pINFO)
650 << "Instantiating HNL generator.";
651
652 const Algorithm * algmcgen = algf->GetAlgorithm(kDefOptSName, kDefOptSConfig);
653 LOG("gevgen_pghnl", pDEBUG)
654 << "Got algorithm " << kDefOptSName.c_str() << "/" << kDefOptSConfig.c_str();;
655
656 const EventRecordVisitorI * mcgen =
657 dynamic_cast< const EventRecordVisitorI * >( algmcgen );
658 if(!mcgen) {
659 LOG("gevgen_pghnl", pFATAL) << "Couldn't instantiate the HNL generator";
660 gAbortingInErr = true;
661 exit(1);
662 }
663
664 LOG("gevgen_pghnl", pINFO)
665 << "HNL generator instantiated successfully.";
666
667 return mcgen;
668}
669//_________________________________________________________________________________________
670int SelectDecayMode( std::vector< HNLDecayMode_t > * intChannels, SimpleHNL sh )
671{
672 const std::map< HNLDecayMode_t, double > gammaMap = sh.GetValidChannels();
673
674 // set CoM lifetime now if unset
675 if( CoMLifetime < 0.0 ){
677 LOG( "gevgen_pghnl", pDEBUG )
678 << "Rest frame CoMLifetime = " << CoMLifetime << " [GeV^{-1}]";
679 }
680
681 for( std::vector< HNLDecayMode_t >::iterator it = intChannels->begin(); it != intChannels->end(); ++it ){
682 HNLDecayMode_t mode = *it;
683 auto mapG = gammaMap.find( mode );
684 double theGamma = mapG->second;
685 LOG("gevgen_pghnl", pDEBUG)
686 << "For mode " << utils::hnl::AsString( mode ) << " gamma = " << theGamma;
687 }
688
689 std::map< HNLDecayMode_t, double > intMap =
690 selector::SetInterestingChannels( (*intChannels), gammaMap );
691
692 sh.SetInterestingChannels( intMap );
693
694 // get probability that channels in intChannels will be selected
695 std::map< HNLDecayMode_t, double > PMap =
697
698 // now do a random throw
700 double ranThrow = rnd->RndGen().Uniform( 0., 1. ); // HNL's fate is sealed.
701
702 HNLDecayMode_t selectedDecayChan =
703 selector::SelectChannelInclusive( PMap, ranThrow );
704
705 int decay = ( int ) selectedDecayChan;
706 return decay;
707}
708//_________________________________________________________________________________________
709void GetCommandLineArgs(int argc, char ** argv)
710{
711 LOG("gevgen_pghnl", pINFO) << "Parsing command line arguments";
712
713 // Parse run options for this app
714
715 CmdLnArgParser parser(argc,argv);
716
717 // help?
718 bool help = parser.OptionExists('h');
719 if(help) {
720 PrintSyntax();
721 exit(0);
722 }
723
724 // force the app to look at HNL tune by default
725 // if user passes --tune argument, look at the user input tune instead
726 char * expargv[ argc + 2 ];
727 bool didFindUserInputTune = false;
728 std::string stExtraTuneBit = kDefOptSTune;
729
730 if( parser.OptionExists("tune") ){
731 didFindUserInputTune = true;
732 stExtraTuneBit = parser.ArgAsString("tune");
733 LOG( "gevgen_hnl", pWARN )
734 << "Using input HNL tune " << parser.ArgAsString("tune");
735 } else {
736 LOG( "gevgen_hnl", pWARN )
737 << "Using default HNL tune " << kDefOptSTune;
738 }
739 // append this to argv
740 for( int iArg = 0; iArg < argc; iArg++ ){
741 expargv[iArg] = argv[iArg];
742 }
743 if( !didFindUserInputTune ){
744 char * chBit = const_cast< char * >( stExtraTuneBit.c_str() ); // ugh. Ugly.
745 std::string stune("--tune"); char * tBit = const_cast< char * >( stune.c_str() );
746 expargv[argc] = tBit;
747 expargv[argc+1] = chBit;
748 }
749
750 // Common run options.
751 int expargc = ( didFindUserInputTune ) ? argc : argc+2;
752 std::string stnull(""); char * nBit = const_cast< char * >( stnull.c_str() );
753 expargv[expargc] = nBit;
754
755 RunOpt::Instance()->ReadFromCommandLine(expargc,expargv);
756
757 // run number
758 if( parser.OptionExists('r') ) {
759 LOG("gevgen_pghnl", pDEBUG) << "Reading MC run number";
760 gOptRunNu = parser.ArgAsLong('r');
761 } else {
762 LOG("gevgen_pghnl", pDEBUG) << "Unspecified run number - Using default";
763 gOptRunNu = 1000;
764 } //-r
765
766 // number of events
767 if( parser.OptionExists('n') ) {
768 LOG("gevgen_pghnl", pDEBUG)
769 << "Reading number of events to generate";
770 gOptNev = parser.ArgAsInt('n');
771 } else {
772 LOG("gevgen_pghnl", pFATAL)
773 << "You need to specify the number of events";
774 PrintSyntax();
775 exit(0);
776 } //-n
777
778 // get HNL mass
779 const Algorithm * algHNLGen = AlgFactory::Instance()->GetAlgorithm("genie::hnl::Decayer", "Default");
780 const Decayer * hnlgen = dynamic_cast< const Decayer * >( algHNLGen );
781 gOptMassHNL = hnlgen->GetHNLMass();
782
783 // HNL decay mode
784 int mode = -1;
785 if( parser.OptionExists('m') ) {
786 LOG("gevgen_pghnl", pDEBUG)
787 << "Reading HNL decay mode";
788 mode = parser.ArgAsInt('m');
789 } else {
790 LOG("gevgen_pghnl", pINFO)
791 << "No decay mode specified - will sample from allowed decay modes";
792 } //-m
794
796 if(!allowed) {
797 LOG("gevgen_pghnl", pFATAL)
798 << "Specified decay is not allowed kinematically for the given HNL mass";
799 PrintSyntax();
800 exit(0);
801 }
802
803 //
804 // geometry
805 //
806
807 string geom = "";
808 string lunits;
809#ifdef __CAN_USE_ROOT_GEOM__
810 // string dunits;
811 if( parser.OptionExists('g') ) {
812 LOG("gevgen_pghnl", pDEBUG) << "Getting input geometry";
813 geom = parser.ArgAsString('g');
814
815 // is it a ROOT file that contains a ROOT geometry?
816 bool accessible_geom_file =
817 ! (gSystem->AccessPathName(geom.c_str()));
818 if (accessible_geom_file) {
820 gOptUsingRootGeom = true;
821 } else {
822 LOG("gevgen_pghnl", pFATAL)
823 << "Geometry option is not a ROOT file. Please use ROOT geom.";
824 PrintSyntax();
825 exit(1);
826 }
827 } else {
828 // LOG("gevgen_pghnl", pFATAL)
829 // << "No geometry option specified - Exiting";
830 // PrintSyntax();
831 // exit(1);
832 } //-g
833
835 // using a ROOT geometry - get requested geometry units
836
837 // length units:
838 if( parser.OptionExists('L') ) {
839 LOG("gevgen_pghnl", pDEBUG)
840 << "Checking for input geometry length units";
841 lunits = parser.ArgAsString('L');
842 } else {
843 LOG("gevgen_pghnl", pDEBUG) << "Using default geometry length units";
845 } // -L
846 // // density units:
847 // if( parser.OptionExists('D') ) {
848 // LOG("gevgen_pghnl", pDEBUG)
849 // << "Checking for input geometry density units";
850 // dunits = parser.ArgAsString('D');
851 // } else {
852 // LOG("gevgen_pghnl", pDEBUG) << "Using default geometry density units";
853 // dunits = kDefOptGeomDUnits;
854 // } // -D
856 // gOptGeomDUnits = utils::units::UnitFromString(dunits);
857
858 } // using root geom?
859#endif // #ifdef __CAN_USE_ROOT_GEOM__
860
861 // event file prefix
862 if( parser.OptionExists('o') ) {
863 LOG("gevgen_pghnl", pDEBUG) << "Reading the event filename prefix";
864 gOptEvFilePrefix = parser.ArgAsString('o');
865 } else {
866 LOG("gevgen_pghnl", pDEBUG)
867 << "Will set the default event filename prefix";
869 } //-o
870
871 // random number seed
872 if( parser.OptionExists("seed") ) {
873 LOG("gevgen_pghnl", pINFO) << "Reading random number seed";
874 gOptRanSeed = parser.ArgAsLong("seed");
875 } else {
876 LOG("gevgen_pghnl", pINFO) << "Unspecified random number seed - Using default";
877 gOptRanSeed = -1;
878 }
879
880 //
881 // >>> print the command line options
882 //
883
884 ostringstream gminfo;
885 if (gOptUsingRootGeom) {
886 gminfo << "Using ROOT geometry - file: " << gOptRootGeom
887 << ", top volume: "
888 << ((gOptRootGeomTopVol.size()==0) ? "<master volume>" : gOptRootGeomTopVol)
889 << ", length units: " << lunits;
890 // << ", density units: " << dunits;
891 }
892
893 LOG("gevgen_pghnl", pNOTICE)
894 << "\n\n"
895 << utils::print::PrintFramedMesg("gevgen_pghnl job configuration");
896
897 LOG("gevgen_pghnl", pNOTICE)
898 << "\n @@ Run number : " << gOptRunNu
899 << "\n @@ Random seed : " << gOptRanSeed
900 << "\n @@ Decay channel : " << utils::hnl::AsString(gOptDecayMode)
901 << "\n @@ Geometry : " << gminfo.str()
902 << "\n @@ Statistics : " << gOptNev << " events";
903}
904//_________________________________________________________________________________________
905void PrintSyntax(void)
906{
907 LOG("gevgen_pghnl", pFATAL)
908 << "\n **Syntax**"
909 << "\n gevgen_pghnl [-h] "
910 << "\n [-r run#]"
911 << "\n -n n_of_events"
912 << "\n [-m decay_mode]"
913 << "\n [-g geometry (ROOT file)]"
914 << "\n [-L length_units_at_geom]"
915 << "\n [-o output_event_file_prefix]"
916 << "\n [--seed random_number_seed]"
917 << "\n [--message-thresholds xml_file]"
918 << "\n [--event-record-print-level level]"
919 << "\n [--mc-job-status-refresh-rate rate]"
920 << "\n"
921 << " Please also read the detailed documentation at http://www.genie-mc.org"
922 << " or look at the source code: $GENIE/src/Apps/gBeamHNLParticleGun.cxx"
923 << "\n";
924}
925//_________________________________________________________________________________________
#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.
GENIE's GHEP MC event record.
Definition GHepRecord.h:45
static void SetPrintLevel(int print_level)
virtual void SetProbability(double prob)
Definition GHepRecord.h:131
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
void Update(int iev, const EventRecord *event)
void SetRefreshRate(int rate)
void SetProbeP4(const TLorentzVector &P4)
Summary information for an interaction.
Definition Interaction.h:56
InitialState * InitStatePtr(void) const
Definition Interaction.h:74
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.
Definition NtpWriter.h:39
void Initialize(void)
add event
Definition NtpWriter.cxx:83
void Save(void)
get the even tree
void AddEventRecord(int ievent, const EventRecord *ev_rec)
save the event tree
Definition NtpWriter.cxx:57
void CustomizeFilenamePrefix(string prefix)
TTree * EventTree(void)
Definition NtpWriter.h:55
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition RandomGen.h:29
TRandom3 & RndGeom(void) const
rnd number generator used by geometry drivers
Definition RandomGen.h:68
static RandomGen * Instance()
Access instance.
Definition RandomGen.cxx:74
TRandom3 & RndGen(void) const
rnd number generator for generic usage
Definition RandomGen.h:80
void ReadFromCommandLine(int argc, char **argv)
Definition RunOpt.cxx:99
static RunOpt * Instance(void)
Definition RunOpt.cxx:54
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
double GetCoMLifetime()
Definition SimpleHNL.h:96
void SetInterestingChannels(const std::map< genie::hnl::HNLDecayMode_t, double > gammaMap)
Definition SimpleHNL.h:276
std::map< genie::hnl::HNLDecayMode_t, double > GetValidChannels()
Definition SimpleHNL.h:154
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 gOptECoupling
bool gOptIsMajorana
double NTP_FS1_E
double NTP_IS_E
double NTP_FS1_PX
double NTP_FS0_PZ
double foy
double gOptMassHNL
HNLDecayMode_t gOptDecayMode
double NTP_FS1_PY
double gOptMCoupling
double NTP_FS0_PY
double fdz
std::vector< HNLDecayMode_t > gOptIntChannels
double foz
double NTP_FS0_PX
double evWeight
double fox
double gOptEnergyHNL
double NTP_IS_PX
double NTP_FS0_E
double fdy
double NTP_FS2_PZ
double NTP_FS2_PY
int NTP_FS1_PDG
double fdx
int NTP_FS2_PDG
double NTP_FS2_PX
double NTP_IS_PY
string kDefOptSTune
double CoMLifetime
double NTP_FS2_E
int NTP_FS0_PDG
string kDefOptSName
double gOptTCoupling
double NTP_FS1_PZ
double NTP_IS_PZ
string kDefOptSConfig
TLorentzVector GeneratePosition(GHepRecord *event)
TLorentzVector * GenerateOriginPosition(GHepRecord *event)
const EventRecordVisitorI * HNLGenerator(void)
int SelectDecayMode(std::vector< HNLDecayMode_t > *intChannels, SimpleHNL sh)
double evProdVtx[3]
void GetCommandLineArgs(int argc, char **argv)
void PrintSyntax(void)
TLorentzVector * GenerateOriginMomentum(GHepRecord *event)
int gOptHNLKind
string lunits
string geom
Typedef enums.
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)
Definition AppInit.cxx:30
void MesgThresholds(string inpfile)
Definition AppInit.cxx:99
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)
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 kPdgKP
Definition PDGCodes.h:172
@ kNFGHEP
Definition NtpMCFormat.h:30
const int kPdgHNL
Definition PDGCodes.h:224
enum genie::ENtpMCFormat NtpMCFormat_t