53 #include "cetlib/exempt_ptr.h" 54 #include "cetlib/search_path.h" 55 #include "cetlib_except/exception.h" 88 #include "TGenPhaseSpace.h" 90 #include "TGeoManager.h" 91 #include "TGeoMaterial.h" 93 #include "TGeoVolume.h" 97 #include "TLorentzVector.h" 100 #include "range/v3/view/enumerate.hpp" 102 #include "CLHEP/Random/RandFlat.h" 103 #include "CLHEP/Random/RandPoisson.h" 210 std::size_t addvolume(std::string
const& volumeName);
215 TLorentzVector dirCalc(
double p,
double m);
217 void readfile(std::string nuclide, std::string
const& filename, std::string
const& PathToFile);
218 void samplespectrum(std::string nuclide,
int& itype,
double& t,
double& m,
double& p);
220 void Ar42Gamma2(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
221 void Ar42Gamma3(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
222 void Ar42Gamma4(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
223 void Ar42Gamma5(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
226 double samplefromth1d(TH1D&
hist);
229 template <
typename Stream>
230 void dumpNuclideSettings(Stream&& out,
232 std::string
const& volumeName = {})
const;
235 std::pair<double, double> defaulttimewindow()
const;
248 std::vector<std::string>
281 constexpr
double m_e = 0.000510998928;
282 constexpr
double m_alpha = 3.727379240;
283 constexpr
double m_neutron = 0.9395654133;
291 ,
fX0{pset.get<std::vector<double>>(
"X0", {})}
292 ,
fY0{pset.get<std::vector<double>>(
"Y0", {})}
293 ,
fZ0{pset.get<std::vector<double>>(
"Z0", {})}
294 ,
fX1{pset.get<std::vector<double>>(
"X1", {})}
295 ,
fY1{pset.get<std::vector<double>>(
"Y1", {})}
296 ,
fZ1{pset.get<std::vector<double>>(
"Z1", {})}
304 produces<std::vector<simb::MCTruth>>();
305 produces<sumdata::RunData, art::InRun>();
307 auto const fPathToFile = pset.get<std::string>(
"PathToFile",
"Radionuclides/");
308 auto const nuclide = pset.get<std::vector<std::string>>(
"Nuclide");
309 auto const material = pset.get<std::vector<std::string>>(
"Material");
310 auto const Bq = pset.get<std::vector<double>>(
"BqPercc");
311 auto t0 = pset.get<std::vector<double>>(
"T0", {});
312 auto t1 = pset.get<std::vector<double>>(
"T1", {});
314 if (fPathToFile.find_last_of(
'/') !=
315 fPathToFile.length() - 1) {
317 <<
"Last entry of the path to radiological files needs to be a forward slash ('/')\n";
320 if (
fT0.empty() ||
fT1.empty()) {
321 if (!
fT0.empty() || !
fT1.empty()) {
323 <<
"RadioGen T0 and T1 need to be both non-empty, or both empty" 325 <<
fT0.size() <<
" entries and T1 has " <<
fT0.size() <<
")\n";
328 t0.push_back(defaultT0);
329 t1.push_back(defaultT1);
338 mf::LogInfo(
"RadioGen") <<
"Configuring activity:";
341 fNuclide.push_back(nuclide.at(iCoord));
342 fMaterial.push_back(material.at(iCoord));
343 fBq.push_back(Bq.at(iCoord));
345 fT0.push_back(t0[std::min(iCoord, t0.size() - 1U)]);
346 fT1.push_back(t1[std::min(iCoord, t1.size() - 1U)]);
352 std::size_t iNext =
fX0.size();
353 auto const volumes = pset.get<std::vector<std::string>>(
"Volumes", {});
356 auto const nVolumes =
addvolume(volName);
359 <<
"No volume named '" << volName <<
"' was found!\n";
362 std::size_t
const iVolFirst =
fNuclide.size();
364 fNuclide.push_back(nuclide.at(iNext));
366 fBq.push_back(Bq.at(iNext));
368 fT0.push_back(t0[std::min(iNext, t0.size() - 1U)]);
369 fT1.push_back(t1[std::min(iNext, t1.size() - 1U)]);
377 unsigned int nsize =
fNuclide.size();
383 throw cet::exception(
"RadioGen") <<
"Different size Material vector and Nuclide vector\n";
384 if (
fBq.size() != nsize)
385 throw cet::exception(
"RadioGen") <<
"Different size Bq vector and Nuclide vector\n";
386 if (
fT0.size() != nsize)
387 throw cet::exception(
"RadioGen") <<
"Different size T0 vector and Nuclide vector\n";
388 if (
fT1.size() != nsize)
389 throw cet::exception(
"RadioGen") <<
"Different size T1 vector and Nuclide vector\n";
390 if (
fX0.size() != nsize)
391 throw cet::exception(
"RadioGen") <<
"Different size X0 vector and Nuclide vector\n";
392 if (
fY0.size() != nsize)
393 throw cet::exception(
"RadioGen") <<
"Different size Y0 vector and Nuclide vector\n";
394 if (
fZ0.size() != nsize)
395 throw cet::exception(
"RadioGen") <<
"Different size Z0 vector and Nuclide vector\n";
396 if (
fX1.size() != nsize)
397 throw cet::exception(
"RadioGen") <<
"Different size X1 vector and Nuclide vector\n";
398 if (
fY1.size() != nsize)
399 throw cet::exception(
"RadioGen") <<
"Different size Y1 vector and Nuclide vector\n";
400 if (
fZ1.size() != nsize)
401 throw cet::exception(
"RadioGen") <<
"Different size Z1 vector and Nuclide vector\n";
403 for (std::string& nuclideName :
fNuclide) {
404 if (nuclideName ==
"39Ar") {
readfile(
"39Ar",
"Argon_39.root", fPathToFile); }
405 else if (nuclideName ==
"60Co") {
406 readfile(
"60Co",
"Cobalt_60.root", fPathToFile);
408 else if (nuclideName ==
"85Kr") {
409 readfile(
"85Kr",
"Krypton_85.root", fPathToFile);
411 else if (nuclideName ==
"40K") {
412 readfile(
"40K",
"Potassium_40.root", fPathToFile);
414 else if (nuclideName ==
"232Th") {
415 readfile(
"232Th",
"Thorium_232.root", fPathToFile);
417 else if (nuclideName ==
"238U") {
418 readfile(
"238U",
"Uranium_238.root", fPathToFile);
420 else if (nuclideName ==
"222Rn") {
423 else if (nuclideName ==
"59Ni") {
426 else if (nuclideName ==
"42Ar") {
443 readfile(
"42Ar_5",
"Argon_42_5.root", fPathToFile);
447 std::string searchName = nuclideName;
448 searchName +=
".root";
449 readfile(nuclideName, searchName, fPathToFile);
465 std::unique_ptr<std::vector<simb::MCTruth>> truthcol(
new std::vector<simb::MCTruth>);
471 for (
unsigned int i = 0; i <
fNuclide.size(); ++i) {
476 truthcol->push_back(truth);
477 evt.
put(std::move(truthcol));
484 auto const& geom = *(lar::providerFrom<geo::Geometry>());
486 std::vector<geo::GeoNodePath> volumePaths;
487 auto findVolume = [&volumePaths, volumeName](
auto& path) {
488 if (path.current()->GetVolume()->GetName() == volumeName) volumePaths.push_back(path);
494 navigator.
apply(findVolume);
501 TGeoShape
const* pShape = path.current()->GetVolume()->GetShape();
502 auto pBox =
dynamic_cast<TGeoBBox const*
>(pShape);
504 throw cet::exception(
"RadioGen") <<
"Volume '" << path.current()->GetName() <<
"' is a " 505 << pShape->IsA()->GetName() <<
", not a TGeoBBox.\n";
508 geo::Point_t const origin = geo::vect::makeFromCoords<geo::Point_t>(pBox->GetOrigin());
509 geo::Vector_t const diag = {pBox->GetDX(), pBox->GetDY(), pBox->GetDZ()};
518 trans.Transform(origin - diag, min);
519 trans.Transform(origin + diag, max);
524 fX0.push_back(std::min(min.X(), max.X()));
525 fY0.push_back(std::min(min.Y(), max.Y()));
526 fZ0.push_back(std::min(min.Z(), max.Z()));
527 fX1.push_back(std::max(min.X(), max.X()));
528 fY1.push_back(std::max(min.Y(), max.Y()));
529 fZ1.push_back(std::max(min.Z(), max.Z()));
533 return volumePaths.size();
545 CLHEP::RandPoisson poisson(
fEngine);
553 long ndecays = poisson.shoot(rate);
555 std::regex
const re_material{
fMaterial[i]};
556 for (
unsigned int idecay = 0; idecay < ndecays; idecay++) {
563 fX0[i] + flat.fire() * (
fX1[i] -
fX0[i]),
564 fY0[i] + flat.fire() * (
fY1[i] -
fY0[i]),
565 fZ0[i] + flat.fire() * (
fZ1[i] -
fZ0[i]),
569 std::string volmaterial =
570 geomanager->FindNode(pos.X(), pos.Y(), pos.Z())->GetMedium()->GetMaterial()->GetName();
571 if (!std::regex_match(volmaterial, re_material))
continue;
577 std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>
583 double t = 0.00548952;
587 double p2 = energy * energy - m * m;
592 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
601 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
608 double bSelect = flat.fire();
609 if (bSelect < 0.819) {
611 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
614 else if (bSelect < 0.9954) {
616 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
623 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
630 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
635 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
647 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom =
648 std::make_tuple(pdgid, m,
dirCalc(p, m));
649 v_prods.push_back(partMassMom);
653 for (
auto prodEntry : v_prods) {
656 ti_PDGID pdgid = std::get<0>(prodEntry);
657 td_Mass m = std::get<1>(prodEntry);
658 TLorentzVector pvec = std::get<2>(prodEntry);
660 std::string primary(
"primary");
664 if (pdgid == 1000020040) {
683 double costheta = (2.0 * flat.fire() - 1.0);
684 if (costheta < -1.0) costheta = -1.0;
685 if (costheta > 1.0) costheta = 1.0;
686 double const sintheta = sqrt(1.0 - costheta * costheta);
687 double const phi = 2.0 * M_PI * flat.fire();
688 return TLorentzVector{p * sintheta * std::cos(phi),
689 p * sintheta * std::sin(phi),
691 std::sqrt(p * p + m * m)};
697 std::string
const& filename,
698 std::string
const& PathToFile)
701 std::regex
const re_argon{
"42Ar.*"};
702 for (
size_t i = 0; i <
fNuclide.size(); i++) {
709 else if (std::regex_match(nuclide, re_argon) &&
fNuclide[i] ==
"42Ar") {
716 Bool_t addStatus = TH1::AddDirectoryStatus();
722 cet::search_path sp(
"FW_SEARCH_PATH");
723 std::string fn2 = PathToFile;
725 std::string fullname;
726 sp.find_file(fn2, fullname);
728 if (fullname.empty() || stat(fullname.c_str(), &sb) != 0)
730 <<
"Input spectrum file " << fn2 <<
" not found in FW_SEARCH_PATH!\n";
732 TFile
f(fullname.c_str(),
"READ");
733 TGraph* alphagraph = (TGraph*)
f.Get(
"Alphas");
734 TGraph* betagraph = (TGraph*)
f.Get(
"Betas");
735 TGraph* gammagraph = (TGraph*)
f.Get(
"Gammas");
736 TGraph* neutrongraph = (TGraph*)
f.Get(
"Neutrons");
739 int np = alphagraph->GetN();
740 double*
y = alphagraph->GetY();
745 auto alphahist = std::make_unique<TH1D>(name.c_str(),
"Alpha Spectrum", np, 0, np);
746 for (
int i = 0; i < np; i++) {
747 alphahist->SetBinContent(i + 1, y[i]);
748 alphahist->SetBinError(i + 1, 0);
759 int np = betagraph->GetN();
761 double*
y = betagraph->GetY();
766 auto betahist = std::make_unique<TH1D>(name.c_str(),
"Beta Spectrum", np, 0, np);
767 for (
int i = 0; i < np; i++) {
768 betahist->SetBinContent(i + 1, y[i]);
769 betahist->SetBinError(i + 1, 0);
780 int np = gammagraph->GetN();
781 double*
y = gammagraph->GetY();
786 auto gammahist = std::make_unique<TH1D>(name.c_str(),
"Gamma Spectrum", np, 0, np);
787 for (
int i = 0; i < np; i++) {
788 gammahist->SetBinContent(i + 1, y[i]);
789 gammahist->SetBinError(i + 1, 0);
800 int np = neutrongraph->GetN();
801 double*
y = neutrongraph->GetY();
806 auto neutronhist = std::make_unique<TH1D>(name.c_str(),
"Neutron Spectrum", np, 0, np);
807 for (
int i = 0; i < np; i++) {
808 neutronhist->SetBinContent(i + 1, y[i]);
809 neutronhist->SetBinError(i + 1, 0);
820 TH1::AddDirectory(addStatus);
846 throw cet::exception(
"RadioGen") <<
"Ununderstood nuclide: " << nuclide <<
"\n";
849 double rtype = flat.fire();
855 int itry = 0; itry < 10;
879 if (itype >= 0)
break;
883 <<
"Normalization problem with nuclide: " << nuclide <<
"\n";
887 if (p >= 0) { p = TMath::Sqrt(p); }
900 int nbinsx = hist.GetNbinsX();
901 std::vector<double> partialsum;
902 partialsum.resize(nbinsx + 1);
905 for (
int i = 1; i <=
nbinsx; i++) {
906 double hc = hist.GetBinContent(i);
908 throw cet::exception(
"RadioGen") <<
"Negative bin: " << i <<
" " << hist.GetName() <<
"\n";
909 partialsum[i] = partialsum[i - 1] + hc;
911 double integral = partialsum[
nbinsx];
912 if (integral == 0)
return 0;
914 for (
int i = 1; i <=
nbinsx; i++)
915 partialsum[i] /= integral;
917 double r1 = flat.fire();
918 int ibin = TMath::BinarySearch(nbinsx, &(partialsum[0]), r1);
919 Double_t
x = hist.GetBinLowEdge(ibin + 1);
920 if (r1 > partialsum[ibin]) {
921 x += hist.GetBinWidth(ibin + 1) * (r1 - partialsum[ibin]) /
922 (partialsum[ibin + 1] - partialsum[ibin]);
938 std::vector<double> vd_p = {.0015246};
939 for (
auto p : vd_p) {
940 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
948 std::vector<double> vd_p = {.0003126};
949 for (
auto p : vd_p) {
950 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
960 double chan1 = (0.052 / (0.052 + 0.020));
961 if (flat.fire() < chan1) {
962 std::vector<double> vd_p = {.0008997};
963 for (
auto p : vd_p) {
964 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
969 std::vector<double> vd_p = {.0024243};
970 for (
auto p : vd_p) {
971 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
981 double chan1 = (0.0033 / (0.0033 + 0.0201 + 0.041));
982 double chan2 = (0.0201 / (0.0033 + 0.0201 + 0.041));
983 double chanPick = flat.fire();
984 if (chanPick < chan1) {
985 std::vector<double> vd_p = {0.000692, 0.001228};
986 for (
auto p : vd_p) {
987 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
991 else if (chanPick < (chan1 + chan2)) {
992 std::vector<double> vd_p = {0.0010212};
993 for (
auto p : vd_p) {
994 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
999 std::vector<double> vd_p = {0.0019208};
1000 for (
auto p : vd_p) {
1001 v_prods.emplace_back(pdgid, m,
dirCalc(p, m));
1029 template <
typename Stream>
1032 std::string
const& volumeName )
const 1035 out <<
"[#" << iNucl <<
"] " <<
fNuclide[iNucl] <<
" (" <<
fBq[iNucl] <<
" Bq/cm^3)" 1036 <<
" in " <<
fMaterial[iNucl] <<
" from " <<
fT0[iNucl] <<
" to " <<
fT1[iNucl]
1037 <<
" ns in ( " <<
fX0[iNucl] <<
", " <<
fY0[iNucl] <<
", " <<
fZ0[iNucl] <<
") to ( " 1038 <<
fX1[iNucl] <<
", " <<
fY1[iNucl] <<
", " <<
fZ1[iNucl] <<
")";
1039 if (!volumeName.empty()) out <<
" (\"" << volumeName <<
"\")";
1060 auto const trigTimeTick = timings.toTick<
electronics_tick>(timings.TriggerTime());
1064 return {double(timings.toTimeScale<
simulation_time>(trigTimeTick + beforeTicks)),
1065 double(timings.toTimeScale<
simulation_time>(trigTimeTick + afterTicks))};
code to link reconstructed objects back to the MC truth information
base_engine_t & createEngine(seed_t seed)
std::vector< std::unique_ptr< TH1D > > gammaspectrum
TLorentzVector dirCalc(double p, double m)
Utilities related to art service access.
timescale_traits< ElectronicsTimeCategory >::tick_t electronics_tick
A point on the electronics time scale expressed in its ticks.
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
std::vector< double > fZ0
Bottom corner z position (cm) in world coordinates.
void SetOrigin(simb::Origin_t origin)
Executes an operation on all the nodes of the ROOT geometry.
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: "39Ar".
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::pair< double, double > defaulttimewindow() const
Returns the start and end of the readout window.
bool apply(GeoNodePath &path, Op &&op) const
Applies the specified operation to all nodes under the path.
Class representing a path in ROOT geometry.
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
unsigned int ReadOutWindowSize() const
Class representing a path in ROOT geometry.
void Ar42Gamma5(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
void dumpNuclideSettings(Stream &&out, std::size_t iNucl, std::string const &volumeName={}) const
Prints the settings for the specified nuclide and volume.
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
std::vector< double > neutronintegral
std::vector< std::string > spectrumname
Interface to detinfo::DetectorClocks.
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Access the description of the physical detector geometry.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
std::vector< std::unique_ptr< TH1D > > alphaspectrum
std::vector< double > fT1
End of time window to simulate in ns.
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
std::vector< double > fY1
Top corner y position (cm) in world coordinates.
timescale_traits< ElectronicsTimeCategory >::tick_interval_t electronics_time_ticks
An interval on the electronics time scale expressed in its ticks.
#define DEFINE_ART_MODULE(klass)
Definitions of geometry vector data types.
timescale_traits< SimulationTimeCategory >::time_point_t simulation_time
A point in time on the simulation time scale.
std::vector< double > fZ1
Top corner z position (cm) in world coordinates.
single particles thrown at the detector
detinfo::DetectorTimings makeDetectorTimings(detinfo::DetectorClocksData const &detClocks)
int trackidcounter
Serial number for the MC track ID.
Utilities to extend the interface of geometry vectors.This library provides facilities that can be us...
void SampleOne(unsigned int i, simb::MCTruth &mct)
Checks that the node represents a box well aligned to world frame axes.
void Ar42Gamma3(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
unsigned int NumberTimeSamples() const
void readfile(std::string nuclide, std::string const &filename, std::string const &PathToFile)
Test of util::counter and support utilities.
void beginRun(art::Run &run)
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
Module to generate particles created by radiological decay, patterned off of SingleGen.
double samplefromth1d(TH1D &hist)
std::vector< double > alphaintegral
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
std::size_t addvolume(std::string const &volumeName)
void samplespectrum(std::string nuclide, int &itype, double &t, double &m, double &p)
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
std::vector< double > betaintegral
void Add(simb::MCParticle const &part)
void Ar42Gamma2(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
CLHEP::HepRandomEngine & fEngine
std::vector< double > fT0
Beginning of time window to simulate in ns.
Representation of a node and its ancestry.
void Ar42Gamma4(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
std::vector< std::unique_ptr< TH1D > > neutronspectrum
std::vector< std::string > fMaterial
List of regexes of materials in which to generate the decays. Example: "LAr".
std::string const & DetectorName() const
Returns a string with the name of the detector, as configured.
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.
Event generator information.
bool fIsFirstSignalSpecial
std::vector< double > gammaintegral
std::vector< double > fBq
Radioactivity in Becquerels (decay per sec) per cubic cm.
Event Generation using GENIE, cosmics or single particles.
Namespace including different time scales as defined in LArSoft.
std::vector< std::unique_ptr< TH1D > > betaspectrum
std::vector< double > fX1
Top corner x position (cm) in world coordinates.
art framework interface to geometry description
ROOT::Math::Transform3D TransformationMatrix
Type of transformation matrix used in geometry.
constexpr Point origin()
Returns a origin position with a point of the specified type.
cet::coded_exception< error, detail::translate > exception
std::vector< double > fY0
Bottom corner y position (cm) in world coordinates.
void produce(art::Event &evt)