All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultiPartVertex_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: MultiPartVertex
3 // Module Type: producer
4 // File: MultiPartVertex_module.cc
5 //
6 // Generated at Tue Dec 13 15:48:59 2016 by Kazuhiro Terao using artmod
7 // from cetpkgsupport v1_11_00.
8 ////////////////////////////////////////////////////////////////////////
9 
10 #include "art/Framework/Core/EDProducer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/SubRun.h"
16 //#include "art/Utilities/InputTag.h"
17 #include "fhiclcpp/ParameterSet.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
19 
20 #include <memory>
21 #include <vector>
22 #include "cetlib/pow.h"
23 
24 #include "CLHEP/Random/RandFlat.h"
25 #include "CLHEP/Random/RandGauss.h"
26 #include "TRandom.h"
27 #include "nurandom/RandomUtils/NuRandomService.h"
32 
33 #include "nusimdata/SimulationBase/MCTruth.h"
34 #include "nusimdata/SimulationBase/MCParticle.h"
35 
36 #include "TLorentzVector.h"
37 #include "TDatabasePDG.h"
38 
39 struct PartGenParam {
40  std::vector<int > pdg;
41  std::vector<double > mass;
42  std::array <size_t, 2 > multi;
43  std::array <double, 2 > kerange;
44  bool use_mom;
45  double weight;
46 };
47 
48 class MultiPartVertex;
49 
50 class MultiPartVertex : public art::EDProducer {
51 public:
52  explicit MultiPartVertex(fhicl::ParameterSet const & p);
53  // The destructor generated by the compiler is fine for classes
54  // without bare pointers or other resource use.
56 
57  // Plugins should not be copied or assigned.
58  MultiPartVertex(MultiPartVertex const &) = delete;
59  MultiPartVertex(MultiPartVertex &&) = delete;
60  MultiPartVertex & operator = (MultiPartVertex const &) = delete;
62 
63  // Required functions.
64  void produce(art::Event & e) override;
65 
66  void beginRun(art::Run& run) override;
67 
68  void GenPosition(double& x, double& y, double& z);
69 
70  std::array<double, 3U> extractDirection() const;
71  void GenMomentum(const PartGenParam& param, const double& mass, double& px, double& py, double& pz);
72 
73  std::vector<size_t> GenParticles() const;
74 
75 private:
76 
77  CLHEP::HepRandomEngine& fFlatEngine;
78  std::unique_ptr<CLHEP::RandFlat> fFlatRandom;
79  std::unique_ptr<CLHEP::RandGauss> fNormalRandom;
80 
81  // exception thrower
82  void abort(const std::string msg) const;
83 
84  // array of particle info for generation
85  std::vector<PartGenParam> _param_v;
86 
87  // g4 time of generation
88  double _t0;
89  double _t0_sigma;
90 
91  // g4 position
92  std::array<double,2> _xrange;
93  std::array<double,2> _yrange;
94  std::array<double,2> _zrange;
95 
96  // TPC range
97  std::vector<std::vector<unsigned short> > _tpc_v;
98 
99  // multiplicity constraint
100  size_t _multi_min;
101  size_t _multi_max;
102 
103  // verbosity flag
104  unsigned short _debug;
105 };
106 
107 void MultiPartVertex::abort(const std::string msg) const
108 {
109  std::cerr << "\033[93m" << msg.c_str() << "\033[00m" << std::endl;
110  throw std::exception();
111 }
112 
114 { }
115 
116 MultiPartVertex::MultiPartVertex(fhicl::ParameterSet const & p)
117 : EDProducer(p)
118 , fFlatEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*this, "HepJamesRandom", "GenVertex"))
119  //, fFlatEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*this, "HepJamesRandom", "Gen", p, "Seed"))
120 // Initialize member data here.
121 {
122 
123  //
124  // Random engine initialization
125  //
126  fFlatRandom = std::make_unique<CLHEP::RandFlat>(fFlatEngine,0,1);
127  fNormalRandom = std::make_unique<CLHEP::RandGauss>(fFlatEngine);
128 
129  produces< std::vector<simb::MCTruth> >();
130  produces< sumdata::RunData, art::InRun >();
131 
132  _debug = p.get<unsigned short>("DebugMode",0);
133 
134  _t0 = p.get<double>("G4Time");
135  _t0_sigma = p.get<double>("G4TimeJitter");
136  if(_t0_sigma < 0) this->abort("Cannot have a negative value for G4 time jitter");
137 
138  _multi_min = p.get<size_t>("MultiMin");
139  _multi_max = p.get<size_t>("MultiMax");
140 
141  _tpc_v = p.get<std::vector<std::vector<unsigned short> > >("TPCRange");
142  auto const xrange = p.get<std::vector<double> > ("XRange");
143  auto const yrange = p.get<std::vector<double> > ("YRange");
144  auto const zrange = p.get<std::vector<double> > ("ZRange");
145 
146  auto const part_cfg = p.get<fhicl::ParameterSet>("ParticleParameter");
147 
148  _param_v.clear();
149  auto const pdg_v = part_cfg.get<std::vector<std::vector<int> > > ("PDGCode");
150  auto const minmult_v = part_cfg.get<std::vector<unsigned short> > ("MinMulti");
151  auto const maxmult_v = part_cfg.get<std::vector<unsigned short> > ("MaxMulti");
152  auto const weight_v = part_cfg.get<std::vector<double> > ("ProbWeight");
153 
154  auto kerange_v = part_cfg.get<std::vector<std::vector<double> > > ("KERange");
155  auto momrange_v = part_cfg.get<std::vector<std::vector<double> > > ("MomRange");
156 
157  if( (kerange_v.empty() && momrange_v.empty()) ||
158  (!kerange_v.empty() && !momrange_v.empty()) ) {
159  this->abort("Only one of KERange or MomRange must be empty!");
160  }
161 
162  bool use_mom = false;
163  if(kerange_v.empty()){
164  kerange_v = momrange_v;
165  use_mom = true;
166  }
167  // sanity check
168  if( pdg_v.size() != kerange_v.size() ||
169  pdg_v.size() != minmult_v.size() ||
170  pdg_v.size() != maxmult_v.size() ||
171  pdg_v.size() != weight_v.size() )
172  this->abort("configuration parameters have incompatible lengths!");
173 
174  // further sanity check (1 more depth for some double-array)
175  for(auto const& r : pdg_v ) { if( r.empty() ) this->abort("PDG code not given!"); }
176  for(auto const& r : kerange_v) { if( r.size()!=2) this->abort("Incompatible legnth @ KE vector!"); }
177 
178  size_t multi_min = 0;
179  for(size_t idx=0; idx<minmult_v.size(); ++idx) {
180  if(minmult_v[idx] > maxmult_v[idx]) this->abort("Particle MinMulti > Particle MaxMulti!");
181  if(minmult_v[idx] > _multi_max) this->abort("Particle MinMulti > overall MultiMax!");
182  multi_min += minmult_v[idx];
183  }
184  _multi_min = std::max(_multi_min, multi_min);
185  if(_multi_max < _multi_min) this->abort("Overall MultiMax <= overall MultiMin!");
186 
187  /*
188  if(!xrange.empty() && xrange.size() >2) this->abort("Incompatible legnth @ X vector!" );
189  if(!yrange.empty() && yrange.size() >2) this->abort("Incompatible legnth @ Y vector!" );
190  if(!zrange.empty() && zrange.size() >2) this->abort("Incompatible legnth @ Z vector!" );
191 
192  // range register
193  if(xrange.size()==1) { _xrange[0] = _xrange[1] = xrange[0]; }
194  if(xrange.size()==2) { _xrange[0] = xrange[0]; _xrange[1] = xrange[1]; }
195  if(yrange.size()==1) { _yrange[0] = _yrange[1] = yrange[0]; }
196  if(yrange.size()==2) { _yrange[0] = yrange[0]; _yrange[1] = yrange[1]; }
197  if(zrange.size()==1) { _zrange[0] = _zrange[1] = zrange[0]; }
198  if(zrange.size()==2) { _zrange[0] = zrange[0]; _zrange[1] = zrange[1]; }
199  */
200 
201  if(!xrange.empty() && xrange.size() >2) this->abort("Incompatible legnth @ X vector!" );
202  if(!yrange.empty() && yrange.size() >2) this->abort("Incompatible legnth @ Y vector!" );
203  if(!zrange.empty() && zrange.size() >2) this->abort("Incompatible legnth @ Z vector!" );
204 
205  // slight modification from mpv: define the overall volume across specified TPC IDs + range options
206  double xmin,xmax,ymin,ymax,zmin,zmax;
207  xmin = ymin = zmin = 1.e20;
208  xmax = ymax = zmax = -1.e20;
209  // Implementation of required member function here.
210  auto geop = lar::providerFrom<geo::Geometry>();
211  for(auto const& tpc_id : _tpc_v) {
212  assert(tpc_id.size() == 2);
213  size_t cid = tpc_id[0];
214  size_t tid = tpc_id[1];
215  auto const& cryostat = geop->Cryostat(cid);
216  assert(cryostat.HasTPC(tid));
217 
218  auto const& tpc = cryostat.TPC(tid);
219  auto const& tpcabox = tpc.ActiveBoundingBox();
220  xmin = std::min(tpcabox.MinX(), xmin);
221  ymin = std::min(tpcabox.MinY(), ymin);
222  zmin = std::min(tpcabox.MinZ(), zmin);
223  xmax = std::max(tpcabox.MaxX(), xmax);
224  ymax = std::max(tpcabox.MaxY(), ymax);
225  zmax = std::max(tpcabox.MaxZ(), zmax);
226 
227  if(_debug) {
228  std::cout << "Using Cryostat " << tpc_id[0] << " TPC " << tpc_id[1]
229  << " ... X " << xmin << " => " << xmax
230  << " ... Y " << ymin << " => " << ymax
231  << " ... Z " << zmin << " => " << zmax
232  << std::endl;
233  }
234  }
235 
236  // range register
237  if(xrange.size()==1) { _xrange[0] = _xrange[1] = xrange[0]; }
238  if(yrange.size()==1) { _yrange[0] = _yrange[1] = yrange[0]; }
239  if(zrange.size()==1) { _zrange[0] = _zrange[1] = zrange[0]; }
240  if(xrange.size()==2) { _xrange[0] = xrange[0]; _xrange[1] = xrange[1]; }
241  if(yrange.size()==2) { _yrange[0] = yrange[0]; _yrange[1] = yrange[1]; }
242  if(zrange.size()==2) { _zrange[0] = zrange[0]; _zrange[1] = zrange[1]; }
243 
244  _xrange[0] = xmin + _xrange[0];
245  _xrange[1] = xmax - _xrange[1];
246  _yrange[0] = ymin + _yrange[0];
247  _yrange[1] = ymax - _yrange[1];
248  _zrange[0] = zmin + _zrange[0];
249  _zrange[1] = zmax - _zrange[1];
250 
251  // check
252  assert(_xrange[0] <= _xrange[1]);
253  assert(_yrange[0] <= _yrange[1]);
254  assert(_zrange[0] <= _zrange[1]);
255 
256  if(_debug>0) {
257  std::cout<<"Particle generation world boundaries..."<<std::endl
258  <<"X " << _xrange[0] << " => " << _xrange[1] << std::endl
259  <<"Y " << _yrange[0] << " => " << _yrange[1] << std::endl
260  <<"Z " << _zrange[0] << " => " << _zrange[1] << std::endl;
261  }
262 
263 
264  // register
265  //auto db = new TDatabasePDG;
266  auto db = TDatabasePDG::Instance();
267  for(size_t idx=0; idx<pdg_v.size(); ++idx) {
268  auto const& pdg = pdg_v[idx];
269  auto const& kerange = kerange_v[idx];
270  PartGenParam param;
271  param.use_mom = use_mom;
272  param.pdg = pdg;
273  param.kerange[0] = kerange[0];
274  param.kerange[1] = kerange[1];
275  param.mass.resize(pdg.size());
276  param.multi[0] = minmult_v[idx];
277  param.multi[1] = maxmult_v[idx];
278  param.weight = weight_v[idx];
279  for(size_t i=0; i<pdg.size(); ++i)
280  param.mass[i] = db->GetParticle(param.pdg[i])->Mass();
281 
282  // sanity check
283  if(kerange[0]<0 || kerange[1]<0)
284  this->abort("You provided negative energy? Fuck off Mr. Trump.");
285 
286  // overall range check
287  if(param.kerange[0] > param.kerange[1]) this->abort("KE range has no phase space...");
288 
289  if(_debug>0) {
290  std::cout << "Generating particle (PDG";
291  for(auto const& pdg : param.pdg) std::cout << " " << pdg;
292  std::cout << ")" << std::endl
293  << (param.use_mom ? " KE range ....... " : " Mom range ....... ")
294  << param.kerange[0] << " => " << param.kerange[1] << " MeV" << std::endl
295  << std::endl;
296  }
297 
298  _param_v.push_back(param);
299  }
300 }
301 
302 void MultiPartVertex::beginRun(art::Run& run)
303 {
304  // grab the geometry object to see what geometry we are using
305  art::ServiceHandle<geo::Geometry> geo;
306 
307  std::unique_ptr<sumdata::RunData> runData(new sumdata::RunData(geo->DetectorName()));
308 
309  run.put(std::move(runData));
310 
311  return;
312 }
313 
314 std::vector<size_t> MultiPartVertex::GenParticles() const {
315 
316  std::vector<size_t> result;
317  std::vector<size_t> gen_count_v(_param_v.size(),0);
318 
319  int num_part = (int)(fFlatRandom->fire(_multi_min,_multi_max+1-1.e-10));
320 
321  // generate min multiplicity first
322  std::vector<double> weight_v(_param_v.size(),0);
323  for(size_t idx=0; idx<_param_v.size(); ++idx) {
324  weight_v[idx] = _param_v[idx].weight;
325  for(size_t ctr=0; ctr<_param_v[idx].multi[0]; ++ctr) {
326  result.push_back(idx);
327  gen_count_v[idx] += 1;
328  num_part -= 1;
329  }
330  if(gen_count_v[idx] >= _param_v[idx].multi[1])
331  weight_v[idx] = 0.;
332  }
333 
334  assert(num_part >= 0);
335 
336  while(num_part) {
337 
338  double total_weight = 0;
339  for(auto const& v : weight_v) total_weight += v;
340 
341  double rval = 0;
342  rval = fFlatRandom->fire(0,total_weight);
343 
344  size_t idx = 0;
345  for(idx = 0; idx < weight_v.size(); ++idx) {
346  rval -= weight_v[idx];
347  if(rval <=0.) break;
348  }
349 
350  // register to the output
351  result.push_back(idx);
352 
353  // if generation count exceeds max, set probability weight to be 0
354  gen_count_v[idx] += 1;
355  if(gen_count_v[idx] >= _param_v[idx].multi[1])
356  weight_v[idx] = 0.;
357 
358  --num_part;
359  }
360  return result;
361 }
362 
363 
364 void MultiPartVertex::GenPosition(double& x, double& y, double& z) {
365 
366  x = fFlatRandom->fire(_xrange[0],_xrange[1]);
367  y = fFlatRandom->fire(_yrange[0],_yrange[1]);
368  z = fFlatRandom->fire(_zrange[0],_zrange[1]);
369 
370  if(_debug>0) {
371  std::cout << "Generating a rain particle at ("
372  << x << "," << y << "," << z << ")" << std::endl;
373  }
374 }
375 /*
376 void MultiPartVertex::GenPosition(double& x, double& y, double& z) {
377 
378  auto const& tpc_id = _tpc_v.at((size_t)(fFlatRandom->fire(0,_tpc_v.size())));
379  // Implementation of required member function here.
380  auto geop = lar::providerFrom<geo::Geometry>();
381  size_t cid = tpc_id[0];
382  size_t tid = tpc_id[1];
383  auto const& cryostat = geop->Cryostat(cid);
384  if(!cryostat.HasTPC(tid)) {
385  std::cerr<< "\033[93mTPC " << tid << " not found... in cryostat " << cid << "\033[00m" << std::endl;
386  throw std::exception();
387  }
388 
389  auto const& tpc = cryostat.TPC(tid);
390  auto const& tpcabox = tpc.ActiveBoundingBox();
391  double xmin = tpcabox.MinX() + _xrange[0];
392  double xmax = tpcabox.MaxX() - _xrange[1];
393  double ymin = tpcabox.MinY() + _yrange[0];
394  double ymax = tpcabox.MaxY() - _yrange[1];
395  double zmin = tpcabox.MinZ() + _zrange[0];
396  double zmax = tpcabox.MaxZ() - _zrange[1];
397  x = fFlatRandom->fire(xmin,xmax);
398  y = fFlatRandom->fire(ymin,ymax);
399  z = fFlatRandom->fire(zmin,zmax);
400 
401 }
402 */
403 
404 std::array<double, 3U> MultiPartVertex::extractDirection() const {
405  double px, py, pz;
406  px = fNormalRandom->fire(0, 1);
407  py = fNormalRandom->fire(0, 1);
408  pz = fNormalRandom->fire(0, 1);
409  double p = std::hypot(px, py, pz);
410  px = px / p;
411  py = py / p;
412  pz = pz / p;
413  std::array<double, 3U> result = { px, py, pz };
414  return result;
415 }
416 
417 void MultiPartVertex::GenMomentum(const PartGenParam& param, const double& mass, double& px, double& py, double& pz) {
418 
419  double tot_energy = 0;
420  if(param.use_mom)
421  tot_energy = sqrt(cet::square(fFlatRandom->fire(param.kerange[0],param.kerange[1])) + cet::square(mass));
422  else
423  tot_energy = fFlatRandom->fire(param.kerange[0],param.kerange[1]) + mass;
424 
425  double mom_mag = sqrt(cet::square(tot_energy) - cet::square(mass));
426 
427  /* Generating unit vector with uniform distribution
428  * in direction = over the sphere.
429  *
430  * It is sufficient to draw a normal variable in
431  * each direction and normalize.
432  *
433  * https://mathworld.wolfram.com/SpherePointPicking.html
434  */
435 
436  std::array<double, 3U> p = extractDirection();
437  px = p[0]; py = p[1]; pz = p[2];
438 
439  if(_debug>1)
440  std::cout << " Direction : (" << px << "," << py << "," << pz << ")" << std::endl
441  << " Momentum : " << mom_mag << " [MeV/c]" << std::endl
442  << " Energy : " << tot_energy << " [MeV/c^2]" << std::endl;
443  px *= mom_mag;
444  py *= mom_mag;
445  pz *= mom_mag;
446 
447 }
448 
449 void MultiPartVertex::produce(art::Event & e)
450 {
451  if(_debug>0) std::cout << "Processing a new event..." << std::endl;
452 
453  std::unique_ptr< std::vector<simb::MCTruth> > mctArray(new std::vector<simb::MCTruth>);
454 
455  double g4_time = fFlatRandom->fire(_t0 - _t0_sigma/2., _t0 + _t0_sigma/2.);
456 
457  double x, y, z;
458  GenPosition(x,y,z);
459  TLorentzVector pos(x,y,z,g4_time);
460 
461  simb::MCTruth mct;
462 
463  mct.SetOrigin(simb::kBeamNeutrino);
464 
465  std::vector<simb::MCParticle> part_v;
466 
467  auto const param_idx_v = GenParticles();
468  if(_debug)
469  std::cout << "Event Vertex @ (" << x << "," << y << "," << z << ") ... " << param_idx_v.size() << " particles..." << std::endl;
470 
471  for(size_t idx=0; idx<param_idx_v.size(); ++idx) {
472  auto const& param = _param_v[param_idx_v[idx]];
473  double px,py,pz;
474  // decide which particle
475  size_t pdg_index = (size_t)(fFlatRandom->fire(0,param.pdg.size()-1.e-10));
476  auto const& pdg = param.pdg[pdg_index];
477  auto const& mass = param.mass[pdg_index];
478  if(_debug) std::cout << " " << idx << "th instance PDG " << pdg << std::endl;
479  GenMomentum(param,mass,px,py,pz);
480  TLorentzVector mom(px,py,pz,sqrt(cet::square(px)+cet::square(py)+cet::square(pz)+cet::square(mass)));
481  //simb::MCParticle part(mct.NParticles(), pdg, "primary", 0, mass, 1);
482  simb::MCParticle part(part_v.size(), pdg, "primary", 0, mass, 1);
483  part.AddTrajectoryPoint(pos,mom);
484  part_v.emplace_back(std::move(part));
485  }
486 
487  if(_debug) std::cout << "Total number particles: " << mct.NParticles() << std::endl;
488 
489  simb::MCParticle nu(mct.NParticles(), 16, "primary", mct.NParticles(), 0, 0);
490  double px=0;
491  double py=0;
492  double pz=0;
493  double en=0;
494  for(auto const& part : part_v) {
495  px += part.Momentum().Px();
496  py += part.Momentum().Py();
497  pz += part.Momentum().Pz();
498  en += part.Momentum().E();
499  }
500  TLorentzVector mom(px,py,pz,en);
501  nu.AddTrajectoryPoint(pos,mom);
502 
503  mct.Add(nu);
504  for(auto& part : part_v)
505  mct.Add(part);
506 
507  // Set the neutrino for the MCTruth object:
508  // NOTE: currently these parameters are all pretty much a guess...
509  mct.SetNeutrino(simb::kCC,
510  simb::kQE, // not sure what the mode should be here, assumed that these are all QE???
511  simb::kCCQE, // not sure what the int_type should be either...
512  0, // target is AR40? not sure how to specify that...
513  0, // nucleon pdg ???
514  0, // quark pdg ???
515  -1.0, // W ??? - not sure how to calculate this from the above
516  -1.0, // X ??? - not sure how to calculate this from the above
517  -1.0, // Y ??? - not sure how to calculate this from the above
518  -1.0); // Qsqr ??? - not sure how to calculate this from the above
519 
520  mctArray->push_back(mct);
521 
522  e.put(std::move(mctArray));
523 }
524 
525 DEFINE_ART_MODULE(MultiPartVertex)
process_name opflash particleana ie ie ie z
std::vector< std::vector< unsigned short > > _tpc_v
MultiPartVertex(fhicl::ParameterSet const &p)
MultiPartVertex & operator=(MultiPartVertex const &)=delete
Utilities related to art service access.
var pdg
Definition: selectors.fcl:14
CLHEP::HepRandomEngine & fFlatEngine
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
BEGIN_PROLOG pz
Definition: filemuons.fcl:10
std::vector< int > pdg
pdgs p
Definition: selectors.fcl:22
std::unique_ptr< CLHEP::RandFlat > fFlatRandom
std::array< double, 2 > _xrange
std::vector< size_t > GenParticles() const
std::vector< PartGenParam > _param_v
std::array< double, 3U > extractDirection() const
void GenMomentum(const PartGenParam &param, const double &mass, double &px, double &py, double &pz)
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
Charged-current interactions.
Definition: IPrediction.h:38
process_name opflash particleana ie ie y
void GenPosition(double &x, double &y, double &z)
void beginRun(art::Run &run) override
createEngine this
void produce(art::Event &e) override
BEGIN_PROLOG px
Definition: filemuons.fcl:10
process_name physics producers generator physics producers generator physics producers generator py
float mass
Definition: dedx.py:47
std::array< double, 2 > _zrange
std::vector< double > mass
do i e
charged current quasi-elastic
Definition: SREnums.h:86
std::array< double, 2 > kerange
void abort(const std::string msg) const
Collection of Physical constants used in LArSoft.
height to which particles are projected pnfs larsoft persistent physics cosmics Fermilab CORSIKA standard He_showers_ * db
BEGIN_PROLOG SN nu
esac echo uname r
std::unique_ptr< CLHEP::RandGauss > fNormalRandom
std::array< size_t, 2 > multi
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::array< double, 2 > _yrange