7 #include "cetlib/container_algorithms.h" 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" 40 #include "TGenPhaseSpace.h" 41 #include "TGeoManager.h" 42 #include "TGeoMaterial.h" 47 #include "TLorentzVector.h" 52 #include "CLHEP/Random/RandFlat.h" 53 #include "CLHEP/Random/RandPoisson.h" 87 TLorentzVector
dirCalc(
double p,
double m);
94 void GetTs(
double& T0,
double& T1)
118 void SimplePDG(
int pdg,
int& simple, std::string& name);
130 bool IsDaughterNode(
const TGeoNode* daughter_node,
const TGeoNode* mother_node);
131 bool findNode(
const TGeoNode* curnode, std::string& tgtnname,
const TGeoNode*& targetnode);
133 std::string& daughter_name,
134 const TGeoNode*& mother_node);
143 static constexpr
double signaling_NaN = std::numeric_limits<double>::signaling_NaN();
194 assert(node !=
nullptr);
208 std::vector<const TGeoNode*> mother_nodes;
209 const TGeoNode* current_node = from;
210 std::string daughter_name = from->GetName();
213 while (current_node != to and iter++ < nmax) {
214 const TGeoNode* mother_node =
nullptr;
215 daughter_name = current_node->GetName();
219 <<
"Didn't find the mum of the following node: " << daughter_name;
221 mother_nodes.push_back(mother_node);
222 current_node = mother_node;
225 TGeoVolume* vol = from->GetVolume();
226 TGeoShape* shape = vol->GetShape();
227 TGeoBBox* bbox = (TGeoBBox*)shape;
229 double dx = bbox->GetDX();
230 double dy = bbox->GetDY();
231 double dz = bbox->GetDZ();
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};
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) {
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];
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);
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]);
271 ,
m_material{pset.get<std::string>(
"material",
".*")}
273 ,
m_volume_gen{pset.get<std::string>(
"volume_gen",
".*")}
290 pset.get<
size_t>(
"target_n_point_rate_calculation", 100
'000)} 292 produces<std::vector<simb::MCTruth>>(); 293 produces<sumdata::RunData, art::InRun>(); 295 m_rate_mode = pset.get_if_present<double>("rate", m_rate); 296 if (not m_rate_mode) m_Bq = pset.get<double>("BqPercc"); 298 bool timed_mode = pset.get_if_present<double>("T0", m_T0); 299 if (timed_mode) { m_T1 = pset.get<double>("T1"); } 301 auto const clockData = 302 art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob(); 304 art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData); 305 int nsample = detProp.NumberTimeSamples(); 306 m_T0 = -nsample * sampling_rate(clockData); 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"; 314 TObjArray* volumes = m_geo_manager->GetListOfVolumes(); 315 TList* materials = m_geo_manager->GetListOfMaterials(); 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); 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()); 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"; 336 m_good_volumes.push_back(volume); 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); 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"; 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")) { 357 m_geo_volume_mode = false; 358 m_volume_rand_present = false; 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"); 367 CalculateActiveVolumeFromXYZ(); 370 const TGeoNode* world = gGeoManager->GetNode(0); 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; 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); 381 CalculateActiveVolumeFromXYZ(); 385 m_geo_volume_mode = true; 386 m_volume_rand_present = false; 387 CalculateActiveVolumeFromAllNodes(); 391 auto rand = CLHEP::RandFlat(m_engine); 392 gRandom->SetSeed(rand.fireInt(std::numeric_limits<long>::max())); 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); 402 inline void BaseRadioGen::CalculateActiveVolumeFromAllNodes() 404 FillAllNodes(gGeoManager->GetTopNode()); 407 for (auto const& node : m_all_nodes) { 408 if (not NodeSupported(node)) continue; 410 double capa = node->GetVolume()->GetShape()->Capacity(); 412 m_good_nodes[node] = m_volume_cc; 415 MF_LOG_INFO("BaseRadioGen") 416 << m_good_nodes.size() << " nodes (i.e. instance of the volumes) satisfy both the regexes.\n"; 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
"; 424 inline void BaseRadioGen::CalculateActiveVolumeFromXYZ() 426 m_volume_cc = (m_X1 - m_X0) * (m_Y1 - m_Y0) * (m_Z1 - m_Z0); 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
"; 436 TGeoNode* node = nullptr; 438 while (nfound < m_target_n_point_rate_calculation and ntries < m_max_tries_rate_calculation) { 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(); 447 if (node->IsOverlapping()) continue; 449 if (!NodeSupported(node)) continue; 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"; 463 double proportion = (double)nfound / ntries; 464 double proportion_error = proportion * sqrt(1. / nfound + 1. / ntries); 465 m_volume_cc *= proportion; 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 " 477 inline void BaseRadioGen::produce(art::Event& evt) 483 inline void BaseRadioGen::beginRun(art::Run& run) 485 art::ServiceHandle<geo::Geometry const> geo; 486 run.put(std::make_unique<sumdata::RunData>(m_geo_service->DetectorName()), art::fullRun()); 490 inline void BaseRadioGen::beginJob() 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"; 497 DeclareOutputHistos(); 502 inline void BaseRadioGen::endJob() 505 m_pdg_TH1D->Scale(1. / m_nevent); 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); 521 inline bool BaseRadioGen::GetGoodPositionTime(TLorentzVector& position) 525 double time = m_T0 + m_random_flat.fire() * (m_T1 - m_T0); 527 if (not m_geo_volume_mode) { 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(); 536 while (n_tries++ < m_max_tries_event) { 539 xpos = m_distrib_xpos->GetRandom(m_X0, m_X1); 541 xpos = m_X0 + m_random_flat.fire() * (m_X1 - m_X0); 544 ypos = m_distrib_ypos->GetRandom(m_Y0, m_Y1); 546 ypos = m_Y0 + m_random_flat.fire() * (m_Y1 - m_Y0); 549 zpos = m_distrib_zpos->GetRandom(m_Z0, m_Z1); 551 zpos = m_Z0 + m_random_flat.fire() * (m_Z1 - m_Z0); 553 auto node = gGeoManager->FindNode(xpos, ypos, zpos); 555 if (NodeSupported(node)) break; 558 if (std::isnan(xpos) or std::isnan(ypos) or std::isnan(zpos)) { 559 MF_LOG_ERROR("BaseRadioGen") << "Error in generation of random position!"; 562 position.SetXYZT(xpos, ypos, zpos, time); 568 if (m_good_nodes.empty() or m_volume_cc == 0) 569 MF_LOG_ERROR("BaseRadioGen") << "There is no node to throw events in!"; 571 double which_vol = m_random_flat.fire() * m_volume_cc; 573 const TGeoNode* node = nullptr; 576 for (auto const& nd : m_good_nodes) { 577 if (which_vol < nd.second) { 584 const TGeoNode* world = gGeoManager->GetNode(0); 588 GetNodeXYZMinMax(node, world, x_min, x_max, y_min, y_max, z_min, z_max); 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(); 598 xpos = m_distrib_xpos->GetRandom(x_min, x_max); 600 xpos = x_min + m_random_flat.fire() * (x_max - x_min); 603 ypos = m_distrib_ypos->GetRandom(y_min, y_max); 605 ypos = y_min + m_random_flat.fire() * (y_max - y_min); 608 zpos = m_distrib_zpos->GetRandom(z_min, z_max); 610 zpos = z_min + m_random_flat.fire() * (z_max - z_min); 612 if (std::isnan(xpos) or std::isnan(ypos) or std::isnan(zpos)) { 613 MF_LOG_ERROR("BaseRadioGen") << "Error in generation of random position!"; 615 position.SetXYZT(xpos, ypos, zpos, time); 617 const TGeoNode* node_generated = gGeoManager->FindNode(xpos, ypos, zpos); 618 if (node_generated == node) return true; 620 if (node->GetNdaughters() and IsDaughterNode(node_generated, node)) return true; 627 //____________________________________________________________________________ 628 // Generate radioactive decays per isotope per volume according to the FCL parameters 629 inline int BaseRadioGen::GetNDecays() 632 if (m_rate_mode) { return m_random_poisson.fire(m_rate); } 634 double rate = abs(m_Bq * (m_T1 - m_T0) * m_volume_cc / 1.0E9); 635 return m_random_poisson.fire(rate); 639 inline bool BaseRadioGen::IsDaughterNode(const TGeoNode* daughter_node, 640 const TGeoNode* mother_node) 642 if (mother_node == daughter_node) return true; 644 TObjArray* daunodes = mother_node->GetNodes(); 645 if (!daunodes) return false; 647 TIter next(daunodes); 648 const TGeoNode* anode = 0; 650 while ((anode = (const TGeoNode*)next())) { 651 bool found = IsDaughterNode(daughter_node, anode); 652 if (found) return true; 658 inline void BaseRadioGen::FillAllNodes(const TGeoNode* curnode) 660 if (!curnode) return; 661 TObjArray* daunodes = curnode->GetNodes(); 662 if (!daunodes) return; 664 TIter next(daunodes); 666 const TGeoNode* anode = 0; 667 while ((anode = (const TGeoNode*)next())) { 668 m_all_nodes.insert(anode); 673 inline bool BaseRadioGen::findNode(const TGeoNode* curnode, 674 std::string& tgtnname, 675 const TGeoNode*& targetnode) 678 std::string nname = curnode->GetName(); 679 std::string vname = curnode->GetVolume()->GetName(); 680 if (nname == tgtnname || vname == tgtnname) { 681 targetnode = curnode; 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; 697 inline bool BaseRadioGen::findMotherNode(const TGeoNode* cur_node, 698 std::string& daughter_name, 699 const TGeoNode*& mother_node) 702 TObjArray* daunodes = cur_node->GetNodes(); 704 if (!daunodes) return false; 706 TIter next(daunodes); 708 const TGeoNode* anode = 0; 710 while ((anode = (const TGeoNode*)next())) { 711 std::string nname = anode->GetName(); 712 std::string vname = anode->GetVolume()->GetName(); 714 if (nname == daughter_name || vname == daughter_name) { 715 mother_node = cur_node; 718 found = findMotherNode(anode, daughter_name, mother_node); 724 inline void BaseRadioGen::DeclareOutputHistos() 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()); 730 for (auto pdg : pdgs) { 732 std::string part = ""; 734 SimplePDG(pdg, simple_pdg, part); 735 art::TFileDirectory dir = tfs->mkdir(part.c_str()); 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); 750 m_pdg_TH1D->GetXaxis()->SetBinLabel(simple_pdg + 1, part.c_str()); 754 inline void BaseRadioGen::SimplePDG(int pdg, int& simple, std::string& name) 788 inline void BaseRadioGen::FillHistos(simb::MCParticle& part) 790 int pdg = part.PdgCode(); 792 std::string dummy = ""; 793 SimplePDG(pdg, simple_pdg, dummy); 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); 810 inline TLorentzVector BaseRadioGen::dirCalc(double p, double m) 812 // isotropic production angle for the decay product 813 double costheta = (2.0 * m_random_flat.fire() - 1.0); 815 if (costheta < -1.0) costheta = -1.0; 816 if (costheta > 1.0) costheta = 1.0; 818 double const sintheta = sqrt(1.0 - costheta * costheta); 819 double const phi = 2.0 * M_PI * m_random_flat.fire(); 821 return TLorentzVector{p * sintheta * std::cos(phi), 822 p * sintheta * std::sin(phi), 824 std::sqrt(p * p + m * m)}; 827 } //end namespace evgen CLHEP::RandPoisson m_random_poisson
base_engine_t & createEngine(seed_t seed)
void SimplePDG(int pdg, int &simple, std::string &name)
void beginRun(art::Run &run)
double m_X1
Top corner x position (cm) in world coordinates.
void CalculateActiveVolumeFromXYZ()
std::set< const TGeoNode * > m_all_nodes
std::map< const TGeoNode *, double > m_good_nodes
std::map< int, TH1D * > m_dir_y_TH1D
bool NodeSupported(TGeoNode const *node) const
std::vector< const TGeoVolume * > m_good_volumes
size_t m_target_n_point_rate_calculation
std::map< int, TH1D * > m_dir_x_TH1D
EDProducer(fhicl::ParameterSet const &pset)
TLorentzVector dirCalc(double p, double m)
virtual void endJob_radio()
void produce(art::Event &evt)
std::string m_volume_gen
The volume in which to generate the decays.
std::map< int, TH1D * > m_mom_TH1D
const std::string instance
void GetYs(double &Y0, double &Y1)
double m_rate
Radioactivity in Becquerels (decay per sec) use either of this of Bq.
void FillHistos(simb::MCParticle &part)
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
std::string m_material
regex of materials in which to generate the decays. Example: "LAr"
TGeoManager * m_geo_manager
virtual void beginRun_radio(art::Run &)
bool findMotherNode(const TGeoNode *cur_node, std::string &daughter_name, const TGeoNode *&mother_node)
Adapted from above.
virtual void beginJob_radio()
static constexpr double signaling_NaN
double m_Y1
Top corner y position (cm) in world coordinates.
std::string m_volume_rand
The volume in which to generate the decays.
void DeclareOutputHistos()
double m_Z1
Top corner z position (cm) in world coordinates.
CLHEP::HepRandomEngine & GetRandomEngine()
std::regex m_regex_volume
BaseRadioGen(fhicl::ParameterSet const &pset)
std::map< int, TH1D * > m_ke_TH1D
std::vector< std::string > m_isotope
isotope to simulate. Example: "Ar39"
double m_T0
Beginning of time window to simulate in ns.
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
art::ServiceHandle< geo::Geometry const > m_geo_service
bool GetGoodPositionTime(TLorentzVector &position)
std::map< int, TH1D * > m_dir_z_TH1D
void GetXs(double &X0, double &X1)
bool m_volume_rand_present
double m_Z0
Bottom corner z position (cm) in world coordinates.
void GetZs(double &Z0, double &Z1)
bool IsDaughterNode(const TGeoNode *daughter_node, const TGeoNode *mother_node)
void CalculateActiveVolumeFromAllNodes()
void GetTs(double &T0, double &T1)
virtual void produce_radio(art::Event &evt)=0
void FillAllNodes(const TGeoNode *curnode)
std::map< int, TH2D * > m_pos_xz_TH2D
double m_Bq
Radioactivity in Becquerels (decay per sec) per cubic cm.
CLHEP::RandFlat m_random_flat
std::map< int, TH1D * > m_time_TH1D
std::regex m_regex_material
double m_Y0
Bottom corner y position (cm) in world coordinates.
Event Generation using GENIE, cosmics or single particles.
double m_X0
Bottom corner x position (cm) in world coordinates.
CLHEP::HepRandomEngine & m_engine
std::map< int, TH2D * > m_pos_xy_TH2D
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.
std::vector< const TGeoMaterial * > m_good_materials
constexpr Point origin()
Returns a origin position with a point of the specified type.
cet::coded_exception< error, detail::translate > exception
double m_T1
End of time window to simulate in ns.
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)