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);
158 const double m_e = 0.000510998928;
159 const double m_alpha = 3.727379240;
160 const double m_neutron = 0.9395654133;
181 this->reconfigure(pset);
186 ->createEngine(*
this, pset,
"Seed");
188 produces< std::vector<simb::MCTruth> >();
189 produces< sumdata::RunData, art::InRun >();
194 RadioGen::~RadioGen()
204 fNuclide = p.
get< std::vector<std::string>>(
"Nuclide");
205 fMaterial = p.
get< std::vector<std::string>>(
"Material");
206 fBq = p.
get< std::vector<double> >(
"BqPercc");
207 fT0 = p.
get< std::vector<double> >(
"T0");
208 fT1 = p.
get< std::vector<double> >(
"T1");
209 fX0 = p.
get< std::vector<double> >(
"X0");
210 fY0 = p.
get< std::vector<double> >(
"Y0");
211 fZ0 = p.
get< std::vector<double> >(
"Z0");
212 fX1 = p.
get< std::vector<double> >(
"X1");
213 fY1 = p.
get< std::vector<double> >(
"Y1");
214 fZ1 = p.
get< std::vector<double> >(
"Z1");
215 fIsFirstSignalSpecial = p.
get<
bool >(
"IsFirstSignalSpecial",
false);
219 unsigned int nsize = fNuclide.size();
220 if ( fMaterial.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Material vector and Nuclide vector\n";
221 if ( fBq.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Bq vector and Nuclide vector\n";
222 if ( fT0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size T0 vector and Nuclide vector\n";
223 if ( fT1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size T1 vector and Nuclide vector\n";
224 if ( fX0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size X0 vector and Nuclide vector\n";
225 if ( fY0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Y0 vector and Nuclide vector\n";
226 if ( fZ0.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Z0 vector and Nuclide vector\n";
227 if ( fX1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size X1 vector and Nuclide vector\n";
228 if ( fY1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Y1 vector and Nuclide vector\n";
229 if ( fZ1.size() != nsize )
throw cet::exception(
"RadioGen") <<
"Different size Z1 vector and Nuclide vector\n";
231 for(std::string & nuclideName : fNuclide){
232 if(nuclideName==
"39Ar" ){readfile(
"39Ar",
"Argon_39.root") ;}
233 else if(nuclideName==
"60Co" ){readfile(
"60Co",
"Cobalt_60.root") ;}
234 else if(nuclideName==
"85Kr" ){readfile(
"85Kr",
"Krypton_85.root") ;}
235 else if(nuclideName==
"40K" ){readfile(
"40K",
"Potassium_40.root") ;}
236 else if(nuclideName==
"232Th"){readfile(
"232Th",
"Thorium_232.root");}
237 else if(nuclideName==
"238U" ){readfile(
"238U",
"Uranium_238.root") ;}
238 else if(nuclideName==
"222Rn"){
continue;}
239 else if(nuclideName==
"59Ni"){
continue;}
240 else if(nuclideName==
"42Ar" ){
241 readfile(
"42Ar_1",
"Argon_42_1.root");
242 readfile(
"42Ar_2",
"Argon_42_2.root");
243 readfile(
"42Ar_3",
"Argon_42_3.root");
244 readfile(
"42Ar_4",
"Argon_42_4.root");
245 readfile(
"42Ar_5",
"Argon_42_5.root");
249 std::string searchName = nuclideName;
251 readfile(nuclideName,searchName);
266 run.
put(std::move(runcol));
276 std::unique_ptr< std::vector<simb::MCTruth> > truthcol(
new std::vector<simb::MCTruth>);
282 for (
unsigned int i=0; i<fNuclide.size(); ++i) {
287 truthcol->push_back(truth);
288 evt.
put(std::move(truthcol));
302 CLHEP::HepRandomEngine &engine = rng->
getEngine();
303 CLHEP::RandFlat flat(engine);
304 CLHEP::RandPoisson poisson(engine);
309 double rate = fabs( fBq[i] * (fT1[i] - fT0[i]) * (fX1[i] - fX0[i]) * (fY1[i] - fY0[i]) * (fZ1[i] - fZ0[i]) ) / 1.0E9;
310 long ndecays = poisson.shoot(rate);
312 for (
unsigned int idecay=0; idecay<ndecays; idecay++)
319 TLorentzVector pos( fX0[i] + flat.fire()*(fX1[i] - fX0[i]),
320 fY0[i] + flat.fire()*(fY1[i] - fY0[i]),
321 fZ0[i] + flat.fire()*(fZ1[i] - fZ0[i]),
322 (idecay==0 && fIsFirstSignalSpecial) ? 0 : ( fT0[i] + flat.fire()*(fT1[i] - fT0[i]) ) );
326 std::string volmaterial = geomanager->FindNode(pos.X(),pos.Y(),pos.Z())->GetMedium()->GetMaterial()->GetName();
328 if ( ! std::regex_match(volmaterial, std::regex(fMaterial[i])) )
continue;
335 std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>> v_prods;
337 if (fNuclide[i] ==
"222Rn")
339 double p=0;
double t=0.00548952;
td_Mass m=m_alpha;
ti_PDGID pdgid=1000020040;
341 double p2 = energy*energy - m*m;
342 if (p2 > 0) p = TMath::Sqrt(p2);
345 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
346 v_prods.push_back(partMassMom);
348 else if(fNuclide[i] ==
"59Ni"){
350 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
351 v_prods.push_back(partMassMom);
353 else if(fNuclide[i] ==
"42Ar"){
355 double bSelect = flat.fire();
357 samplespectrum(
"42Ar_1", pdgid, t, m, p);
358 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
359 v_prods.push_back(partMassMom);
361 }
else if(bSelect<0.9954){
362 samplespectrum(
"42Ar_2", pdgid, t, m, p);
363 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
364 v_prods.push_back(partMassMom);
366 }
else if(bSelect<0.9988){
367 samplespectrum(
"42Ar_3", pdgid, t, m, p);
368 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
369 v_prods.push_back(partMassMom);
371 }
else if(bSelect<0.9993){
372 samplespectrum(
"42Ar_4", pdgid, t, m, p);
373 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
374 v_prods.push_back(partMassMom);
377 samplespectrum(
"42Ar_5", pdgid, t, m, p);
378 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
379 v_prods.push_back(partMassMom);
387 samplespectrum(fNuclide[i],pdgid,t,m,p);
388 std::tuple<ti_PDGID, td_Mass, TLorentzVector> partMassMom = std::make_tuple(pdgid, m, dirCalc(p,m));
389 v_prods.push_back(partMassMom);
393 for(
auto prodEntry : v_prods){
395 int trackid = trackidcounter;
396 ti_PDGID pdgid = std::get<0>(prodEntry);
397 td_Mass m = std::get<1>(prodEntry);
398 TLorentzVector pvec = std::get<2>(prodEntry);
400 std::string primary(
"primary");
404 if (pdgid == 1000020040){
419 TLorentzVector RadioGen::dirCalc(
double p,
double m){
421 CLHEP::HepRandomEngine &engine = rng->
getEngine();
422 CLHEP::RandFlat flat(engine);
424 double costheta = (2.0*flat.fire() - 1.0);
425 if (costheta < -1.0) costheta = -1.0;
426 if (costheta > 1.0) costheta = 1.0;
427 double sintheta = sqrt(1.0-costheta*costheta);
428 double phi = 2.0*M_PI*flat.fire();
429 TLorentzVector pvec(p*sintheta*std::cos(phi),
430 p*sintheta*std::sin(phi),
439 void RadioGen::readfile(std::string nuclide, std::string filename)
442 for (
size_t i=0; i<fNuclide.size(); i++)
444 if (fNuclide[i] == nuclide){
448 else if ( (std::regex_match(nuclide, std::regex(
"42Ar.*" )) ) && fNuclide[i]==
"42Ar" ){
453 if (ifound == 0)
return;
455 Bool_t addStatus = TH1::AddDirectoryStatus();
456 TH1::AddDirectory(kFALSE);
460 spectrumname.push_back(nuclide);
461 cet::search_path sp(
"FW_SEARCH_PATH");
462 std::string fn2 =
"Radionuclides/";
464 std::string fullname;
465 sp.find_file(fn2, fullname);
467 if (fullname.empty() || stat(fullname.c_str(), &sb)!=0)
470 <<
" not found in FW_SEARCH_PATH!\n";
472 TFile
f(fullname.c_str(),
"READ");
473 TGraph *alphagraph = (TGraph*)
f.Get(
"Alphas");
474 TGraph *betagraph = (TGraph*)
f.Get(
"Betas");
475 TGraph *gammagraph = (TGraph*)
f.Get(
"Gammas");
476 TGraph *neutrongraph = (TGraph*)
f.Get(
"Neutrons");
480 int np = alphagraph->GetN();
481 double *
y = alphagraph->GetY();
486 TH1D *alphahist = (TH1D*)
new TH1D(name.c_str(),
"Alpha Spectrum",np,0,np);
487 for (
int i=0; i<np; i++)
489 alphahist->SetBinContent(i+1,y[i]);
490 alphahist->SetBinError(i+1,0);
492 alphaspectrum.push_back(alphahist);
493 alphaintegral.push_back(alphahist->Integral());
497 alphaspectrum.push_back(0);
498 alphaintegral.push_back(0);
504 int np = betagraph->GetN();
506 double *
y = betagraph->GetY();
511 TH1D *betahist = (TH1D*)
new TH1D(name.c_str(),
"Beta Spectrum",np,0,np);
513 for (
int i=0; i<np; i++)
515 betahist->SetBinContent(i+1,y[i]);
516 betahist->SetBinError(i+1,0);
518 betaspectrum.push_back(betahist);
519 betaintegral.push_back(betahist->Integral());
523 betaspectrum.push_back(0);
524 betaintegral.push_back(0);
529 int np = gammagraph->GetN();
530 double *
y = gammagraph->GetY();
535 TH1D *gammahist = (TH1D*)
new TH1D(name.c_str(),
"Gamma Spectrum",np,0,np);
536 for (
int i=0; i<np; i++)
538 gammahist->SetBinContent(i+1,y[i]);
539 gammahist->SetBinError(i+1,0);
541 gammaspectrum.push_back(gammahist);
542 gammaintegral.push_back(gammahist->Integral());
546 gammaspectrum.push_back(0);
547 gammaintegral.push_back(0);
552 int np = neutrongraph->GetN();
553 double *
y = neutrongraph->GetY();
558 TH1D *neutronhist = (TH1D*)
new TH1D(name.c_str(),
"Neutron Spectrum",np,0,np);
559 for (
int i=0; i<np; i++)
561 neutronhist->SetBinContent(i+1,y[i]);
562 neutronhist->SetBinError(i+1,0);
564 neutronspectrum.push_back(neutronhist);
565 neutronintegral.push_back(neutronhist->Integral());
569 neutronspectrum.push_back(0);
570 neutronintegral.push_back(0);
574 TH1::AddDirectory(addStatus);
576 double total = alphaintegral.back() + betaintegral.back() + gammaintegral.back() + neutronintegral.back();
579 alphaintegral.back() /= total;
580 betaintegral.back() /= total;
581 gammaintegral.back() /= total;
582 neutronintegral.back() /= total;
587 void RadioGen::samplespectrum(std::string nuclide,
int &itype,
double &t,
double &m,
double &p)
591 CLHEP::HepRandomEngine &engine = rng->
getEngine();
592 CLHEP::RandFlat flat(engine);
595 for (
size_t i=0; i<spectrumname.size(); i++)
597 if (nuclide == spectrumname[i])
607 throw cet::exception(
"RadioGen") <<
"Ununderstood nuclide: " << nuclide <<
"\n";
610 double rtype = flat.fire();
615 for (
int itry=0;itry<10;itry++)
617 if (rtype <= alphaintegral[inuc] && alphaspectrum[inuc] != 0)
621 t = samplefromth1d(alphaspectrum[inuc])/1000000.0;
623 else if (rtype <= alphaintegral[inuc]+betaintegral[inuc] && betaspectrum[inuc] != 0)
627 t = samplefromth1d(betaspectrum[inuc])/1000000.0;
629 else if ( rtype <= alphaintegral[inuc] + betaintegral[inuc] + gammaintegral[inuc] && gammaspectrum[inuc] != 0)
633 t = samplefromth1d(gammaspectrum[inuc])/1000000.0;
635 else if( neutronspectrum[inuc] != 0)
639 t = samplefromth1d(neutronspectrum[inuc])/1000000.0;
641 if (itype >= 0)
break;
645 throw cet::exception(
"RadioGen") <<
"Normalization problem with nuclide: " << nuclide <<
"\n";
650 { p = TMath::Sqrt(p); }
658 double RadioGen::samplefromth1d(TH1D *
hist)
661 CLHEP::HepRandomEngine &engine = rng->
getEngine();
662 CLHEP::RandFlat flat(engine);
664 int nbinsx = hist->GetNbinsX();
665 std::vector<double> partialsum;
666 partialsum.resize(nbinsx+1);
669 for (
int i=1;i<=nbinsx;i++)
671 double hc = hist->GetBinContent(i);
672 if ( hc < 0)
throw cet::exception(
"RadioGen") <<
"Negative bin: " << i <<
" " << hist->GetName() <<
"\n";
673 partialsum[i] = partialsum[i-1] + hc;
675 double integral = partialsum[nbinsx];
676 if (integral == 0)
return 0;
678 for (
int i=1;i<=nbinsx;i++) partialsum[i] /= integral;
680 double r1 = flat.fire();
681 int ibin = TMath::BinarySearch(nbinsx,&(partialsum[0]),r1);
682 Double_t
x = hist->GetBinLowEdge(ibin+1);
683 if (r1 > partialsum[ibin]) x +=
684 hist->GetBinWidth(ibin+1)*(r1-partialsum[ibin])/(partialsum[ibin+1] - partialsum[ibin]);
696 void RadioGen::Ar42Gamma2(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
698 std::vector<double> vd_p = {.0015246};
700 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
701 v_prods.push_back(prods);
704 void RadioGen::Ar42Gamma3(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
706 std::vector<double> vd_p = {.0003126};
708 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
709 v_prods.push_back(prods);
713 void RadioGen::Ar42Gamma4(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
715 CLHEP::HepRandomEngine &engine = rng->
getEngine();
716 CLHEP::RandFlat flat(engine);
718 double chan1 = (0.052 / (0.052+0.020) );
719 if(flat.fire()<chan1){
720 std::vector<double> vd_p = {.0008997};
722 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
723 v_prods.push_back(prods);
727 std::vector<double> vd_p = {.0024243};
729 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
730 v_prods.push_back(prods);
734 void RadioGen::Ar42Gamma5(
std::vector<std::tuple<ti_PDGID, td_Mass, TLorentzVector>>& v_prods){
736 CLHEP::HepRandomEngine &engine = rng->
getEngine();
737 CLHEP::RandFlat flat(engine);
739 double chan1 = ( 0.0033 / (0.0033 + 0.0201 + 0.041) );
double chan2 = ( 0.0201 / (0.0033 + 0.0201 + 0.041) );
740 double chanPick = flat.fire();
741 if(chanPick < chan1){
742 std::vector<double> vd_p = {0.000692, 0.001228};
744 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
745 v_prods.push_back(prods);
748 }
else if (chanPick<(chan1+chan2)){
749 std::vector<double> vd_p = {0.0010212};
751 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
752 v_prods.push_back(prods);
756 std::vector<double> vd_p = {0.0019208};
758 std::tuple<ti_PDGID, td_Mass, TLorentzVector> prods = std::make_tuple(pdgid, m, dirCalc(p,m));
759 v_prods.push_back(prods);
800
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.
bool fIsFirstSignalSpecial
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.