All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
evgen::RadioGen Class Reference

Module to generate particles created by radiological decay, patterned off of SingleGen. More...

Inheritance diagram for evgen::RadioGen:

Public Member Functions

 RadioGen (fhicl::ParameterSet const &pset)
 

Private Types

typedef int ti_PDGID
 
typedef double td_Mass
 

Private Member Functions

void produce (art::Event &evt)
 
void beginRun (art::Run &run)
 
std::size_t addvolume (std::string const &volumeName)
 
void SampleOne (unsigned int i, simb::MCTruth &mct)
 Checks that the node represents a box well aligned to world frame axes. More...
 
TLorentzVector dirCalc (double p, double m)
 
void readfile (std::string nuclide, std::string const &filename)
 
void samplespectrum (std::string nuclide, int &itype, double &t, double &m, double &p)
 
void Ar42Gamma2 (std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
 
void Ar42Gamma3 (std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
 
void Ar42Gamma4 (std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
 
void Ar42Gamma5 (std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
 
double samplefromth1d (TH1D &hist)
 
template<typename Stream >
void dumpNuclideSettings (Stream &&out, std::size_t iNucl, std::string const &volumeName={}) const
 Prints the settings for the specified nuclide and volume. More...
 
std::pair< double, double > defaulttimewindow () const
 Returns the start and end of the readout window. More...
 

Private Attributes

std::vector< std::string > fNuclide
 List of nuclides to simulate. Example: "39Ar". More...
 
std::vector< std::string > fMaterial
 List of regexes of materials in which to generate the decays. Example: "LAr". More...
 
std::vector< double > fBq
 Radioactivity in Becquerels (decay per sec) per cubic cm. More...
 
std::vector< double > fT0
 Beginning of time window to simulate in ns. More...
 
std::vector< double > fT1
 End of time window to simulate in ns. More...
 
std::vector< double > fX0
 Bottom corner x position (cm) in world coordinates. More...
 
std::vector< double > fY0
 Bottom corner y position (cm) in world coordinates. More...
 
std::vector< double > fZ0
 Bottom corner z position (cm) in world coordinates. More...
 
std::vector< double > fX1
 Top corner x position (cm) in world coordinates. More...
 
std::vector< double > fY1
 Top corner y position (cm) in world coordinates. More...
 
std::vector< double > fZ1
 Top corner z position (cm) in world coordinates. More...
 
bool fIsFirstSignalSpecial
 
int trackidcounter
 Serial number for the MC track ID. More...
 
std::vector< std::string > spectrumname
 
std::vector< std::unique_ptr
< TH1D > > 
alphaspectrum
 
std::vector< double > alphaintegral
 
std::vector< std::unique_ptr
< TH1D > > 
betaspectrum
 
std::vector< double > betaintegral
 
std::vector< std::unique_ptr
< TH1D > > 
gammaspectrum
 
std::vector< double > gammaintegral
 
std::vector< std::unique_ptr
< TH1D > > 
neutronspectrum
 
std::vector< double > neutronintegral
 
CLHEP::HepRandomEngine & fEngine
 

Detailed Description

Module to generate particles created by radiological decay, patterned off of SingleGen.

The module generates the products of radioactive decay of some known nuclides. Each nuclide decay producing a single particle (with exceptions, as for example argon(A=42)), whose spectrum is specified in a ROOT file to be found in the FW_SEARCH_PATH path, and it can be a alpha, beta, gamma or neutron. In case multiple decay channels are possible, each decay is stochastically chosen weighting the channels according to the integral of their spectrum. The normalization of the spectrum is otherwise ignored.

Nuclides can be added by making the proper distributions available in a file called after the name used for it in the Nuclide configuration parameter (e.g 14C.root if the nuclide key is 14C): check the existing nuclide files for examples.

A special treatment is encoded for argon(A=42) and radon(A=222) (and, "temporary", for nichel(A=59) ).

Decays happen only in volumes specified in the configuration, and with a rate also specified in the configuration. Volumes are always box-shaped, and can be specified by coordinates or by name. In addition, within each volume decays will be generated only in the subvolumes matching the specified materials.

Note
All beta decays emit positrons.

Configuration parameters

Definition at line 188 of file RadioGen_module.cc.

Member Typedef Documentation

typedef double evgen::RadioGen::td_Mass
private

Definition at line 198 of file RadioGen_module.cc.

typedef int evgen::RadioGen::ti_PDGID
private

Definition at line 197 of file RadioGen_module.cc.

Constructor & Destructor Documentation

evgen::RadioGen::RadioGen ( fhicl::ParameterSet const &  pset)
explicit

Definition at line 283 of file RadioGen_module.cc.

284  : EDProducer{pset}
285  , fX0{pset.get< std::vector<double> >("X0", {})}
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.

Member Function Documentation

std::size_t evgen::RadioGen::addvolume ( std::string const &  volumeName)
private

Adds all volumes with the specified name to the coordinates. Volumes must be boxes aligned to the world frame axes.

Definition at line 434 of file RadioGen_module.cc.

434  {
435 
436  auto const& geom = *(lar::providerFrom<geo::Geometry>());
437 
438  std::vector<geo::GeoNodePath> volumePaths;
439  auto findVolume = [&volumePaths, volumeName](auto& path)
440  {
441  if (path.current().GetVolume()->GetName() == volumeName)
442  volumePaths.push_back(path);
443  return true;
444  };
445 
446  geo::ROOTGeometryNavigator navigator { *(geom.ROOTGeoManager()) };
447 
448  navigator.apply(findVolume);
449 
450  for (geo::GeoNodePath const& path: volumePaths) {
451 
452  //
453  // find the coordinates of the volume in local coordinates
454  //
455  TGeoShape const* pShape = path.current().GetVolume()->GetShape();
456  auto pBox = dynamic_cast<TGeoBBox const*>(pShape);
457  if (!pBox) {
458  throw cet::exception("RadioGen") << "Volume '"
459  << path.current().GetName() << "' is a " << pShape->IsA()->GetName()
460  << ", not a TGeoBBox.\n";
461  }
462 
463  geo::Point_t const origin
464  = geo::vect::makeFromCoords<geo::Point_t>(pBox->GetOrigin());
465  geo::Vector_t const diag
466  = { pBox->GetDX(), pBox->GetDY(), pBox->GetDZ() };
467 
468  //
469  // convert to world coordinates
470  //
471 
472  auto const trans
473  = path.currentTransformation<geo::TransformationMatrix>();
474 
475  geo::Point_t min, max;
476  trans.Transform(origin - diag, min);
477  trans.Transform(origin + diag, max);
478 
479  //
480  // add to the coordinates
481  //
482  fX0.push_back(std::min(min.X(), max.X()));
483  fY0.push_back(std::min(min.Y(), max.Y()));
484  fZ0.push_back(std::min(min.Z(), max.Z()));
485  fX1.push_back(std::max(min.X(), max.X()));
486  fY1.push_back(std::max(min.Y(), max.Y()));
487  fZ1.push_back(std::max(min.Z(), max.Z()));
488 
489  } // for
490 
491  return volumePaths.size();
492  } // RadioGen::addvolume()
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
bool apply(geo::GeoNodePath &path, Op &&op) const
Applies the specified operation to all nodes under the path.
std::vector< double > fZ0
Bottom corner z position (cm) in world coordinates.
Executes an operation on all the nodes of the ROOT geometry.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
std::vector< double > fY1
Top corner y position (cm) in world coordinates.
std::vector< double > fZ1
Top corner z position (cm) in world coordinates.
Representation of a node and its ancestry.
Definition: GeoNodePath.h:38
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
std::vector< double > fX1
Top corner x position (cm) in world coordinates.
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.
Definition: geo_vectors.h:227
std::vector< double > fY0
Bottom corner y position (cm) in world coordinates.
void evgen::RadioGen::Ar42Gamma2 ( std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &  v_prods)
private

Definition at line 875 of file RadioGen_module.cc.

876  {
877  ti_PDGID pdgid = 22; td_Mass m = 0.0; //we are writing gammas
878  std::vector<double> vd_p = {.0015246};//Momentum in GeV
879  for(auto p : vd_p){
880  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
881  }
882  }
TLorentzVector dirCalc(double p, double m)
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
void evgen::RadioGen::Ar42Gamma3 ( std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &  v_prods)
private

Definition at line 884 of file RadioGen_module.cc.

885  {
886  ti_PDGID pdgid = 22; td_Mass m = 0.0; //we are writing gammas
887  std::vector<double> vd_p = {.0003126};
888  for(auto p : vd_p){
889  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
890  }
891  Ar42Gamma2(v_prods);
892  }
TLorentzVector dirCalc(double p, double m)
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
void Ar42Gamma2(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
void evgen::RadioGen::Ar42Gamma4 ( std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &  v_prods)
private

Definition at line 894 of file RadioGen_module.cc.

895  {
896  CLHEP::RandFlat flat(fEngine);
897  ti_PDGID pdgid = 22; td_Mass m = 0.0; //we are writing gammas
898  double chan1 = (0.052 / (0.052+0.020) );
899  if(flat.fire()<chan1){
900  std::vector<double> vd_p = {.0008997};//Momentum in GeV
901  for(auto p : vd_p){
902  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
903  }
904  Ar42Gamma2(v_prods);
905  }else{
906  std::vector<double> vd_p = {.0024243};//Momentum in GeV
907  for(auto p : vd_p){
908  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
909  }
910  }
911  }
TLorentzVector dirCalc(double p, double m)
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
void Ar42Gamma2(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
CLHEP::HepRandomEngine & fEngine
void evgen::RadioGen::Ar42Gamma5 ( std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &  v_prods)
private

Definition at line 913 of file RadioGen_module.cc.

914  {
915  CLHEP::RandFlat flat(fEngine);
916  ti_PDGID pdgid = 22; td_Mass m = 0.0; //we are writing gammas
917  double chan1 = ( 0.0033 / (0.0033 + 0.0201 + 0.041) ); double chan2 = ( 0.0201 / (0.0033 + 0.0201 + 0.041) );
918  double chanPick = flat.fire();
919  if(chanPick < chan1){
920  std::vector<double> vd_p = {0.000692, 0.001228};//Momentum in GeV
921  for(auto p : vd_p){
922  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
923  }
924  Ar42Gamma2(v_prods);
925  }else if (chanPick<(chan1+chan2)){
926  std::vector<double> vd_p = {0.0010212};//Momentum in GeV
927  for(auto p : vd_p){
928  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
929  }
930  Ar42Gamma4(v_prods);
931  }else{
932  std::vector<double> vd_p = {0.0019208};//Momentum in GeV
933  for(auto p : vd_p){
934  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
935  }
936  Ar42Gamma2(v_prods);
937  }
938  }
TLorentzVector dirCalc(double p, double m)
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
void Ar42Gamma2(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
CLHEP::HepRandomEngine & fEngine
void Ar42Gamma4(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
void evgen::RadioGen::beginRun ( art::Run &  run)
private

Definition at line 408 of file RadioGen_module.cc.

409  {
410  art::ServiceHandle<geo::Geometry const> geo;
411  run.put(std::make_unique<sumdata::RunData>(geo->DetectorName()));
412  }
std::pair< double, double > evgen::RadioGen::defaulttimewindow ( ) const
private

Returns the start and end of the readout window.

Definition at line 982 of file RadioGen_module.cc.

982  {
983  // values are in simulation time scale (and therefore in [ns])
984  using namespace detinfo::timescales;
985 
986  auto const& timings = detinfo::makeDetectorTimings
987  (art::ServiceHandle<detinfo::DetectorClocksService>()->DataForJob());
988  detinfo::DetectorPropertiesData const& detInfo
989  = art::ServiceHandle<detinfo::DetectorPropertiesService>()->DataForJob();
990 
991  //
992  // we take a number of (TPC electronics) ticks before the trigger time,
993  // and we go to a number of ticks after the trigger time;
994  // that shift is one readout window size
995  //
996 
997  auto const trigTimeTick
998  = timings.toTick<electronics_tick>(timings.TriggerTime());
999  electronics_time_ticks const beforeTicks
1000  { -static_cast<int>(detInfo.ReadOutWindowSize()) };
1001  electronics_time_ticks const afterTicks { detInfo.NumberTimeSamples() };
1002 
1003  return {
1004  double(timings.toTimeScale<simulation_time>(trigTimeTick + beforeTicks)),
1005  double(timings.toTimeScale<simulation_time>(trigTimeTick + afterTicks))
1006  };
1007  } // RadioGen::defaulttimewindow()
timescale_traits< ElectronicsTimeCategory >::tick_t electronics_tick
A point on the electronics time scale expressed in its ticks.
timescale_traits< ElectronicsTimeCategory >::tick_interval_t electronics_time_ticks
An interval on the electronics time scale expressed in its ticks.
timescale_traits< SimulationTimeCategory >::time_point_t simulation_time
A point in time on the simulation time scale.
detinfo::DetectorTimings makeDetectorTimings(detinfo::DetectorClocksData const &detClocks)
TLorentzVector evgen::RadioGen::dirCalc ( double  p,
double  m 
)
private

Definition at line 609 of file RadioGen_module.cc.

610  {
611  CLHEP::RandFlat flat(fEngine);
612  // isotropic production angle for the decay product
613  double costheta = (2.0*flat.fire() - 1.0);
614  if (costheta < -1.0) costheta = -1.0;
615  if (costheta > 1.0) costheta = 1.0;
616  double const sintheta = sqrt(1.0-costheta*costheta);
617  double const phi = 2.0*M_PI*flat.fire();
618  return TLorentzVector{p*sintheta*std::cos(phi),
619  p*sintheta*std::sin(phi),
620  p*costheta,
621  std::sqrt(p*p+m*m)};
622  }
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
CLHEP::HepRandomEngine & fEngine
template<typename Stream >
void evgen::RadioGen::dumpNuclideSettings ( Stream &&  out,
std::size_t  iNucl,
std::string const &  volumeName = {} 
) const
private

Prints the settings for the specified nuclide and volume.

Definition at line 965 of file RadioGen_module.cc.

967  {
968 
969  out << "[#" << iNucl << "] "
970  << fNuclide[iNucl]
971  << " (" << fBq[iNucl] << " Bq/cm^3)"
972  << " in " << fMaterial[iNucl]
973  << " from " << fT0[iNucl] << " to " << fT1[iNucl] << " ns in ( "
974  << fX0[iNucl] << ", " << fY0[iNucl] << ", " << fZ0[iNucl] << ") to ( "
975  << fX1[iNucl] << ", " << fY1[iNucl] << ", " << fZ1[iNucl] << ")";
976  if (!volumeName.empty()) out << " (\"" << volumeName << "\")";
977 
978  } // RadioGen::dumpNuclideSettings()
std::vector< double > fZ0
Bottom corner z position (cm) in world coordinates.
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: &quot;39Ar&quot;.
std::vector< double > fT1
End of time window to simulate in ns.
std::vector< double > fY1
Top corner y position (cm) in world coordinates.
std::vector< double > fZ1
Top corner z position (cm) in world coordinates.
std::vector< double > fT0
Beginning of time window to simulate in ns.
std::vector< std::string > fMaterial
List of regexes of materials in which to generate the decays. Example: &quot;LAr&quot;.
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.
std::vector< double > fBq
Radioactivity in Becquerels (decay per sec) per cubic cm.
std::vector< double > fX1
Top corner x position (cm) in world coordinates.
std::vector< double > fY0
Bottom corner y position (cm) in world coordinates.
void evgen::RadioGen::produce ( art::Event &  evt)
private

unique_ptr allows ownership to be transferred to the art::Event after the put statement

Definition at line 415 of file RadioGen_module.cc.

416  {
417  ///unique_ptr allows ownership to be transferred to the art::Event after the put statement
418  std::unique_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
419 
420  simb::MCTruth truth;
421  truth.SetOrigin(simb::kSingleParticle);
422 
423  trackidcounter = -1;
424  for (unsigned int i=0; i<fNuclide.size(); ++i) {
425  SampleOne(i,truth);
426  }//end loop over nuclides
427 
428  MF_LOG_DEBUG("RadioGen") << truth;
429  truthcol->push_back(truth);
430  evt.put(std::move(truthcol));
431  }
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: &quot;39Ar&quot;.
int trackidcounter
Serial number for the MC track ID.
void SampleOne(unsigned int i, simb::MCTruth &mct)
Checks that the node represents a box well aligned to world frame axes.
TCEvent evt
Definition: DataStructs.cxx:8
void evgen::RadioGen::readfile ( std::string  nuclide,
std::string const &  filename 
)
private

Definition at line 626 of file RadioGen_module.cc.

627  {
628  bool found{false};
629  std::regex const re_argon{"42Ar.*"};
630  for (size_t i=0; i<fNuclide.size(); i++)
631  {
632  if (fNuclide[i] == nuclide){ //This check makes sure that the nuclide we are searching for is in fact in our fNuclide list. Ar42 handeled separately.
633  found = true;
634  break;
635  } //End If nuclide is in our list. Next is the special case of Ar42
636  else if (std::regex_match(nuclide, re_argon) && fNuclide[i]=="42Ar") {
637  found = true;
638  break;
639  }
640  }
641  if (!found) return;
642 
643  Bool_t addStatus = TH1::AddDirectoryStatus();
644  TH1::AddDirectory(kFALSE); // cloned histograms go in memory, and aren't deleted when files are closed.
645  // be sure to restore this state when we're out of the routine.
646 
647  spectrumname.push_back(nuclide);
648  cet::search_path sp("FW_SEARCH_PATH");
649  std::string fn2 = "Radionuclides/";
650  fn2 += filename;
651  std::string fullname;
652  sp.find_file(fn2, fullname);
653  struct stat sb;
654  if (fullname.empty() || stat(fullname.c_str(), &sb)!=0)
655  throw cet::exception("RadioGen") << "Input spectrum file "
656  << fn2
657  << " not found in FW_SEARCH_PATH!\n";
658 
659  TFile f(fullname.c_str(),"READ");
660  TGraph *alphagraph = (TGraph*) f.Get("Alphas");
661  TGraph *betagraph = (TGraph*) f.Get("Betas");
662  TGraph *gammagraph = (TGraph*) f.Get("Gammas");
663  TGraph *neutrongraph = (TGraph*) f.Get("Neutrons");
664 
665  if (alphagraph)
666  {
667  int np = alphagraph->GetN();
668  double *y = alphagraph->GetY();
669  std::string name;
670  name = "RadioGen_";
671  name += nuclide;
672  name += "_Alpha";
673  auto alphahist = std::make_unique<TH1D>(name.c_str(),"Alpha Spectrum",np,0,np);
674  for (int i=0; i<np; i++) {
675  alphahist->SetBinContent(i+1,y[i]);
676  alphahist->SetBinError(i+1,0);
677  }
678  alphaintegral.push_back(alphahist->Integral());
679  alphaspectrum.push_back(move(alphahist));
680  }
681  else
682  {
683  alphaintegral.push_back(0);
684  alphaspectrum.push_back(nullptr);
685  }
686 
687 
688  if (betagraph)
689  {
690  int np = betagraph->GetN();
691 
692  double *y = betagraph->GetY();
693  std::string name;
694  name = "RadioGen_";
695  name += nuclide;
696  name += "_Beta";
697  auto betahist = std::make_unique<TH1D>(name.c_str(),"Beta Spectrum",np,0,np);
698  for (int i=0; i<np; i++) {
699  betahist->SetBinContent(i+1,y[i]);
700  betahist->SetBinError(i+1,0);
701  }
702  betaintegral.push_back(betahist->Integral());
703  betaspectrum.push_back(move(betahist));
704  }
705  else
706  {
707  betaintegral.push_back(0);
708  betaspectrum.push_back(nullptr);
709  }
710 
711  if (gammagraph)
712  {
713  int np = gammagraph->GetN();
714  double *y = gammagraph->GetY();
715  std::string name;
716  name = "RadioGen_";
717  name += nuclide;
718  name += "_Gamma";
719  auto gammahist = std::make_unique<TH1D>(name.c_str(),"Gamma Spectrum",np,0,np);
720  for (int i=0; i<np; i++) {
721  gammahist->SetBinContent(i+1,y[i]);
722  gammahist->SetBinError(i+1,0);
723  }
724  gammaintegral.push_back(gammahist->Integral());
725  gammaspectrum.push_back(move(gammahist));
726  }
727  else
728  {
729  gammaintegral.push_back(0);
730  gammaspectrum.push_back(nullptr);
731  }
732 
733  if (neutrongraph)
734  {
735  int np = neutrongraph->GetN();
736  double *y = neutrongraph->GetY();
737  std::string name;
738  name = "RadioGen_";
739  name += nuclide;
740  name += "_Neutron";
741  auto neutronhist = std::make_unique<TH1D>(name.c_str(),"Neutron Spectrum",np,0,np);
742  for (int i=0; i<np; i++)
743  {
744  neutronhist->SetBinContent(i+1,y[i]);
745  neutronhist->SetBinError(i+1,0);
746  }
747  neutronintegral.push_back(neutronhist->Integral());
748  neutronspectrum.push_back(move(neutronhist));
749  }
750  else
751  {
752  neutronintegral.push_back(0);
753  neutronspectrum.push_back(nullptr);
754  }
755 
756  f.Close();
757  TH1::AddDirectory(addStatus);
758 
759  double total = alphaintegral.back() + betaintegral.back() + gammaintegral.back() + neutronintegral.back();
760  if (total>0)
761  {
762  alphaintegral.back() /= total;
763  betaintegral.back() /= total;
764  gammaintegral.back() /= total;
765  neutronintegral.back() /= total;
766  }
767  }
std::vector< std::unique_ptr< TH1D > > gammaspectrum
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: &quot;39Ar&quot;.
BEGIN_PROLOG could also be dds filename
std::vector< double > neutronintegral
std::vector< std::string > spectrumname
std::vector< std::unique_ptr< TH1D > > alphaspectrum
process_name opflash particleana ie ie y
std::vector< double > alphaintegral
std::vector< double > betaintegral
then echo fcl name
std::vector< std::unique_ptr< TH1D > > neutronspectrum
std::vector< double > gammaintegral
std::vector< std::unique_ptr< TH1D > > betaspectrum
double evgen::RadioGen::samplefromth1d ( TH1D &  hist)
private

Definition at line 838 of file RadioGen_module.cc.

839  {
840  CLHEP::RandFlat flat(fEngine);
841 
842  int nbinsx = hist.GetNbinsX();
843  std::vector<double> partialsum;
844  partialsum.resize(nbinsx+1);
845  partialsum[0] = 0;
846 
847  for (int i=1;i<=nbinsx;i++)
848  {
849  double hc = hist.GetBinContent(i);
850  if ( hc < 0) throw cet::exception("RadioGen") << "Negative bin: " << i << " " << hist.GetName() << "\n";
851  partialsum[i] = partialsum[i-1] + hc;
852  }
853  double integral = partialsum[nbinsx];
854  if (integral == 0) return 0;
855  // normalize to unit sum
856  for (int i=1;i<=nbinsx;i++) partialsum[i] /= integral;
857 
858  double r1 = flat.fire();
859  int ibin = TMath::BinarySearch(nbinsx,&(partialsum[0]),r1);
860  Double_t x = hist.GetBinLowEdge(ibin+1);
861  if (r1 > partialsum[ibin]) {
862  x += hist.GetBinWidth(ibin+1)*(r1-partialsum[ibin])/(partialsum[ibin+1] - partialsum[ibin]);
863  }
864  return x;
865  }
process_name opflash particleana ie x
CLHEP::HepRandomEngine & fEngine
void evgen::RadioGen::SampleOne ( unsigned int  i,
simb::MCTruth &  mct 
)
private

Checks that the node represents a box well aligned to world frame axes.

Definition at line 498 of file RadioGen_module.cc.

499  {
500  art::ServiceHandle<geo::Geometry const> geo;
501  TGeoManager *geomanager = geo->ROOTGeoManager();
502 
503  CLHEP::RandFlat flat(fEngine);
504  CLHEP::RandPoisson poisson(fEngine);
505 
506  // figure out how many decays to generate, assuming that the entire prism consists of the radioactive material.
507  // we will skip over decays in other materials later.
508 
509  double rate = fabs( fBq[i] * (fT1[i] - fT0[i]) * (fX1[i] - fX0[i]) * (fY1[i] - fY0[i]) * (fZ1[i] - fZ0[i]) ) / 1.0E9;
510  long ndecays = poisson.shoot(rate);
511 
512  std::regex const re_material{fMaterial[i]};
513  for (unsigned int idecay=0; idecay<ndecays; idecay++)
514  {
515  // generate just one particle at a time. Need a little recoding if a radioactive
516  // decay generates multiple daughters that need simulation
517  // uniformly distributed in position and time
518  //
519  // JStock: Leaving this as a single position for the decay products. For now I will assume they all come from the same spot.
520  TLorentzVector pos( fX0[i] + flat.fire()*(fX1[i] - fX0[i]),
521  fY0[i] + flat.fire()*(fY1[i] - fY0[i]),
522  fZ0[i] + flat.fire()*(fZ1[i] - fZ0[i]),
523  (idecay==0 && fIsFirstSignalSpecial) ? 0 : ( fT0[i] + flat.fire()*(fT1[i] - fT0[i]) ) );
524 
525  // discard decays that are not in the proper material
526  std::string volmaterial = geomanager->FindNode(pos.X(),pos.Y(),pos.Z())->GetMedium()->GetMaterial()->GetName();
527  if (!std::regex_match(volmaterial, re_material)) continue;
528 
529  //Moved pdgid into the next statement, so that it is localized.
530  // electron=11, photon=22, alpha = 1000020040, neutron = 2112
531 
532  //JStock: Allow us to have different particles from the same decay. This requires multiple momenta.
533  std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>> v_prods; //(First is for PDGID, second is mass, third is Momentum)
534 
535  if (fNuclide[i] == "222Rn") // Treat 222Rn separately
536  {
537  double p=0; double t=0.00548952; td_Mass m=m_alpha; ti_PDGID pdgid=1000020040; //td_Mass = double. ti_PDGID = int;
538  double energy = t + m;
539  double p2 = energy*energy - m*m;
540  if (p2 > 0) p = TMath::Sqrt(p2);
541  else p = 0;
542  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
543  }//End special case RN222
544  else if(fNuclide[i] == "59Ni"){ //Treat 59Ni Calibration Source separately (as I haven't made a spectrum for it, and ultimately it should be handeled with multiple particle outputs.
545  double p=0.008997; td_Mass m=0; ti_PDGID pdgid=22; // td_Mas=double. ti_PDFID=int. Assigning p directly, as t=p for gammas.
546  v_prods.emplace_back(pdgid, m, dirCalc(p,m));
547  }//end special case Ni59 calibration source
548  else if(fNuclide[i] == "42Ar"){ // Spot for special treatment of Ar42.
549  double p=0; double t=0; td_Mass m = 0; ti_PDGID pdgid=0; //td_Mass = double. ti_PDGID = int;
550  double bSelect = flat.fire(); //Make this a random number from 0 to 1.
551  if(bSelect<0.819){ //beta channel 1. No Gamma. beta Q value 3525.22 keV
552  samplespectrum("42Ar_1", pdgid, t, m, p);
553  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
554  //No gamma here.
555  }else if(bSelect<0.9954){ //beta channel 2. 1 Gamma (1524.6 keV). beta Q value 2000.62
556  samplespectrum("42Ar_2", pdgid, t, m, p);
557  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
558  Ar42Gamma2(v_prods);
559  }else if(bSelect<0.9988){ //beta channel 3. 1 Gamma Channel. 312.6 keV + gamma 2. beta Q value 1688.02 keV
560  samplespectrum("42Ar_3", pdgid, t, m, p);
561  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
562  Ar42Gamma3(v_prods);
563  }else if(bSelect<0.9993){ //beta channel 4. 2 Gamma Channels. Either 899.7 keV (i 0.052) + gamma 2 or 2424.3 keV (i 0.020). beta Q value 1100.92 keV
564  samplespectrum("42Ar_4", pdgid, t, m, p);
565  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
566  Ar42Gamma4(v_prods);
567  }else{ //beta channel 5. 3 gamma channels. 692.0 keV + 1228.0 keV + Gamma 2 (i 0.0033) ||OR|| 1021.2 keV + gamma 4 (i 0.0201) ||OR|| 1920.8 keV + gamma 2 (i 0.041). beta Q value 79.82 keV
568  samplespectrum("42Ar_5", pdgid, t, m, p);
569  v_prods.emplace_back(pdgid, m, dirCalc(p, m));
570  Ar42Gamma5(v_prods);
571  }
572  //Add beta.
573  //Call gamma function for beta mode.
574  }
575  else{ //General Case.
576  double p=0; double t=0; td_Mass m = 0; ti_PDGID pdgid=0; //td_Mass = double. ti_PDGID = int;
577  samplespectrum(fNuclide[i],pdgid,t,m,p);
578  std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
579  v_prods.push_back(partMassMom);
580  }//end else (not RN or other special case
581 
582  //JStock: Modify this to now loop over the v_prods.
583  for(auto prodEntry : v_prods){
584  // set track id to a negative serial number as these are all primary particles and have id <= 0
585  int trackid = trackidcounter;
586  ti_PDGID pdgid = std::get<0>(prodEntry);
587  td_Mass m = std::get<1>(prodEntry);
588  TLorentzVector pvec = std::get<2>(prodEntry);
589  trackidcounter--;
590  std::string primary("primary");
591 
592  // alpha particles need a little help since they're not in the TDatabasePDG table
593  // // so don't rely so heavily on default arguments to the MCParticle constructor
594  if (pdgid == 1000020040){
595  simb::MCParticle part(trackid, pdgid, primary,-1,m,1);
596  part.AddTrajectoryPoint(pos, pvec);
597  mct.Add(part);
598  }// end "If alpha"
599  else{
600  simb::MCParticle part(trackid, pdgid, primary);
601  part.AddTrajectoryPoint(pos, pvec);
602  mct.Add(part);
603  }// end All standard cases.
604  }//End Loop over all particles produces in this single decay.
605  }
606  }
TLorentzVector dirCalc(double p, double m)
std::vector< double > fZ0
Bottom corner z position (cm) in world coordinates.
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: &quot;39Ar&quot;.
pdgs p
Definition: selectors.fcl:22
void Ar42Gamma5(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
std::vector< double > fT1
End of time window to simulate in ns.
std::vector< double > fY1
Top corner y position (cm) in world coordinates.
std::vector< double > fZ1
Top corner z position (cm) in world coordinates.
int trackidcounter
Serial number for the MC track ID.
void Ar42Gamma3(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
void samplespectrum(std::string nuclide, int &itype, double &t, double &m, double &p)
void Ar42Gamma2(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
Var Sqrt(const Var &v)
Use to take sqrt of a var.
Definition: Var.cxx:172
CLHEP::HepRandomEngine & fEngine
std::vector< double > fT0
Beginning of time window to simulate in ns.
void Ar42Gamma4(std::vector< std::tuple< ti_PDGID, td_Mass, TLorentzVector >> &v_prods)
std::vector< std::string > fMaterial
List of regexes of materials in which to generate the decays. Example: &quot;LAr&quot;.
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.
std::vector< double > fBq
Radioactivity in Becquerels (decay per sec) per cubic cm.
std::vector< double > fX1
Top corner x position (cm) in world coordinates.
std::vector< double > fY0
Bottom corner y position (cm) in world coordinates.
void evgen::RadioGen::samplespectrum ( std::string  nuclide,
int &  itype,
double &  t,
double &  m,
double &  p 
)
private

Definition at line 770 of file RadioGen_module.cc.

771  {
772  CLHEP::RandFlat flat(fEngine);
773 
774  int inuc = -1;
775  for (size_t i=0; i<spectrumname.size(); i++)
776  {
777  if (nuclide == spectrumname[i])
778  {
779  inuc = i;
780  break;
781  }
782  }
783  if (inuc == -1)
784  {
785  t=0; // throw an exception in the future
786  itype = 0;
787  throw cet::exception("RadioGen") << "Ununderstood nuclide: " << nuclide << "\n";
788  }
789 
790  double rtype = flat.fire();
791 
792  itype = -1;
793  m = 0;
794  p = 0;
795  for (int itry=0;itry<10;itry++) // maybe a tiny normalization issue with a sum of 0.99999999999 or something, so try a few times.
796  {
797  if (rtype <= alphaintegral[inuc] && alphaspectrum[inuc] != nullptr)
798  {
799  itype = 1000020040; // alpha
800  m = m_alpha;
801  t = samplefromth1d(*alphaspectrum[inuc])/1000000.0;
802  }
803  else if (rtype <= alphaintegral[inuc]+betaintegral[inuc] && betaspectrum[inuc] != nullptr)
804  {
805  itype = 11; // beta
806  m = m_e;
807  t = samplefromth1d(*betaspectrum[inuc])/1000000.0;
808  }
809  else if ( rtype <= alphaintegral[inuc] + betaintegral[inuc] + gammaintegral[inuc] && gammaspectrum[inuc] != nullptr)
810  {
811  itype = 22; // gamma
812  m = 0;
813  t = samplefromth1d(*gammaspectrum[inuc])/1000000.0;
814  }
815  else if( neutronspectrum[inuc] != nullptr)
816  {
817  itype = 2112;
818  m = m_neutron;
819  t = samplefromth1d(*neutronspectrum[inuc])/1000000.0;
820  }
821  if (itype >= 0) break;
822  }
823  if (itype == -1)
824  {
825  throw cet::exception("RadioGen") << "Normalization problem with nuclide: " << nuclide << "\n";
826  }
827  double e = t + m;
828  p = e*e - m*m;
829  if (p>=0)
830  { p = TMath::Sqrt(p); }
831  else
832  { p=0; }
833  }
std::vector< std::unique_ptr< TH1D > > gammaspectrum
pdgs p
Definition: selectors.fcl:22
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
std::vector< std::string > spectrumname
std::vector< std::unique_ptr< TH1D > > alphaspectrum
double samplefromth1d(TH1D &hist)
std::vector< double > alphaintegral
std::vector< double > betaintegral
Var Sqrt(const Var &v)
Use to take sqrt of a var.
Definition: Var.cxx:172
CLHEP::HepRandomEngine & fEngine
do i e
std::vector< std::unique_ptr< TH1D > > neutronspectrum
std::vector< double > gammaintegral
std::vector< std::unique_ptr< TH1D > > betaspectrum

Member Data Documentation

std::vector<double> evgen::RadioGen::alphaintegral
private

Definition at line 262 of file RadioGen_module.cc.

std::vector<std::unique_ptr<TH1D> > evgen::RadioGen::alphaspectrum
private

Definition at line 261 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::betaintegral
private

Definition at line 264 of file RadioGen_module.cc.

std::vector<std::unique_ptr<TH1D> > evgen::RadioGen::betaspectrum
private

Definition at line 263 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fBq
private

Radioactivity in Becquerels (decay per sec) per cubic cm.

Definition at line 243 of file RadioGen_module.cc.

CLHEP::HepRandomEngine& evgen::RadioGen::fEngine
private

Definition at line 269 of file RadioGen_module.cc.

bool evgen::RadioGen::fIsFirstSignalSpecial
private

Definition at line 252 of file RadioGen_module.cc.

std::vector<std::string> evgen::RadioGen::fMaterial
private

List of regexes of materials in which to generate the decays. Example: "LAr".

Definition at line 242 of file RadioGen_module.cc.

std::vector<std::string> evgen::RadioGen::fNuclide
private

List of nuclides to simulate. Example: "39Ar".

Definition at line 241 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fT0
private

Beginning of time window to simulate in ns.

Definition at line 244 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fT1
private

End of time window to simulate in ns.

Definition at line 245 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fX0
private

Bottom corner x position (cm) in world coordinates.

Definition at line 246 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fX1
private

Top corner x position (cm) in world coordinates.

Definition at line 249 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fY0
private

Bottom corner y position (cm) in world coordinates.

Definition at line 247 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fY1
private

Top corner y position (cm) in world coordinates.

Definition at line 250 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fZ0
private

Bottom corner z position (cm) in world coordinates.

Definition at line 248 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::fZ1
private

Top corner z position (cm) in world coordinates.

Definition at line 251 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::gammaintegral
private

Definition at line 266 of file RadioGen_module.cc.

std::vector<std::unique_ptr<TH1D> > evgen::RadioGen::gammaspectrum
private

Definition at line 265 of file RadioGen_module.cc.

std::vector<double> evgen::RadioGen::neutronintegral
private

Definition at line 268 of file RadioGen_module.cc.

std::vector<std::unique_ptr<TH1D> > evgen::RadioGen::neutronspectrum
private

Definition at line 267 of file RadioGen_module.cc.

std::vector<std::string> evgen::RadioGen::spectrumname
private

Definition at line 260 of file RadioGen_module.cc.

int evgen::RadioGen::trackidcounter
private

Serial number for the MC track ID.

Definition at line 253 of file RadioGen_module.cc.


The documentation for this class was generated from the following file: