LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
BaseRadioGen.h
Go to the documentation of this file.
1 #pragma once
6 
7 #include "cetlib/container_algorithms.h"
8 
9 // Framework includes
16 #include "art_root_io/TFileService.h"
17 #include "cetlib/exempt_ptr.h"
18 #include "cetlib/search_path.h"
19 #include "cetlib_except/exception.h"
20 #include "fhiclcpp/ParameterSet.h"
22 
23 // lar includes
27 
28 // nurandom includes
30 
31 // nusimdata, nugen includes
35 
36 // root includes
37 #include "TCanvas.h"
38 #include "TF1.h"
39 #include "TFile.h"
40 #include "TGenPhaseSpace.h"
41 #include "TGeoManager.h"
42 #include "TGeoMaterial.h"
43 #include "TGeoNode.h"
44 #include "TGraph.h"
45 #include "TH1D.h"
46 #include "TH2D.h"
47 #include "TLorentzVector.h"
48 #include "TMath.h"
49 #include "TRandom.h"
50 #include "TVector3.h"
51 
52 #include "CLHEP/Random/RandFlat.h"
53 #include "CLHEP/Random/RandPoisson.h"
54 
55 // C++ includes.
56 #include <cmath>
57 #include <iterator>
58 #include <map>
59 #include <memory>
60 #include <regex>
61 #include <set>
62 #include <string>
63 #include <sys/stat.h>
64 #include <vector>
65 
66 namespace evgen {
67  class clhep_random;
68 }
69 
70 namespace evgen {
71  class BaseRadioGen : public art::EDProducer {
72  public:
73  explicit BaseRadioGen(fhicl::ParameterSet const& pset);
74  void produce(art::Event& evt);
75  void beginRun(art::Run& run);
76  void beginJob();
77  void endJob();
78 
79  virtual void produce_radio(art::Event& evt) = 0;
80  virtual void beginRun_radio(art::Run&) {}
81  virtual void beginJob_radio() {}
82  virtual void endJob_radio() {}
83 
84  protected:
85  int GetNDecays();
86  bool GetGoodPositionTime(TLorentzVector& position);
87  TLorentzVector dirCalc(double p, double m);
88 
90  std::vector<std::string> m_isotope;
91 
92  CLHEP::HepRandomEngine& GetRandomEngine() { return m_engine; }
93  int GetNEvents() { return m_nevent; }
94  void GetTs(double& T0, double& T1)
95  {
96  T0 = m_T0;
97  T1 = m_T1;
98  }
99  void GetXs(double& X0, double& X1)
100  {
101  X0 = m_X0;
102  X1 = m_X1;
103  }
104  void GetYs(double& Y0, double& Y1)
105  {
106  Y0 = m_Y0;
107  Y1 = m_Y1;
108  }
109  void GetZs(double& Z0, double& Z1)
110  {
111  Z0 = m_Z0;
112  Z1 = m_Z1;
113  }
114 
115  private:
118  void SimplePDG(int pdg, int& simple, std::string& name);
119  void DeclareOutputHistos();
120  std::set<const TGeoNode*> m_all_nodes;
121  void FillAllNodes(const TGeoNode* curnode);
122  void GetNodeXYZMinMax(const TGeoNode* from,
123  const TGeoNode* to,
124  double& x_min,
125  double& x_max,
126  double& y_min,
127  double& y_max,
128  double& z_min,
129  double& z_max);
130  bool IsDaughterNode(const TGeoNode* daughter_node, const TGeoNode* mother_node);
131  bool findNode(const TGeoNode* curnode, std::string& tgtnname, const TGeoNode*& targetnode);
132  bool findMotherNode(const TGeoNode* cur_node,
133  std::string& daughter_name,
134  const TGeoNode*& mother_node);
135  bool NodeSupported(TGeoNode const* node) const;
136 
137  std::string m_material;
138  std::string m_volume_rand;
139  std::string m_volume_gen;
140  std::regex m_regex_material;
141  std::regex m_regex_volume;
142 
143  static constexpr double signaling_NaN = std::numeric_limits<double>::signaling_NaN();
144  double m_Bq{signaling_NaN};
145  double m_rate{
146  signaling_NaN};
147  double m_T0{signaling_NaN};
148  double m_T1{signaling_NaN};
149  double m_X0{signaling_NaN};
150  double m_Y0{signaling_NaN};
151  double m_Z0{signaling_NaN};
152  double m_X1{signaling_NaN};
153  double m_Y1{signaling_NaN};
154  double m_Z1{signaling_NaN};
155  double m_volume_cc{signaling_NaN};
156 
158  TGeoManager* m_geo_manager;
159 
160  CLHEP::HepRandomEngine& m_engine;
161  CLHEP::RandFlat m_random_flat;
162  CLHEP::RandPoisson m_random_poisson;
163 
164  bool m_geo_volume_mode{false};
167 
171 
172  std::map<const TGeoNode*, double> m_good_nodes{};
173  std::vector<const TGeoVolume*> m_good_volumes{};
174  std::vector<const TGeoMaterial*> m_good_materials{};
175 
176  TF1* m_distrib_xpos{nullptr};
177  TF1* m_distrib_ypos{nullptr};
178  TF1* m_distrib_zpos{nullptr};
179 
180  int m_nevent{0};
181  std::map<int, TH2D*> m_pos_xy_TH2D{};
182  std::map<int, TH2D*> m_pos_xz_TH2D{};
183  std::map<int, TH1D*> m_dir_x_TH1D{};
184  std::map<int, TH1D*> m_dir_y_TH1D{};
185  std::map<int, TH1D*> m_dir_z_TH1D{};
186  std::map<int, TH1D*> m_mom_TH1D{};
187  std::map<int, TH1D*> m_ke_TH1D{};
188  std::map<int, TH1D*> m_time_TH1D{};
189  TH1D* m_pdg_TH1D{nullptr};
190  };
191 
192  inline bool BaseRadioGen::NodeSupported(const TGeoNode* node) const
193  {
194  assert(node != nullptr);
195  return cet::search_all(m_good_volumes, node->GetVolume()) and
196  cet::search_all(m_good_materials, node->GetMedium()->GetMaterial());
197  }
198 
199  inline void BaseRadioGen::GetNodeXYZMinMax(const TGeoNode* from,
200  const TGeoNode* to,
201  double& x_min,
202  double& x_max,
203  double& y_min,
204  double& y_max,
205  double& z_min,
206  double& z_max)
207  {
208  std::vector<const TGeoNode*> mother_nodes;
209  const TGeoNode* current_node = from;
210  std::string daughter_name = from->GetName();
211  int nmax = 20;
212  int iter = 0;
213  while (current_node != to and iter++ < nmax) {
214  const TGeoNode* mother_node = nullptr;
215  daughter_name = current_node->GetName();
216  bool found_mum = findMotherNode(to, daughter_name, mother_node);
217  if (not found_mum) {
218  throw cet::exception("BaseRadioGen")
219  << "Didn't find the mum of the following node: " << daughter_name;
220  }
221  mother_nodes.push_back(mother_node);
222  current_node = mother_node;
223  }
224 
225  TGeoVolume* vol = from->GetVolume();
226  TGeoShape* shape = vol->GetShape();
227  TGeoBBox* bbox = (TGeoBBox*)shape;
228 
229  double dx = bbox->GetDX();
230  double dy = bbox->GetDY();
231  double dz = bbox->GetDZ();
232 
233  double halfs[3] = {dx, dy, dz};
234  double posmin[3] = {1.0e30, 1.0e30, 1.0e30};
235  double posmax[3] = {-1.0e30, -1.0e30, -1.0e30};
236 
237  const double* origin = bbox->GetOrigin();
238  for (int ix = -1; ix <= 1; ix += 2) {
239  for (int iy = -1; iy <= 1; iy += 2) {
240  for (int iz = -1; iz <= 1; iz += 2) {
241  double local[3];
242  local[0] = origin[0] + (double)ix * halfs[0];
243  local[1] = origin[1] + (double)iy * halfs[1];
244  local[2] = origin[2] + (double)iz * halfs[2];
245  double master[3];
246  from->LocalToMaster(local, master);
247  for (auto const& mum : mother_nodes) {
248  local[0] = master[0];
249  local[1] = master[1];
250  local[2] = master[2];
251  mum->LocalToMaster(local, master);
252  }
253  for (int j = 0; j < 3; ++j) {
254  posmin[j] = TMath::Min(posmin[j], master[j]);
255  posmax[j] = TMath::Max(posmax[j], master[j]);
256  }
257  }
258  }
259  }
260 
261  x_min = posmin[0];
262  y_min = posmin[1];
263  z_min = posmin[2];
264  x_max = posmax[0];
265  y_max = posmax[1];
266  z_max = posmax[2];
267  }
268 
270  : EDProducer{pset}
271  , m_material{pset.get<std::string>("material", ".*")}
272  , m_volume_rand{""}
273  , m_volume_gen{pset.get<std::string>("volume_gen", ".*")}
274  , m_regex_material{(std::regex)m_material}
275  , m_regex_volume{(std::regex)m_volume_gen}
277  , m_engine(art::ServiceHandle<rndm::NuRandomService>()->registerAndSeedEngine(
278  createEngine(0, "HepJamesRandom", "BaseRadioGen"),
279  "HepJamesRandom",
280  "BaseRadioGen",
281  pset,
282  "SeedBaseRadioGen"))
285  , m_rate_mode{pset.has_key("rate")}
286  , m_volume_rand_present{pset.has_key("volume_rand")}
287  , m_max_tries_event{pset.get<size_t>("max_tries_event", 1'000'000)}
288  , m_max_tries_rate_calculation{pset.get<size_t>("max_tries_rate_calculation", 40'000'000)}
290  pset.get<size_t>("target_n_point_rate_calculation", 100'000)}
291  {
292  produces<std::vector<simb::MCTruth>>();
293  produces<sumdata::RunData, art::InRun>();
294 
295  m_rate_mode = pset.get_if_present<double>("rate", m_rate);
296  if (not m_rate_mode) m_Bq = pset.get<double>("BqPercc");
297 
298  bool timed_mode = pset.get_if_present<double>("T0", m_T0);
299  if (timed_mode) { m_T1 = pset.get<double>("T1"); }
300  else {
301  auto const clockData =
302  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
303  auto const detProp =
304  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
305  int nsample = detProp.NumberTimeSamples();
306  m_T0 = -nsample * sampling_rate(clockData);
307  m_T1 = -m_T0;
308  }
309 
310  if (m_material != ".*" || m_volume_gen != ".*") {
311  MF_LOG_INFO("BaseRadioGen") << "Calculating the volume of " << m_material
312  << " and the volume " << m_volume_gen << " in the geometry.\n";
313 
314  TObjArray* volumes = m_geo_manager->GetListOfVolumes();
315  TList* materials = m_geo_manager->GetListOfMaterials();
316 
317  for (int i = 0; i < volumes->GetEntries(); ++i) {
318  TGeoVolume* volume = (TGeoVolume*)volumes->At(i);
319  std::string volume_name = volume->GetName();
320  bool good = std::regex_match(volume_name, m_regex_volume);
321  if (good) {
322 
323  if (m_volume_gen != ".*") {
324  MF_LOG_INFO("BaseRadioGen")
325  << " Volume " << volume_name << " is an accepted volume of "
326  << volume->GetShape()->Capacity() << "cm^3.\n";
327  if (volume->GetShape()->TestShapeBits(TGeoShape::kGeoBox)) {
328  TGeoBBox* box = dynamic_cast<TGeoBBox*>(volume->GetShape());
329  if (box)
330  MF_LOG_INFO("BaseRadioGen")
331  << " It is a box of size " << 2. * box->GetDX() << " x " << 2. * box->GetDY()
332  << " x " << 2. * box->GetDZ() << " cm^3\n";
333  }
334  }
335 
336  m_good_volumes.push_back(volume);
337  }
338  }
339 
340  for (int i = 0; i < materials->GetEntries(); ++i) {
341  TGeoMaterial* material = (TGeoMaterial*)materials->At(i);
342  std::string material_name = material->GetName();
343  bool good = std::regex_match(material_name, m_regex_material);
344  if (good) m_good_materials.push_back(material);
345  }
346  }
347  MF_LOG_INFO("BaseRadioGen") << m_good_volumes.size() << " volumes correspond to the regex \""
348  << m_volume_gen << "\".\n";
349  MF_LOG_INFO("BaseRadioGen") << m_good_materials.size()
350  << " materials correspond to the regex \"" << m_material << "\".\n";
351 
352  if (pset.has_key("X0") or pset.has_key("X1") or pset.has_key("Y0") or pset.has_key("Y1") or
353  pset.has_key("Z0") or pset.has_key("Z1")) {
356 
357  m_geo_volume_mode = false;
358  m_volume_rand_present = false;
359 
360  m_X0 = pset.get<double>("X0");
361  m_Y0 = pset.get<double>("Y0");
362  m_Z0 = pset.get<double>("Z0");
363  m_X1 = pset.get<double>("X1");
364  m_Y1 = pset.get<double>("Y1");
365  m_Z1 = pset.get<double>("Z1");
366 
367  CalculateActiveVolumeFromXYZ();
368  }
369  else {
370  const TGeoNode* world = gGeoManager->GetNode(0);
371 
372  if (pset.get_if_present<std::string>("volume_rand", m_volume_rand)) {
373  m_geo_volume_mode = false;
374  m_volume_rand_present = true;
375 
377  const TGeoNode* node = nullptr;
378  findNode(world, m_volume_rand, node);
379  GetNodeXYZMinMax(node, world, m_X0, m_X1, m_Y0, m_Y1, m_Z0, m_Z1);
380 
381  CalculateActiveVolumeFromXYZ();
382  }
383  else {
385  m_geo_volume_mode = true;
386  m_volume_rand_present = false;
387  CalculateActiveVolumeFromAllNodes();
388  }
389  }
390 
391  auto rand = CLHEP::RandFlat(m_engine);
392  gRandom->SetSeed(rand.fireInt(std::numeric_limits<long>::max()));
393 
394  if (pset.has_key("distrib_x"))
395  m_distrib_xpos = new TF1("distrib_x", pset.get<std::string>("distrib_x").c_str(), m_X0, m_X1);
396  if (pset.has_key("distrib_y"))
397  m_distrib_ypos = new TF1("distrib_y", pset.get<std::string>("distrib_y").c_str(), m_Y0, m_Y1);
398  if (pset.has_key("distrib_z"))
399  m_distrib_zpos = new TF1("distrib_z", pset.get<std::string>("distrib_z").c_str(), m_Z0, m_Z1);
400  }
401 
402  inline void BaseRadioGen::CalculateActiveVolumeFromAllNodes()
403  {
404  FillAllNodes(gGeoManager->GetTopNode());
405  m_volume_cc = 0;
406 
407  for (auto const& node : m_all_nodes) {
408  if (not NodeSupported(node)) continue;
409 
410  double capa = node->GetVolume()->GetShape()->Capacity();
411  m_volume_cc += capa;
412  m_good_nodes[node] = m_volume_cc;
413  }
414 
415  MF_LOG_INFO("BaseRadioGen")
416  << m_good_nodes.size() << " nodes (i.e. instance of the volumes) satisfy both the regexes.\n";
417 
418  if (empty(m_good_nodes))
419  throw cet::exception("BaseRadioGen")
420  << "Didn't find an instance of material " << m_material << " and the volume "
421  << m_volume_gen << " in the geometry.\n";
422  }
423 
424  inline void BaseRadioGen::CalculateActiveVolumeFromXYZ()
425  {
426  m_volume_cc = (m_X1 - m_X0) * (m_Y1 - m_Y0) * (m_Z1 - m_Z0);
427 
428  if (m_material != ".*" || m_volume_gen != ".*") {
429  MF_LOG_INFO("BaseRadioGen") << "Calculating the proportion of " << m_material
430  << " and the volume " << m_volume_gen
431  << " in the specified volume " << m_volume_rand << ".\n";
432  size_t nfound = 0;
433  size_t ntries = 0;
434 
435  double xyz[3];
436  TGeoNode* node = nullptr;
437 
438  while (nfound < m_target_n_point_rate_calculation and ntries < m_max_tries_rate_calculation) {
439  ntries++;
440  node = nullptr;
441  xyz[0] = m_X0 + (m_X1 - m_X0) * m_random_flat.fire(0, 1.);
442  xyz[1] = m_Y0 + (m_Y1 - m_Y0) * m_random_flat.fire(0, 1.);
443  xyz[2] = m_Z0 + (m_Z1 - m_Z0) * m_random_flat.fire(0, 1.);
444  m_geo_manager->SetCurrentPoint(xyz);
445  node = m_geo_manager->FindNode();
446  if (!node) continue;
447  if (node->IsOverlapping()) continue;
448 
449  if (!NodeSupported(node)) continue;
450  nfound++;
451  }
452 
453  if (nfound == 0) {
454  throw cet::exception("BaseRadioGen")
455  << "Didn't find the material " << m_material << " and the volume " << m_volume_gen
456  << " in the specified volume " << m_volume_rand << ".\n"
457  << "Position of the box:\n"
458  << m_X0 << " " << m_X1 << "\n"
459  << m_Y0 << " " << m_Y1 << "\n"
460  << m_Z0 << " " << m_Z1 << "\n";
461  }
462 
463  double proportion = (double)nfound / ntries;
464  double proportion_error = proportion * sqrt(1. / nfound + 1. / ntries);
465  m_volume_cc *= proportion;
466 
467  MF_LOG_INFO("BaseRadioGen")
468  << "There is " << proportion * 100. << "% (+/- " << proportion_error * 100. << "%) of "
469  << m_material << " and " << m_volume_gen << " in the specified volume ("
470  << 100. * proportion_error / proportion << "% relat. uncert.).\n"
471  << "If the uncertainty is too big, crank up the parameters \"max_tries_rate_calculation\" "
472  "(default=40,000,000) and/or \"target_n_point_rate_calculation\" (default=100,000) in "
473  "your fhicl.\n\n\n";
474  }
475  }
476 
477  inline void BaseRadioGen::produce(art::Event& evt)
478  {
479  m_nevent++;
480  produce_radio(evt);
481  }
482 
483  inline void BaseRadioGen::beginRun(art::Run& run)
484  {
485  art::ServiceHandle<geo::Geometry const> geo;
486  run.put(std::make_unique<sumdata::RunData>(m_geo_service->DetectorName()), art::fullRun());
487  beginRun_radio(run);
488  }
489 
490  inline void BaseRadioGen::beginJob()
491  {
492  if (m_isotope.empty()) {
493  throw cet::exception("BaseRadioGen")
494  << "m_isotope is empty, you need to fill it yourself in the constructor of your module\n";
495  }
496 
497  DeclareOutputHistos();
498  beginJob_radio();
499  m_nevent = 0;
500  }
501 
502  inline void BaseRadioGen::endJob()
503  {
504  if (m_nevent) {
505  m_pdg_TH1D->Scale(1. / m_nevent);
506 
507  for (auto histo : m_pos_xy_TH2D) {
508  m_pos_xy_TH2D[histo.first]->Scale(1. / m_nevent);
509  m_pos_xz_TH2D[histo.first]->Scale(1. / m_nevent);
510  m_dir_x_TH1D[histo.first]->Scale(1. / m_nevent);
511  m_dir_y_TH1D[histo.first]->Scale(1. / m_nevent);
512  m_dir_z_TH1D[histo.first]->Scale(1. / m_nevent);
513  m_mom_TH1D[histo.first]->Scale(1. / m_nevent);
514  m_ke_TH1D[histo.first]->Scale(1. / m_nevent);
515  m_time_TH1D[histo.first]->Scale(1. / m_nevent);
516  }
517  }
518  endJob_radio();
519  }
520 
521  inline bool BaseRadioGen::GetGoodPositionTime(TLorentzVector& position)
522  {
523 
525  double time = m_T0 + m_random_flat.fire() * (m_T1 - m_T0);
526 
527  if (not m_geo_volume_mode) {
529 
530  size_t n_tries = 0;
531 
532  double xpos = std::numeric_limits<double>::signaling_NaN();
533  double ypos = std::numeric_limits<double>::signaling_NaN();
534  double zpos = std::numeric_limits<double>::signaling_NaN();
535 
536  while (n_tries++ < m_max_tries_event) {
537 
538  if (m_distrib_xpos)
539  xpos = m_distrib_xpos->GetRandom(m_X0, m_X1);
540  else
541  xpos = m_X0 + m_random_flat.fire() * (m_X1 - m_X0);
542 
543  if (m_distrib_ypos)
544  ypos = m_distrib_ypos->GetRandom(m_Y0, m_Y1);
545  else
546  ypos = m_Y0 + m_random_flat.fire() * (m_Y1 - m_Y0);
547 
548  if (m_distrib_zpos)
549  zpos = m_distrib_zpos->GetRandom(m_Z0, m_Z1);
550  else
551  zpos = m_Z0 + m_random_flat.fire() * (m_Z1 - m_Z0);
552 
553  auto node = gGeoManager->FindNode(xpos, ypos, zpos);
554 
555  if (NodeSupported(node)) break;
556  }
557 
558  if (std::isnan(xpos) or std::isnan(ypos) or std::isnan(zpos)) {
559  MF_LOG_ERROR("BaseRadioGen") << "Error in generation of random position!";
560  }
561 
562  position.SetXYZT(xpos, ypos, zpos, time);
563  return true;
564  }
565  else {
567 
568  if (m_good_nodes.empty() or m_volume_cc == 0)
569  MF_LOG_ERROR("BaseRadioGen") << "There is no node to throw events in!";
570 
571  double which_vol = m_random_flat.fire() * m_volume_cc;
572 
573  const TGeoNode* node = nullptr;
574  size_t i = 0;
575 
576  for (auto const& nd : m_good_nodes) {
577  if (which_vol < nd.second) {
578  node = nd.first;
579  break;
580  }
581  i++;
582  }
583 
584  const TGeoNode* world = gGeoManager->GetNode(0);
585  double x_min, x_max;
586  double y_min, y_max;
587  double z_min, z_max;
588  GetNodeXYZMinMax(node, world, x_min, x_max, y_min, y_max, z_min, z_max);
589 
590  size_t n_tries = 0;
591 
592  while (n_tries++ < m_max_tries_event) {
593  double xpos = std::numeric_limits<double>::signaling_NaN();
594  double ypos = std::numeric_limits<double>::signaling_NaN();
595  double zpos = std::numeric_limits<double>::signaling_NaN();
596 
597  if (m_distrib_xpos)
598  xpos = m_distrib_xpos->GetRandom(x_min, x_max);
599  else
600  xpos = x_min + m_random_flat.fire() * (x_max - x_min);
601 
602  if (m_distrib_ypos)
603  ypos = m_distrib_ypos->GetRandom(y_min, y_max);
604  else
605  ypos = y_min + m_random_flat.fire() * (y_max - y_min);
606 
607  if (m_distrib_zpos)
608  zpos = m_distrib_zpos->GetRandom(z_min, z_max);
609  else
610  zpos = z_min + m_random_flat.fire() * (z_max - z_min);
611 
612  if (std::isnan(xpos) or std::isnan(ypos) or std::isnan(zpos)) {
613  MF_LOG_ERROR("BaseRadioGen") << "Error in generation of random position!";
614  }
615  position.SetXYZT(xpos, ypos, zpos, time);
616 
617  const TGeoNode* node_generated = gGeoManager->FindNode(xpos, ypos, zpos);
618  if (node_generated == node) return true;
619 
620  if (node->GetNdaughters() and IsDaughterNode(node_generated, node)) return true;
621  }
622  }
623 
624  return false;
625  }
626 
627  //____________________________________________________________________________
628  // Generate radioactive decays per isotope per volume according to the FCL parameters
629  inline int BaseRadioGen::GetNDecays()
630  {
631 
632  if (m_rate_mode) { return m_random_poisson.fire(m_rate); }
633  else {
634  double rate = abs(m_Bq * (m_T1 - m_T0) * m_volume_cc / 1.0E9);
635  return m_random_poisson.fire(rate);
636  }
637  }
638 
639  inline bool BaseRadioGen::IsDaughterNode(const TGeoNode* daughter_node,
640  const TGeoNode* mother_node)
641  {
642  if (mother_node == daughter_node) return true;
643 
644  TObjArray* daunodes = mother_node->GetNodes();
645  if (!daunodes) return false;
646 
647  TIter next(daunodes);
648  const TGeoNode* anode = 0;
649 
650  while ((anode = (const TGeoNode*)next())) {
651  bool found = IsDaughterNode(daughter_node, anode);
652  if (found) return true;
653  }
654 
655  return false;
656  }
657 
658  inline void BaseRadioGen::FillAllNodes(const TGeoNode* curnode)
659  {
660  if (!curnode) return;
661  TObjArray* daunodes = curnode->GetNodes();
662  if (!daunodes) return;
663 
664  TIter next(daunodes);
665 
666  const TGeoNode* anode = 0;
667  while ((anode = (const TGeoNode*)next())) {
668  m_all_nodes.insert(anode);
669  FillAllNodes(anode);
670  }
671  }
672 
673  inline bool BaseRadioGen::findNode(const TGeoNode* curnode,
674  std::string& tgtnname,
675  const TGeoNode*& targetnode)
677  {
678  std::string nname = curnode->GetName();
679  std::string vname = curnode->GetVolume()->GetName();
680  if (nname == tgtnname || vname == tgtnname) {
681  targetnode = curnode;
682  return true;
683  }
684 
685  TObjArray* daunodes = curnode->GetNodes();
686  if (!daunodes) return false;
687  TIter next(daunodes);
688  const TGeoNode* anode = 0;
689  while ((anode = (const TGeoNode*)next())) {
690  bool found = findNode(anode, tgtnname, targetnode);
691  if (found) return true;
692  }
693 
694  return false;
695  }
696 
697  inline bool BaseRadioGen::findMotherNode(const TGeoNode* cur_node,
698  std::string& daughter_name,
699  const TGeoNode*& mother_node)
701  {
702  TObjArray* daunodes = cur_node->GetNodes();
703 
704  if (!daunodes) return false;
705 
706  TIter next(daunodes);
707 
708  const TGeoNode* anode = 0;
709  bool found = 0;
710  while ((anode = (const TGeoNode*)next())) {
711  std::string nname = anode->GetName();
712  std::string vname = anode->GetVolume()->GetName();
713 
714  if (nname == daughter_name || vname == daughter_name) {
715  mother_node = cur_node;
716  return true;
717  }
718  found = findMotherNode(anode, daughter_name, mother_node);
719  }
720 
721  return found;
722  }
723 
724  inline void BaseRadioGen::DeclareOutputHistos()
725  {
726  art::ServiceHandle<art::TFileService> tfs;
727  auto pdgs = {1000020040, 11, -11, 22, 2112, 2212, 9999};
728  m_pdg_TH1D = tfs->make<TH1D>("PDG", ";PDG;n particles/event", pdgs.size(), 0, pdgs.size());
729 
730  for (auto pdg : pdgs) {
731 
732  std::string part = "";
733  int simple_pdg;
734  SimplePDG(pdg, simple_pdg, part);
735  art::TFileDirectory dir = tfs->mkdir(part.c_str());
736 
737  m_pos_xy_TH2D[simple_pdg] =
738  dir.make<TH2D>("posXY", ";X [cm];Y [cm]", 100, m_X0, m_X1, 100, m_Y0, m_Y1);
739  m_pos_xz_TH2D[simple_pdg] =
740  dir.make<TH2D>("posXZ", ";X [cm];Z [cm]", 100, m_X0, m_X1, 100, m_Z0, m_Z1);
741  m_dir_x_TH1D[simple_pdg] = dir.make<TH1D>("dirX", ";X momentum projection", 100, -1, 1);
742  m_dir_y_TH1D[simple_pdg] = dir.make<TH1D>("dirY", ";Y momentum projection", 100, -1, 1);
743  m_dir_z_TH1D[simple_pdg] = dir.make<TH1D>("dirZ", ";Z momentum projection", 100, -1, 1);
744  m_mom_TH1D[simple_pdg] =
745  dir.make<TH1D>("Momentum", ";Momentum [MeV];n particles/event", 5000, 0, 500);
746  m_ke_TH1D[simple_pdg] = dir.make<TH1D>("KE", ";KE [MeV];n particles/event", 5000, 0, 500);
747  m_time_TH1D[simple_pdg] =
748  dir.make<TH1D>("Time", ";Time[ns];n particles/event", 100, m_T0, m_T1);
749 
750  m_pdg_TH1D->GetXaxis()->SetBinLabel(simple_pdg + 1, part.c_str());
751  }
752  }
753 
754  inline void BaseRadioGen::SimplePDG(int pdg, int& simple, std::string& name)
755  {
756  switch (pdg) {
757  case 1000020040:
758  name = "alpha";
759  simple = 0;
760  return;
761  case 22:
762  name = "gamma";
763  simple = 1;
764  return;
765  case -11:
766  name = "positron";
767  simple = 2;
768  return;
769  case 11:
770  name = "electron";
771  simple = 3;
772  return;
773  case 2112:
774  name = "neutron";
775  simple = 4;
776  return;
777  case 2212:
778  name = "proton";
779  simple = 5;
780  return;
781  default:
782  name = "other";
783  simple = 6;
784  return;
785  }
786  }
787 
788  inline void BaseRadioGen::FillHistos(simb::MCParticle& part)
789  {
790  int pdg = part.PdgCode();
791  int simple_pdg = 0;
792  std::string dummy = "";
793  SimplePDG(pdg, simple_pdg, dummy);
794 
795  TLorentzVector position = part.Position();
796  TLorentzVector mom = part.Momentum();
797  double mass = mom.M();
798  m_pos_xy_TH2D[simple_pdg]->Fill(position.X(), position.Y());
799  m_pos_xz_TH2D[simple_pdg]->Fill(position.X(), position.Z());
800  m_dir_x_TH1D[simple_pdg]->Fill(mom.Px() / mom.P());
801  m_dir_y_TH1D[simple_pdg]->Fill(mom.Py() / mom.P());
802  m_dir_z_TH1D[simple_pdg]->Fill(mom.Pz() / mom.P());
803  double ke = (sqrt(mom.P() * mom.P() + mass * mass) - mass) * 1000.;
804  m_ke_TH1D[simple_pdg]->Fill(ke);
805  m_mom_TH1D[simple_pdg]->Fill(mom.P() * 1000.);
806  m_time_TH1D[simple_pdg]->Fill(position.T());
807  m_pdg_TH1D->Fill(simple_pdg);
808  }
809 
810  inline TLorentzVector BaseRadioGen::dirCalc(double p, double m)
811  {
812  // isotropic production angle for the decay product
813  double costheta = (2.0 * m_random_flat.fire() - 1.0);
814 
815  if (costheta < -1.0) costheta = -1.0;
816  if (costheta > 1.0) costheta = 1.0;
817 
818  double const sintheta = sqrt(1.0 - costheta * costheta);
819  double const phi = 2.0 * M_PI * m_random_flat.fire();
820 
821  return TLorentzVector{p * sintheta * std::cos(phi),
822  p * sintheta * std::sin(phi),
823  p * costheta,
824  std::sqrt(p * p + m * m)};
825  }
826 
827 } //end namespace evgen
CLHEP::RandPoisson m_random_poisson
Definition: BaseRadioGen.h:162
base_engine_t & createEngine(seed_t seed)
void SimplePDG(int pdg, int &simple, std::string &name)
Definition: BaseRadioGen.h:754
void beginRun(art::Run &run)
Definition: BaseRadioGen.h:483
double m_X1
Top corner x position (cm) in world coordinates.
Definition: BaseRadioGen.h:152
void CalculateActiveVolumeFromXYZ()
Definition: BaseRadioGen.h:424
std::set< const TGeoNode * > m_all_nodes
Definition: BaseRadioGen.h:120
std::map< const TGeoNode *, double > m_good_nodes
Definition: BaseRadioGen.h:172
std::map< int, TH1D * > m_dir_y_TH1D
Definition: BaseRadioGen.h:184
bool NodeSupported(TGeoNode const *node) const
Definition: BaseRadioGen.h:192
std::vector< const TGeoVolume * > m_good_volumes
Definition: BaseRadioGen.h:173
size_t m_target_n_point_rate_calculation
Definition: BaseRadioGen.h:170
std::map< int, TH1D * > m_dir_x_TH1D
Definition: BaseRadioGen.h:183
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
TLorentzVector dirCalc(double p, double m)
Definition: BaseRadioGen.h:810
virtual void endJob_radio()
Definition: BaseRadioGen.h:82
void produce(art::Event &evt)
Definition: BaseRadioGen.h:477
std::string m_volume_gen
The volume in which to generate the decays.
Definition: BaseRadioGen.h:139
std::map< int, TH1D * > m_mom_TH1D
Definition: BaseRadioGen.h:186
const std::string instance
void GetYs(double &Y0, double &Y1)
Definition: BaseRadioGen.h:104
double m_rate
Radioactivity in Becquerels (decay per sec) use either of this of Bq.
Definition: BaseRadioGen.h:145
Particle class.
void FillHistos(simb::MCParticle &part)
Definition: BaseRadioGen.h:788
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
Definition: Run.h:37
std::string m_material
regex of materials in which to generate the decays. Example: "LAr"
Definition: BaseRadioGen.h:137
double x_min
Definition: berger.C:15
TGeoManager * m_geo_manager
Definition: BaseRadioGen.h:158
TString part[npart]
Definition: Style.C:32
virtual void beginRun_radio(art::Run &)
Definition: BaseRadioGen.h:80
bool findMotherNode(const TGeoNode *cur_node, std::string &daughter_name, const TGeoNode *&mother_node)
Adapted from above.
Definition: BaseRadioGen.h:697
virtual void beginJob_radio()
Definition: BaseRadioGen.h:81
static constexpr double signaling_NaN
Definition: BaseRadioGen.h:143
double m_Y1
Top corner y position (cm) in world coordinates.
Definition: BaseRadioGen.h:153
std::string m_volume_rand
The volume in which to generate the decays.
Definition: BaseRadioGen.h:138
Double_t X1
Definition: plot.C:263
Double_t Y1
Definition: plot.C:263
double m_Z1
Top corner z position (cm) in world coordinates.
Definition: BaseRadioGen.h:154
CLHEP::HepRandomEngine & GetRandomEngine()
Definition: BaseRadioGen.h:92
std::regex m_regex_volume
Definition: BaseRadioGen.h:141
BaseRadioGen(fhicl::ParameterSet const &pset)
Definition: BaseRadioGen.h:269
std::map< int, TH1D * > m_ke_TH1D
Definition: BaseRadioGen.h:187
std::vector< std::string > m_isotope
isotope to simulate. Example: "Ar39"
Definition: BaseRadioGen.h:90
double m_T0
Beginning of time window to simulate in ns.
Definition: BaseRadioGen.h:147
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
size_t m_max_tries_rate_calculation
Definition: BaseRadioGen.h:169
art::ServiceHandle< geo::Geometry const > m_geo_service
Definition: BaseRadioGen.h:157
bool GetGoodPositionTime(TLorentzVector &position)
Definition: BaseRadioGen.h:521
std::map< int, TH1D * > m_dir_z_TH1D
Definition: BaseRadioGen.h:185
void GetXs(double &X0, double &X1)
Definition: BaseRadioGen.h:99
Double_t Z1
Definition: plot.C:263
double x_max
Definition: berger.C:16
ifstream in
Definition: comparison.C:7
double m_Z0
Bottom corner z position (cm) in world coordinates.
Definition: BaseRadioGen.h:151
void GetZs(double &Z0, double &Z1)
Definition: BaseRadioGen.h:109
bool IsDaughterNode(const TGeoNode *daughter_node, const TGeoNode *mother_node)
Definition: BaseRadioGen.h:639
void CalculateActiveVolumeFromAllNodes()
Definition: BaseRadioGen.h:402
void GetTs(double &T0, double &T1)
Definition: BaseRadioGen.h:94
virtual void produce_radio(art::Event &evt)=0
void FillAllNodes(const TGeoNode *curnode)
Definition: BaseRadioGen.h:658
std::map< int, TH2D * > m_pos_xz_TH2D
Definition: BaseRadioGen.h:182
double m_Bq
Radioactivity in Becquerels (decay per sec) per cubic cm.
Definition: BaseRadioGen.h:144
CLHEP::RandFlat m_random_flat
Definition: BaseRadioGen.h:161
std::map< int, TH1D * > m_time_TH1D
Definition: BaseRadioGen.h:188
TCEvent evt
Definition: DataStructs.cxx:8
std::regex m_regex_material
Definition: BaseRadioGen.h:140
double m_Y0
Bottom corner y position (cm) in world coordinates.
Definition: BaseRadioGen.h:150
Event Generation using GENIE, cosmics or single particles.
double m_X0
Bottom corner x position (cm) in world coordinates.
Definition: BaseRadioGen.h:149
CLHEP::HepRandomEngine & m_engine
Definition: BaseRadioGen.h:160
std::map< int, TH2D * > m_pos_xy_TH2D
Definition: BaseRadioGen.h:181
art framework interface to geometry description
bool findNode(const TGeoNode *curnode, std::string &tgtnname, const TGeoNode *&targetnode)
Shamelessly stolen from here: https://cdcvs.fnal.gov/redmine/attachments/6719/calc_bbox.C.
Definition: BaseRadioGen.h:673
std::vector< const TGeoMaterial * > m_good_materials
Definition: BaseRadioGen.h:174
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:229
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double m_T1
End of time window to simulate in ns.
Definition: BaseRadioGen.h:148
void GetNodeXYZMinMax(const TGeoNode *from, const TGeoNode *to, double &x_min, double &x_max, double &y_min, double &y_max, double &z_min, double &z_max)
Definition: BaseRadioGen.h:199