26 #include "art/Framework/Core/EDProducer.h"
27 #include "art/Framework/Principal/Event.h"
28 #include "art/Framework/Principal/Run.h"
29 #include "fhiclcpp/ParameterSet.h"
30 #include "art/Framework/Services/Registry/ServiceHandle.h"
31 #include "art_root_io/TFileService.h"
32 #include "art/Framework/Core/ModuleMacros.h"
33 #include "messagefacility/MessageLogger/MessageLogger.h"
34 #include "cetlib_except/exception.h"
37 #include "nurandom/RandomUtils/NuRandomService.h"
40 #include "nusimdata/SimulationBase/MCTruth.h"
41 #include "nusimdata/SimulationBase/MCParticle.h"
48 #include "TDatabasePDG.h"
55 #include "CLHEP/Random/RandFlat.h"
56 #include "CLHEP/Random/RandGaussQ.h"
71 void beginRun(art::Run& run)
override;
80 void SampleOne(
unsigned int i, simb::MCTruth &mct, CLHEP::HepRandomEngine& engine);
81 void Sample(simb::MCTruth &mct, CLHEP::HepRandomEngine& engine);
88 std::vector<double>
GetBinning(
const TAxis* axis,
bool finalEdge=
true);
164 : art::EDProducer{pset}
167 ,
fEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*
this, pset,
"Seed"))
168 ,
fMode {pset.get<
int >(
"ParticleSelectionMode")}
170 ,
fPDG {pset.get< std::vector<int> >(
"PDG")}
173 ,
fEmin {pset.get<
double >(
"Emin")}
174 ,
fEmax {pset.get<
double >(
"Emax")}
175 ,
fEmid {pset.get<
double >(
"Emid")}
184 ,
fT0 {pset.get<
double >(
"T0")}
191 , fEpsilon {pset.get<
double >(
"Epsilon")}
193 produces< std::vector<simb::MCTruth> >();
201 art::ServiceHandle<geo::Geometry const> geom;
202 for (
unsigned int i=0; i < geom->Ncryostats() ; i++ ) {
213 art::ServiceHandle<art::TFileService const>
tfs;
230 fTree = tfs->make<TTree>(
"Generator",
"analysis tree");
242 fTree->Branch(
"Phi" ,&
Phi ,
"Phi/D" );
249 if (
fThetamax > M_PI/2 + 0.01 )
throw cet::exception(
"GaisserParam")<<
"\nThetamax has to be less than " << M_PI/2 <<
", but was entered as " <<
fThetamax <<
", this cause an error so leaving program now...\n\n";
250 if (
fThetamin < 0 )
throw cet::exception(
"GaisserParam")<<
"\nThetamin has to be more than 0, but was entered as " <<
fThetamin <<
", this cause an error so leaving program now...\n\n" << std::endl;
251 if (
fThetamax <
fThetamin )
throw cet::exception(
"GaisserParam")<<
"\nMinimum angle is bigger than maximum angle....causes an error so leaving program now....\n\n" << std::endl;
254 art::ServiceHandle<geo::Geometry const> geo;
255 run.put(std::make_unique<sumdata::RunData>(geo->DetectorName()));
263 std::unique_ptr< std::vector<simb::MCTruth> > truthcol(
new std::vector<simb::MCTruth>);
266 truth.SetOrigin(simb::kSingleParticle);
270 MF_LOG_DEBUG(
"GaisserParam") << truth;
272 truthcol->push_back(truth);
274 evt.put(std::move(truthcol));
282 CLHEP::RandFlat flat(engine);
283 CLHEP::RandGaussQ gauss(engine);
292 int trackid = -1*(i+1);
293 std::string primary(
"primary");
299 if(1.0-2.0*flat.fire() > 0)
fPDG[i]=-
fPDG[i];
303 static TDatabasePDG pdgt;
304 TParticlePDG* pdgp = pdgt.GetParticle(
fPDG[i]);
305 if (pdgp) m = pdgp->Mass();
321 TLorentzVector pos(x[0], x[1], x[2],
Time);
327 std::pair<double,double> theta_energy;
331 Theta = theta_energy.first;
332 Phi = M_PI*( 1.0-2.0*flat.fire() );
336 Gamma = 1 + (KinEnergy/
m);
341 pmom[1] = -
Momentum*std::cos(Theta);
344 pnorm = std::sqrt( pmom[0]*pmom[0] + pmom[1]*pmom[1] + pmom[2]*pmom[2] );
350 std::cout <<
"MuFlux map hasn't been initialised, aborting...." << std::endl;
354 TLorentzVector pvec(pmom[0], pmom[1], pmom[2],
Energy );
356 simb::MCParticle part(trackid,
fPDG[i], primary);
357 part.AddTrajectoryPoint(pos, pvec);
380 std::cout <<
"x: " << pos.X() <<
" y: " << pos.Y() <<
" z: " << pos.Z() <<
" time: " << pos.T() << std::endl;
381 std::cout <<
"Px: " << pvec.Px() <<
" Py: " << pvec.Py() <<
" Pz: " << pvec.Pz() << std::endl;
394 for (
unsigned int i=0; i<
fPDG.size(); ++i) {
401 CLHEP::RandFlat flat(engine);
403 unsigned int i=flat.fireInt(
fPDG.size());
408 mf::LogWarning(
"UnrecognizeOption") <<
"GaisserParam does not recognize ParticleSelectionMode "
419 if(rand1 < 0 || rand1 > 1)
std::cerr <<
"GetThetaAndEnergy:\tInvalid random number " << rand1 << std::endl;
420 if(rand2 < 0 || rand2 > 1)
std::cerr <<
"GetThetaAndEnergy:\tInvalid random number " << rand2 << std::endl;
424 if(
m_thetaHist->GetBinContent(thetaBin) < rand1) thetaBin += 1;
426 double thetaLow =
m_thetaHist->GetXaxis()->GetBinLowEdge(thetaBin);
427 double thetaUp =
m_thetaHist->GetXaxis()->GetBinUpEdge(thetaBin);
428 double theta = drand1*(thetaUp-thetaLow) + thetaLow;
432 bool notFound =
true;
434 if( fabs(mapit->first+thetaLow)<0.000001 ) {
435 energyHist = mapit->second;
440 if(notFound)
std::cout <<
"GetThetaAndEnergy: ERROR:\tInvalid theta!" << std::endl;
443 energyHist->GetBinWithContent(
double(rand2),energyBin,1,energyHist->GetNbinsX(),1.0);
444 if(energyHist->GetBinContent(energyBin) < rand2) energyBin += 1;
445 double drand2 = (energyHist->GetBinContent(energyBin) - rand2)/(energyHist->GetBinContent(energyBin) - energyHist->GetBinContent(energyBin-1));
446 double energyLow = energyHist->GetXaxis()->GetBinLowEdge(energyBin);
447 double energyUp = energyHist->GetXaxis()->GetBinUpEdge(energyBin);
448 double energy = drand2*(energyUp-energyLow) + energyLow;
451 return std::make_pair(theta,energy);
457 std::cout <<
"In my function MakePDF" << std::endl;
461 double TotalMuonFlux=0;
466 std::cout <<
"MakePDF: Map has already been initialised. " << std::endl;
467 std::cout <<
"Do fSetReWrite - true if you really want to override this map." << std::endl;
475 std::cout <<
"Making new dhist_Map called m_PDFmap....." << std::endl;
478 TF2* muonSpec =
new TF2(
"muonSpec",
this,
481 "GaisserParam",
"GaisserMuonFlux_Integrand"
488 std::cout <<
"Surface flux of muons = " << TotalMuonFlux <<
" cm-2 s-1" << std::endl;
491 std::ostringstream pdfFile;
493 std::string tmpfileName = pdfFile.str();
494 std::replace(tmpfileName.begin(),tmpfileName.end(),
'+',
'0');
495 if (tmpfileName ==
"GaisserPDF_0-100-100100-1000-10000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_DefaultBins.root";
496 else if (tmpfileName ==
"GaisserPDF_0-100-4000-1000-1000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_LowEnergy.root";
497 else if (tmpfileName ==
"GaisserPDF_4000-10000-100000-1000-10000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_MidEnergy.root";
498 else if (tmpfileName ==
"GaisserPDF_100000-500000-1e007-10000-100000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_HighEnergy.root";
500 std::ostringstream pdfFilePath;
502 std::string
fileName = pdfFilePath.str();
507 cet::search_path sp(
"FW_SEARCH_PATH");
508 std::string fROOTfile;
509 if( sp.find_file(tmpfileName, fROOTfile) ) fileName = fROOTfile;
511 std::cout <<
"File path; " << fileName << std::endl;
516 if(!fSetRead)
std::cout <<
"WARNING- "+fileName+
" does not exist." << std::endl;
518 std::cout <<
"Reading PDF from file "+fileName << std::endl;
519 m_File =
new TFile(fileName.c_str());
520 if(
m_File->IsZombie() ||
m_File->TestBit(TFile::kRecovered)){
521 std::cout <<
"WARNING- "+fileName+
" is corrupted or cannot be read." << std::endl;
528 std::cout <<
"Now going to read file...." << std::endl;
533 std::ostringstream pdfEnergyHist;
534 pdfEnergyHist <<
"pdf_energy_"<<i;
535 std::string pdfEnergyHiststr = pdfEnergyHist.str();
537 TH1* pdf_hist = (TH1D*)
m_File->Get( pdfEnergyHiststr.c_str() );
538 m_PDFmap->insert(std::make_pair(-thetalow,pdf_hist));
539 thetalow = double(i)*(
fThetamax)/
double(fThetaBins);
544 std::cout <<
"Generating a new muon flux PDF" << std::endl;
546 std::cout <<
"Writing to PDF to file "+fileName << std::endl;
547 m_File =
new TFile(fileName.c_str(),
"RECREATE");
550 double dnbins_theta = double(fThetaBins);
553 double di = i==0 ? 0.1 : double(i);
554 double theta = di*(
fThetamax)/dnbins_theta;
556 m_thetaHist->SetBinContent(i, int_i/TotalMuonFlux);
559 std::cout <<
"theta PDF complete... now making the energy PDFs (this will take a little longer)... " << std::endl;
565 double di = double(i);
566 double theta = di*(
fThetamax)/fThetaBins;
573 TH1* pdf_lowenergy =
new TH1D(
"pdf_lowenergy",
"pdf_lowenergy", nbins,
fEmin,
fEmid);
574 double dnbins = double(nbins);
575 for(
int j=1; j<=nbins; j++){
576 double dj = double(j);
580 pdf_lowenergy->SetBinContent(j, int_j/int_tot);
585 dnbins=double(nbins);
586 TH1* pdf_highenergy =
new TH1D(
"pdf_highenergy",
"pdf_highenergy", nbins,
fEmid,
fEmax);
587 for(
int j=1; j<=nbins; j++){
588 double dj = double(j);
591 pdf_highenergy->SetBinContent(j, int_j/int_tot);
595 std::vector<double> vxbins =
GetBinning(pdf_lowenergy->GetXaxis(),
false);
596 std::vector<double> vxbins2 =
GetBinning(pdf_highenergy->GetXaxis());
597 vxbins.insert(vxbins.end(), vxbins2.begin(), vxbins2.end());
600 double* xbins =
new double[vxbins.size()];
601 for(std::vector<double>::const_iterator binit=vxbins.begin(); binit!=vxbins.end(); binit++, ibin++) xbins[ibin]=(*binit);
602 TH1* pdf_energy =
new TH1D(
"pdf_energy",
"pdf_energy", vxbins.size()-1, xbins);
604 for(ibin = 1; ibin<=pdf_lowenergy->GetNbinsX(); ibin++, ibin2++){
605 double content = pdf_lowenergy->GetBinContent(ibin);
606 if(ibin == 1) content = content - 0.00001;
607 pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), content);
609 for(ibin = 1; ibin<=pdf_highenergy->GetNbinsX(); ibin++, ibin2++){
610 pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), pdf_highenergy->GetBinContent(ibin));
614 std::ostringstream Clonestr;
615 Clonestr <<
"pdf_energy_"<<i;
616 TH1* pdf_energy_noneg = (TH1D*) pdf_energy->Clone( Clonestr.str().c_str() );
617 pdf_energy_noneg->Reset();
622 for(ibin = 1; ibin<=pdf_energy->GetNbinsX(); ibin++){
623 double newPD = pdf_energy->GetBinContent(ibin);
624 double probDiff = newPD - lastPD;
626 if(ibin!=pdf_energy->GetNbinsX()){
632 else PDF += probDiff;
634 for(
int iskip=0; iskip <= nSkip; iskip++) pdf_energy_noneg->Fill(pdf_energy_noneg->GetBinCenter(ibin-iskip), PDF);
642 m_PDFmap->insert(std::make_pair(-thetalow,pdf_energy_noneg));
648 delete pdf_lowenergy;
649 delete pdf_highenergy;
652 std::cout <<
"\r===> " << 100.0*double(i)/double(fThetaBins) <<
"% complete... " << std::endl;
654 std::cout <<
"finished the energy pdfs." << std::endl;
664 double ct = cos(theta);
672 double c1 = sqrt(1.-(1.-pow(ct,2.0))/pow( (1.+32./6370.) ,2.0));
673 double deltae = 2.06e-3 * (1030. / c1 - 120.);
674 double em = e + deltae/2.;
675 double e1 = e + deltae;
676 double pdec = pow( (120. / (1030. / c1)), (1.04 / c1 / em));
677 di=A*pow(e1,-gamma)*(1./(1.+1.1*e1*c1/115.) + 0.054/(1.+1.1*e1*c1/850.) +
rc)*pdec;
683 double gamma2 = 1.29;
684 double ct_star = sqrt( (pow(ct,2) + 0.102573*0.102573 - 0.068287*pow(ct,0.958633)
685 + 0.0407253*pow(ct,0.817285) )/(1.0 + 0.102573*0.102573 - 0.068287 + 0.0407253) );
686 double eMod = e*(1.0+C/(e*pow(ct_star,gamma2)));
687 di=A*pow(eMod,-gamma)*(1./(1.+1.1*e*ct_star/115.) + 0.054/(1.+1.1*e*ct_star/850.));
697 double flux = 2.0*M_PI*sin(x[1])*
GaisserFlux(x[0],x[1]);
704 std::vector<double> vbins;
705 for(
int ibin=1; ibin<=axis->GetNbins()+1; ibin++){
706 if(ibin<=axis->GetNbins()) vbins.push_back(axis->GetBinLowEdge(ibin));
707 else if(finalEdge) vbins.push_back(axis->GetBinLowEdge(ibin) + axis->GetBinWidth(ibin));
717 if(mapit->second)
delete mapit->second;
721 std::cout <<
"Reset PDFmap and thetaHist..." << std::endl;
double fEpsilon
Minimum integration sum....
double fThetamax
Maximum theta.
createEngine fPadOutVectors
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
static constexpr int kGAUS
module to produce single or multiple specified particles in the detector
double fYInput
Max Y position.
int fThetaBins
Number of theta Bins.
std::vector< double > GetBinning(const TAxis *axis, bool finalEdge=true)
double fEmid
Energy to go from low to high (GeV)
bool fSetReWrite
Whether to ReWrite pdfs.
produces< sumdata::RunData, art::InRun >()
double GaisserFlux(double e, double theta)
void produce(art::Event &evt) override
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
CLHEP::HepRandomEngine & fEngine
art-managed random-number engine
std::string fInputDir
Input Directory.
int fEBinsLow
Number of low energy Bins.
GaisserParam(fhicl::ParameterSet const &pset)
std::map< double, TH1 * > dhist_Map
std::pair< double, double > GetThetaAndEnergy(double rand1, double rand2)
double fEmin
Minimum Kinetic Energy (GeV)
double fSigmaT
Variation in t position (ns)
fEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this, pset,"Seed"))
void Sample(simb::MCTruth &mct, CLHEP::HepRandomEngine &engine)
bool fSetParam
Which version of Gaissers Param.
double fEmax
Maximum Kinetic Energy (GeV)
double fXHalfRange
Max X position.
double fCryoBoundaries[6]
services TFileService fileName
int fEBinsHigh
Number of high energy Bins.
std::vector< int > fPDG
PDG code of particles to generate.
void SampleOne(unsigned int i, simb::MCTruth &mct, CLHEP::HepRandomEngine &engine)
bool fSetRead
Whether to Read.
double fThetamin
Minimum theta.
double GaisserMuonFlux_Integrand(Double_t *x, Double_t *par)
art::ServiceHandle< art::TFileService > tfs
int fTDist
How to distribute t (gaus, or uniform)
double fT0
Central t position (ns) in world coordinates.
std::map< double, TH1 * >::iterator dhist_Map_it
void beginRun(art::Run &run) override
bool fSetWrite
Whether to Write.
art framework interface to geometry description
BEGIN_PROLOG could also be cout
double fZHalfRange
Max Z position.