31 #ifndef EVGEN_RADIOLOGICAL 32 #define EVGEN_RADIOLOGICAL 44 #include <TGeoManager.h> 45 #include <TGeoMaterial.h> 59 #include "cetlib_except/exception.h" 60 #include "cetlib/search_path.h" 76 #include "TLorentzVector.h" 78 #include "TGenPhaseSpace.h" 85 #include "CLHEP/Random/RandFlat.h" 86 #include "CLHEP/Random/RandPoisson.h" 88 namespace simb {
class MCTruth; }
113 void SampleOne(
unsigned int i,
116 TLorentzVector dirCalc(
double p,
double m);
118 void readfile(std::string nuclide, std::string filename);
119 void samplespectrum(std::string nuclide,
int &itype,
double &t,
double &m,
double &p);
121 void Ar42Gamma2(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
122 void Ar42Gamma3(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
123 void Ar42Gamma4(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
124 void Ar42Gamma5(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods);
127 double samplefromth1d(TH1D *
hist);
157 const double m_e = 0.000510998928;
158 const double m_alpha = 3.727379240;
159 const double m_neutron = 0.9395654133;
180 this->reconfigure(pset);
185 ->createEngine(*
this, pset,
"Seed");
187 produces< std::vector<simb::MCTruth> >();
188 produces< sumdata::RunData, art::InRun >();
193 RadioGen::~RadioGen()
203 fNuclide = p.
get< std::vector<std::string>>(
"Nuclide");
204 fMaterial = p.
get< std::vector<std::string>>(
"Material");
205 fBq = p.
get< std::vector<double> >(
"BqPercc");
206 fT0 = p.
get< std::vector<double> >(
"T0");
207 fT1 = p.
get< std::vector<double> >(
"T1");
208 fX0 = p.
get< std::vector<double> >(
"X0");
209 fY0 = p.
get< std::vector<double> >(
"Y0");
210 fZ0 = p.
get< std::vector<double> >(
"Z0");
211 fX1 = p.
get< std::vector<double> >(
"X1");
212 fY1 = p.
get< std::vector<double> >(
"Y1");
213 fZ1 = p.
get< std::vector<double> >(
"Z1");
217 unsigned int nsize = fNuclide.size();
218 if ( fMaterial.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Material vector and Nuclide vector\n";
219 if ( fBq.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Bq vector and Nuclide vector\n";
220 if ( fT0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size T0 vector and Nuclide vector\n";
221 if ( fT1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size T1 vector and Nuclide vector\n";
222 if ( fX0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size X0 vector and Nuclide vector\n";
223 if ( fY0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Y0 vector and Nuclide vector\n";
224 if ( fZ0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Z0 vector and Nuclide vector\n";
225 if ( fX1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size X1 vector and Nuclide vector\n";
226 if ( fY1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Y1 vector and Nuclide vector\n";
227 if ( fZ1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Z1 vector and Nuclide vector\n";
229 for(std::string & nuclideName : fNuclide){
230 if(nuclideName==
"39Ar" ){readfile(
"39Ar",
"Argon_39.root") ;}
231 else if(nuclideName==
"60Co" ){readfile(
"60Co",
"Cobalt_60.root") ;}
232 else if(nuclideName==
"85Kr" ){readfile(
"85Kr",
"Krypton_85.root") ;}
233 else if(nuclideName==
"40K" ){readfile(
"40K",
"Potassium_40.root") ;}
234 else if(nuclideName==
"232Th"){readfile(
"232Th",
"Thorium_232.root");}
235 else if(nuclideName==
"238U" ){readfile(
"238U",
"Uranium_238.root") ;}
236 else if(nuclideName==
"222Rn"){
continue;}
237 else if(nuclideName==
"59Ni"){
continue;}
238 else if(nuclideName==
"42Ar" ){
239 readfile(
"42Ar_1",
"Argon_42_1.root");
240 readfile(
"42Ar_2",
"Argon_42_2.root");
241 readfile(
"42Ar_3",
"Argon_42_3.root");
242 readfile(
"42Ar_4",
"Argon_42_4.root");
243 readfile(
"42Ar_5",
"Argon_42_5.root");
247 std::string searchName = nuclideName;
249 readfile(nuclideName,searchName);
264 run.
put(std::move(runcol));
274 std::unique_ptr< std::vector<simb::MCTruth> > truthcol(
new std::vector<simb::MCTruth>);
280 for (
unsigned int i=0; i<fNuclide.size(); ++i) {
285 truthcol->push_back(truth);
286 evt.
put(std::move(truthcol));
300 CLHEP::HepRandomEngine &engine = rng->
getEngine();
301 CLHEP::RandFlat flat(engine);
302 CLHEP::RandPoisson poisson(engine);
307 double rate = fabs( fBq[i] * (fT1[i] - fT0[i]) * (fX1[i] - fX0[i]) * (fY1[i] - fY0[i]) * (fZ1[i] - fZ0[i]) ) / 1.0E9;
308 long ndecays = poisson.shoot(rate);
310 for (
unsigned int idecay=0; idecay<ndecays; idecay++)
317 TLorentzVector pos( fX0[i] + flat.fire()*(fX1[i] - fX0[i]),
318 fY0[i] + flat.fire()*(fY1[i] - fY0[i]),
319 fZ0[i] + flat.fire()*(fZ1[i] - fZ0[i]),
320 fT0[i] + flat.fire()*(fT1[i] - fT0[i]) );
323 std::string volmaterial = geomanager->FindNode(pos.X(),pos.Y(),pos.Z())->GetMedium()->GetMaterial()->GetName();
325 if ( ! std::regex_match(volmaterial, std::regex(fMaterial[i])) )
continue;
332 std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>> v_prods;
334 if (fNuclide[i] ==
"222Rn")
336 double p=0;
double t=0.00548952;
td_Mass m=m_alpha;
ti_PDGID pdgid=1000020040;
338 double p2 = energy*energy - m*m;
339 if (p2 > 0) p = TMath::Sqrt(p2);
342 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
343 v_prods.push_back(partMassMom);
345 else if(fNuclide[i] ==
"59Ni"){
347 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
348 v_prods.push_back(partMassMom);
350 else if(fNuclide[i] ==
"42Ar"){
352 double bSelect = flat.fire();
354 samplespectrum(
"42Ar_1", pdgid, t, m, p);
355 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
356 v_prods.push_back(partMassMom);
358 }
else if(bSelect<0.9954){
359 samplespectrum(
"42Ar_2", pdgid, t, m, p);
360 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
361 v_prods.push_back(partMassMom);
363 }
else if(bSelect<0.9988){
364 samplespectrum(
"42Ar_3", pdgid, t, m, p);
365 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
366 v_prods.push_back(partMassMom);
368 }
else if(bSelect<0.9993){
369 samplespectrum(
"42Ar_4", pdgid, t, m, p);
370 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
371 v_prods.push_back(partMassMom);
374 samplespectrum(
"42Ar_5", pdgid, t, m, p);
375 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
376 v_prods.push_back(partMassMom);
384 samplespectrum(fNuclide[i],pdgid,t,m,p);
385 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
386 v_prods.push_back(partMassMom);
390 for(
auto prodEntry : v_prods){
392 int trackid = trackidcounter;
393 ti_PDGID pdgid = std::get<0>(prodEntry);
394 td_Mass m = std::get<1>(prodEntry);
395 TLorentzVector pvec = std::get<2>(prodEntry);
397 std::string primary(
"primary");
401 if (pdgid == 1000020040){
416 TLorentzVector RadioGen::dirCalc(
double p,
double m){
418 CLHEP::HepRandomEngine &engine = rng->
getEngine();
419 CLHEP::RandFlat flat(engine);
421 double costheta = (2.0*flat.fire() - 1.0);
422 if (costheta < -1.0) costheta = -1.0;
423 if (costheta > 1.0) costheta = 1.0;
424 double sintheta = sqrt(1.0-costheta*costheta);
425 double phi = 2.0*M_PI*flat.fire();
426 TLorentzVector pvec(p*sintheta*std::cos(phi),
427 p*sintheta*std::sin(phi),
436 void RadioGen::readfile(std::string nuclide, std::string filename)
439 for (
size_t i=0; i<fNuclide.size(); i++)
441 if (fNuclide[i] == nuclide){
445 else if ( (std::regex_match(nuclide, std::regex(
"42Ar.*" )) ) && fNuclide[i]==
"42Ar" ){
450 if (ifound == 0)
return;
452 Bool_t addStatus = TH1::AddDirectoryStatus();
453 TH1::AddDirectory(kFALSE);
457 spectrumname.push_back(nuclide);
458 cet::search_path sp(
"FW_SEARCH_PATH");
459 std::string fn2 =
"Radionuclides/";
461 std::string fullname;
462 sp.find_file(fn2, fullname);
464 if (fullname.empty() || stat(fullname.c_str(), &sb)!=0)
467 <<
" not found in FW_SEARCH_PATH!\n";
469 TFile
f(fullname.c_str(),
"READ");
470 TGraph *alphagraph = (TGraph*)
f.Get(
"Alphas");
471 TGraph *betagraph = (TGraph*)
f.Get(
"Betas");
472 TGraph *gammagraph = (TGraph*)
f.Get(
"Gammas");
473 TGraph *neutrongraph = (TGraph*)
f.Get(
"Neutrons");
477 int np = alphagraph->GetN();
478 double *
y = alphagraph->GetY();
483 TH1D *alphahist = (TH1D*)
new TH1D(name.c_str(),
"Alpha Spectrum",np,0,np);
484 for (
int i=0; i<np; i++)
486 alphahist->SetBinContent(i+1,y[i]);
487 alphahist->SetBinError(i+1,0);
489 alphaspectrum.push_back(alphahist);
490 alphaintegral.push_back(alphahist->Integral());
494 alphaspectrum.push_back(0);
495 alphaintegral.push_back(0);
501 int np = betagraph->GetN();
503 double *
y = betagraph->GetY();
508 TH1D *betahist = (TH1D*)
new TH1D(name.c_str(),
"Beta Spectrum",np,0,np);
510 for (
int i=0; i<np; i++)
512 betahist->SetBinContent(i+1,y[i]);
513 betahist->SetBinError(i+1,0);
515 betaspectrum.push_back(betahist);
516 betaintegral.push_back(betahist->Integral());
520 betaspectrum.push_back(0);
521 betaintegral.push_back(0);
526 int np = gammagraph->GetN();
527 double *
y = gammagraph->GetY();
532 TH1D *gammahist = (TH1D*)
new TH1D(name.c_str(),
"Gamma Spectrum",np,0,np);
533 for (
int i=0; i<np; i++)
535 gammahist->SetBinContent(i+1,y[i]);
536 gammahist->SetBinError(i+1,0);
538 gammaspectrum.push_back(gammahist);
539 gammaintegral.push_back(gammahist->Integral());
543 gammaspectrum.push_back(0);
544 gammaintegral.push_back(0);
549 int np = neutrongraph->GetN();
550 double *
y = neutrongraph->GetY();
555 TH1D *neutronhist = (TH1D*)
new TH1D(name.c_str(),
"Neutron Spectrum",np,0,np);
556 for (
int i=0; i<np; i++)
558 neutronhist->SetBinContent(i+1,y[i]);
559 neutronhist->SetBinError(i+1,0);
561 neutronspectrum.push_back(neutronhist);
562 neutronintegral.push_back(neutronhist->Integral());
566 neutronspectrum.push_back(0);
567 neutronintegral.push_back(0);
571 TH1::AddDirectory(addStatus);
573 double total = alphaintegral.back() + betaintegral.back() + gammaintegral.back() + neutronintegral.back();
576 alphaintegral.back() /= total;
577 betaintegral.back() /= total;
578 gammaintegral.back() /= total;
579 neutronintegral.back() /= total;
584 void RadioGen::samplespectrum(std::string nuclide,
int &itype,
double &t,
double &m,
double &p)
588 CLHEP::HepRandomEngine &engine = rng->
getEngine();
589 CLHEP::RandFlat flat(engine);
592 for (
size_t i=0; i<spectrumname.size(); i++)
594 if (nuclide == spectrumname[i])
604 throw cet::exception(
"RadioGen") <<
"Ununderstood nuclide: " << nuclide <<
"\n";
607 double rtype = flat.fire();
612 for (
int itry=0;itry<10;itry++)
614 if (rtype <= alphaintegral[inuc] && alphaspectrum[inuc] != 0)
618 t = samplefromth1d(alphaspectrum[inuc])/1000000.0;
620 else if (rtype <= alphaintegral[inuc]+betaintegral[inuc] && betaspectrum[inuc] != 0)
624 t = samplefromth1d(betaspectrum[inuc])/1000000.0;
626 else if ( rtype <= alphaintegral[inuc] + betaintegral[inuc] + gammaintegral[inuc] && gammaspectrum[inuc] != 0)
630 t = samplefromth1d(gammaspectrum[inuc])/1000000.0;
632 else if( neutronspectrum[inuc] != 0)
636 t = samplefromth1d(neutronspectrum[inuc])/1000000.0;
638 if (itype >= 0)
break;
642 throw cet::exception(
"RadioGen") <<
"Normalization problem with nuclide: " << nuclide <<
"\n";
647 { p = TMath::Sqrt(p); }
655 double RadioGen::samplefromth1d(TH1D *
hist)
658 CLHEP::HepRandomEngine &engine = rng->
getEngine();
659 CLHEP::RandFlat flat(engine);
661 int nbinsx = hist->GetNbinsX();
662 std::vector<double> partialsum;
663 partialsum.resize(nbinsx+1);
666 for (
int i=1;i<=nbinsx;i++)
668 double hc = hist->GetBinContent(i);
669 if ( hc < 0)
throw cet::exception(
"RadioGen") <<
"Negative bin: " << i <<
" " << hist->GetName() <<
"\n";
670 partialsum[i] = partialsum[i-1] + hc;
672 double integral = partialsum[nbinsx];
673 if (integral == 0)
return 0;
675 for (
int i=1;i<=nbinsx;i++) partialsum[i] /= integral;
677 double r1 = flat.fire();
678 int ibin = TMath::BinarySearch(nbinsx,&(partialsum[0]),r1);
679 Double_t
x = hist->GetBinLowEdge(ibin+1);
680 if (r1 > partialsum[ibin]) x +=
681 hist->GetBinWidth(ibin+1)*(r1-partialsum[ibin])/(partialsum[ibin+1] - partialsum[ibin]);
692 void RadioGen::Ar42Gamma2(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
694 std::vector<double> vd_p = {.0015246};
696 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
697 v_prods.push_back(prods);
700 void RadioGen::Ar42Gamma3(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
702 std::vector<double> vd_p = {.0003126};
704 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
705 v_prods.push_back(prods);
709 void RadioGen::Ar42Gamma4(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
711 CLHEP::HepRandomEngine &engine = rng->
getEngine();
712 CLHEP::RandFlat flat(engine);
714 double chan1 = (0.052 / (0.052+0.020) );
715 if(flat.fire()<chan1){
716 std::vector<double> vd_p = {.0008997};
718 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
719 v_prods.push_back(prods);
723 std::vector<double> vd_p = {.0024243};
725 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
726 v_prods.push_back(prods);
730 void RadioGen::Ar42Gamma5(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
732 CLHEP::HepRandomEngine &engine = rng->
getEngine();
733 CLHEP::RandFlat flat(engine);
735 double chan1 = ( 0.0033 / (0.0033 + 0.0201 + 0.041) );
double chan2 = ( 0.0201 / (0.0033 + 0.0201 + 0.041) );
736 double chanPick = flat.fire();
737 if(chanPick < chan1){
738 std::vector<double> vd_p = {0.000692, 0.001228};
740 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
741 v_prods.push_back(prods);
744 }
else if (chanPick<(chan1+chan2)){
745 std::vector<double> vd_p = {0.0010212};
747 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
748 v_prods.push_back(prods);
752 std::vector<double> vd_p = {0.0019208};
754 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
755 v_prods.push_back(prods);
796
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
std::vector< double > fZ0
Bottom corner z position (cm) in world coordinates.
void SetOrigin(simb::Origin_t origin)
std::vector< std::string > fNuclide
List of nuclides to simulate. Example: "39Ar".
art::ProductID put(std::unique_ptr< PROD > &&)
std::vector< TH1D * > alphaspectrum
void Add(simb::MCParticle &part)
TGeoManager * ROOTGeoManager() const
Access to the ROOT geometry description manager.
std::vector< double > neutronintegral
std::vector< std::string > spectrumname
std::vector< TH1D * > neutronspectrum
ProductID put(std::unique_ptr< PROD > &&product)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
std::vector< TH1D * > betaspectrum
base_engine_t & getEngine() const
std::vector< double > fT1
End of time window to simulate in ns.
std::vector< double > fY1
Top corner y position (cm) in world coordinates.
#define DEFINE_ART_MODULE(klass)
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
std::vector< double > fZ1
Top corner z position (cm) in world coordinates.
single particles thrown at the detector
T get(std::string const &key) const
int trackidcounter
Serial number for the MC track ID.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
std::vector< double > alphaintegral
std::vector< double > betaintegral
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: "LAr".
std::vector< double > fX0
Bottom corner x position (cm) in world coordinates.
Event generator information.
std::vector< double > gammaintegral
std::vector< double > fBq
Radioactivity in Becquerels (decay per sec) per cubic cm.
Namespace collecting geometry-related classes utilities.
Event Generation using GENIE, cosmics or single particles.
std::vector< double > fX1
Top corner x position (cm) in world coordinates.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
std::vector< TH1D * > gammaspectrum
std::vector< double > fY0
Bottom corner y position (cm) in world coordinates.