1 #ifndef EVGEN_GAISSERPARAM 13 #define EVGEN_GAISSERPARAM 41 #include "cetlib_except/exception.h" 56 #include "TDatabasePDG.h" 65 #include "CLHEP/Random/RandFlat.h" 66 #include "CLHEP/Random/RandGaussQ.h" 69 namespace simb {
class MCTruth; }
98 std::pair<double,double> GetThetaAndEnergy(
double rand1,
double rand2);
101 double GaisserMuonFlux_Integrand(Double_t *
x, Double_t *par);
102 double GaisserFlux(
double e,
double theta);
103 std::vector<double> GetBinning(
const TAxis* axis,
bool finalEdge=
true);
106 static const int kGAUS = 1;
112 std::vector<int> fPDG;
159 double fCryoBoundaries[6];
169 double Time, Momentum, KinEnergy, Gamma, Energy, Theta, Phi, pnorm;
170 double XPosition, YPosition,
ZPosition, DirCosineX, DirCosineY, DirCosineZ;
179 this->reconfigure(pset);
184 ->createEngine(*
this, pset,
"Seed");
186 produces< std::vector<simb::MCTruth> >();
187 produces< sumdata::RunData, art::InRun >();
191 GaisserParam::~GaisserParam()
201 fPadOutVectors = p.
get<
bool >(
"PadOutVectors");
202 fMode = p.
get<
int >(
"ParticleSelectionMode");
203 fPDG = p.
get< std::vector<int> >(
"PDG");
205 fCharge = p.
get<
int >(
"Charge");
206 fInputDir = p.
get< std::string >(
"InputDir");
208 fEmin = p.
get<
double >(
"Emin");
209 fEmax = p.
get<
double >(
"Emax");
210 fEmid = p.
get<
double >(
"Emid");
211 fEBinsLow = p.
get<
int >(
"EBinsLow");
212 fEBinsHigh = p.
get<
int >(
"EBinsHigh");
214 fThetamin = p.
get<
double >(
"Thetamin");
215 fThetamax = p.
get<
double >(
"Thetamax");
216 fThetaBins = p.
get<
int >(
"ThetaBins");
218 fXHalfRange = p.
get<
double >(
"XHalfRange");
219 fYInput = p.
get<
double >(
"YInput");
220 fZHalfRange = p.
get<
double >(
"ZHalfRange");
222 fT0 = p.
get<
double >(
"T0");
223 fSigmaT = p.
get<
double >(
"SigmaT");
224 fTDist = p.
get<
int >(
"TDist");
226 fSetParam = p.
get<
bool >(
"SetParam");
227 fSetRead = p.
get<
bool >(
"SetRead");
228 fSetWrite = p.
get<
bool >(
"SetWrite");
229 fSetReWrite = p.
get<
bool >(
"SetReWrite");
230 fEpsilon = p.
get<
double >(
"Epsilon");
240 for (
unsigned int i=0; i < geom->
Ncryostats() ; i++ ) {
242 if ( xNeg > fCryoBoundaries[0] ) xNeg = fCryoBoundaries[0];
243 if ( xPos < fCryoBoundaries[1] ) xPos = fCryoBoundaries[1];
244 if ( zNeg > fCryoBoundaries[4] ) zNeg = fCryoBoundaries[4];
245 if ( zPos < fCryoBoundaries[5] ) zPos = fCryoBoundaries[5];
247 fCenterX = xNeg + (xPos-xNeg)/2;
248 fCenterZ = zNeg + (zPos-zNeg)/2;
268 fTree = tfs->
make<TTree>(
"Generator",
"analysis tree");
269 fTree->Branch(
"XPosition" ,&XPosition ,
"XPosition/D" );
270 fTree->Branch(
"YPosition" ,&YPosition ,
"YPosition/D" );
271 fTree->Branch(
"ZPosition" ,&ZPosition ,
"ZPosition/D" );
272 fTree->Branch(
"Time" ,&Time ,
"Time/D" );
273 fTree->Branch(
"Momentum" ,&Momentum ,
"Momentum/D" );
274 fTree->Branch(
"KinEnergy" ,&KinEnergy ,
"KinEnergy/D" );
275 fTree->Branch(
"Energy" ,&Energy ,
"Energy/D" );
276 fTree->Branch(
"DirCosineX",&DirCosineX,
"DirCosineX/D");
277 fTree->Branch(
"DirCosineY",&DirCosineY,
"DirCosineY/D");
278 fTree->Branch(
"DirCosineZ",&DirCosineZ,
"DirCosineZ/D");
279 fTree->Branch(
"Theta" ,&Theta ,
"Theta/D" );
280 fTree->Branch(
"Phi" ,&Phi ,
"Phi/D" );
291 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";
292 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;
293 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;
295 run.
put(std::move(runcol));
305 std::unique_ptr< std::vector<simb::MCTruth> > truthcol(
new std::vector<simb::MCTruth>);
314 truthcol->push_back(truth);
316 evt.
put(std::move(truthcol));
328 CLHEP::HepRandomEngine &engine = rng->
getEngine();
329 CLHEP::RandFlat flat(engine);
330 CLHEP::RandGaussQ gauss(engine);
332 Time = Momentum = KinEnergy = Gamma = Energy = Theta = Phi = pnorm = 0.0;
333 XPosition = YPosition = ZPosition = DirCosineX = DirCosineY = DirCosineZ = 0.0;
339 int trackid = -1*(i+1);
340 std::string primary(
"primary");
346 if(1.0-2.0*flat.fire() > 0) fPDG[i]=-fPDG[i];
348 else if ( fCharge == 1 ) fPDG[i] = 13;
349 else if ( fCharge == 2 ) fPDG[i] = -13;
350 static TDatabasePDG pdgt;
351 TParticlePDG* pdgp = pdgt.GetParticle(fPDG[i]);
352 if (pdgp) m = pdgp->Mass();
356 Time = gauss.fire(fT0, fSigmaT);
359 Time = fT0 + fSigmaT*(2.0*flat.fire()-1.0);
363 x[0] = (1.0 - 2.0*flat.fire())*fXHalfRange + fCenterX;
365 x[2] = (1.0 - 2.0*flat.fire())*fZHalfRange + fCenterZ;
368 TLorentzVector pos(x[0], x[1], x[2], Time);
374 std::pair<double,double> theta_energy;
375 theta_energy = GetThetaAndEnergy(flat.fire(),flat.fire());
378 Theta = theta_energy.first;
379 Phi = M_PI*( 1.0-2.0*flat.fire() );
382 KinEnergy = theta_energy.second;
383 Gamma = 1 + (KinEnergy/m);
385 Momentum = std::sqrt(Energy*Energy-m*m);
387 pmom[0] = Momentum*std::sin(Theta)*std::cos(Phi);
388 pmom[1] = -Momentum*std::cos(Theta);
389 pmom[2] = Momentum*std::sin(Theta)*std::sin(Phi);
391 pnorm = std::sqrt( pmom[0]*pmom[0] + pmom[1]*pmom[1] + pmom[2]*pmom[2] );
392 DirCosineX = pmom[0] / pnorm;
393 DirCosineY = pmom[1] / pnorm;
394 DirCosineZ = pmom[2] / pnorm;
397 std::cout <<
"MuFlux map hasn't been initialised, aborting...." << std::endl;
401 TLorentzVector pvec(pmom[0], pmom[1], pmom[2], Energy );
426 std::cout <<
"Theta: " << Theta <<
" Phi: " << Phi <<
" KineticEnergy: " << KinEnergy <<
" Energy: " << Energy <<
" Momentum: " << Momentum << std::endl;
427 std::cout <<
"x: " << pos.X() <<
" y: " << pos.Y() <<
" z: " << pos.Z() <<
" time: " << pos.T() << std::endl;
428 std::cout <<
"Px: " << pvec.Px() <<
" Py: " << pvec.Py() <<
" Pz: " << pvec.Pz() << std::endl;
429 std::cout <<
"Normalised..." << DirCosineX <<
" " << DirCosineY <<
" " << DirCosineZ << std::endl;
441 for (
unsigned int i=0; i<fPDG.size(); ++i) {
449 CLHEP::HepRandomEngine &engine = rng->
getEngine();
450 CLHEP::RandFlat flat(engine);
452 unsigned int i=flat.fireInt(fPDG.size());
457 mf::LogWarning(
"UnrecognizeOption") <<
"GaisserParam does not recognize ParticleSelectionMode " 466 std::pair<double,double> GaisserParam::GetThetaAndEnergy(
double rand1,
double rand2)
468 if(rand1 < 0 || rand1 > 1) std::cerr <<
"GetThetaAndEnergy:\tInvalid random number " << rand1 << std::endl;
469 if(rand2 < 0 || rand2 > 1) std::cerr <<
"GetThetaAndEnergy:\tInvalid random number " << rand2 << std::endl;
472 m_thetaHist->GetBinWithContent(
double(rand1),thetaBin,1,m_thetaHist->GetNbinsX(),1.0);
473 if(m_thetaHist->GetBinContent(thetaBin) < rand1) thetaBin += 1;
474 double drand1 = (m_thetaHist->GetBinContent(thetaBin) - rand1)/(m_thetaHist->GetBinContent(thetaBin) - m_thetaHist->GetBinContent(thetaBin-1));
475 double thetaLow = m_thetaHist->GetXaxis()->GetBinLowEdge(thetaBin);
476 double thetaUp = m_thetaHist->GetXaxis()->GetBinUpEdge(thetaBin);
477 double theta = drand1*(thetaUp-thetaLow) + thetaLow;
481 bool notFound =
true;
482 for(
dhist_Map_it mapit=m_PDFmap->begin(); mapit!=m_PDFmap->end(); mapit++){
483 if( fabs(mapit->first+thetaLow)<0.000001 ) {
484 energyHist = mapit->second;
489 if(notFound) std::cout <<
"GetThetaAndEnergy: ERROR:\tInvalid theta!" << std::endl;
492 energyHist->GetBinWithContent(
double(rand2),energyBin,1,energyHist->GetNbinsX(),1.0);
493 if(energyHist->GetBinContent(energyBin) < rand2) energyBin += 1;
494 double drand2 = (energyHist->GetBinContent(energyBin) - rand2)/(energyHist->GetBinContent(energyBin) - energyHist->GetBinContent(energyBin-1));
495 double energyLow = energyHist->GetXaxis()->GetBinLowEdge(energyBin);
496 double energyUp = energyHist->GetXaxis()->GetBinUpEdge(energyBin);
497 double energy = drand2*(energyUp-energyLow) + energyLow;
500 return std::make_pair(theta,energy);
504 void GaisserParam::MakePDF()
506 std::cout <<
"In my function MakePDF" << std::endl;
510 double TotalMuonFlux=0;
513 std::cout <<
"PDFMAP" << std::endl;
514 if(m_PDFmap->size()>0 && !fSetReWrite){
515 std::cout <<
"MakePDF: Map has already been initialised. " << std::endl;
516 std::cout <<
"Do fSetReWrite - true if you really want to override this map." << std::endl;
519 std::cout << fSetReWrite << std::endl;
520 if(fSetReWrite) ResetMap();
524 std::cout <<
"Making new dhist_Map called m_PDFmap....." << std::endl;
527 TF2* muonSpec =
new TF2(
"muonSpec",
this,
529 fEmin, fEmax, fThetamin, fThetamax, 0,
530 "GaisserParam",
"GaisserMuonFlux_Integrand" 536 TotalMuonFlux = muonSpec->Integral(fEmin, fEmax, fThetamin, fThetamax, fEpsilon );
537 std::cout <<
"Surface flux of muons = " << TotalMuonFlux <<
" cm-2 s-1" << std::endl;
540 std::ostringstream pdfFile;
541 pdfFile <<
"GaisserPDF_"<<fEmin<<
"-"<<fEmid<<
"-"<<fEmax<<
"-"<< fEBinsLow<<
"-"<<fEBinsHigh<<
"-"<<fThetamin<<
"-"<<fThetamax<<
"-"<<fThetaBins<<
".root";
542 std::string tmpfileName = pdfFile.str();
543 std::replace(tmpfileName.begin(),tmpfileName.end(),
'+',
'0');
544 if (tmpfileName ==
"GaisserPDF_0-100-100100-1000-10000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_DefaultBins.root";
545 else if (tmpfileName ==
"GaisserPDF_0-100-4000-1000-1000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_LowEnergy.root";
546 else if (tmpfileName ==
"GaisserPDF_4000-10000-100000-1000-10000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_MidEnergy.root";
547 else if (tmpfileName ==
"GaisserPDF_100000-500000-1e007-10000-100000-0-1.5708-100.root") tmpfileName =
"GaisserPDF_HighEnergy.root";
549 std::ostringstream pdfFilePath;
550 pdfFilePath << fInputDir << tmpfileName;
551 std::string fileName = pdfFilePath.str();
556 cet::search_path sp(
"FW_SEARCH_PATH");
557 std::string fROOTfile;
558 if( sp.find_file(tmpfileName, fROOTfile) ) fileName = fROOTfile;
560 std::cout <<
"File path; " << fileName << std::endl;
564 fSetRead = stat(fileName.c_str(), &buffer) == 0;
565 if(!fSetRead) std::cout <<
"WARNING- "+fileName+
" does not exist." << std::endl;
567 std::cout <<
"Reading PDF from file "+fileName << std::endl;
568 m_File =
new TFile(fileName.c_str());
569 if(m_File->IsZombie() || m_File->TestBit(TFile::kRecovered)){
570 std::cout <<
"WARNING- "+fileName+
" is corrupted or cannot be read." << std::endl;
577 std::cout <<
"Now going to read file...." << std::endl;
579 double thetalow = fThetamin;
580 m_thetaHist = (TH1D*) m_File->Get(
"pdf_theta");
581 for(
int i=1; i<=fThetaBins; i++){
582 std::ostringstream pdfEnergyHist;
583 pdfEnergyHist <<
"pdf_energy_"<<i;
584 std::string pdfEnergyHiststr = pdfEnergyHist.str();
586 TH1* pdf_hist = (TH1D*) m_File->Get( pdfEnergyHiststr.c_str() );
587 m_PDFmap->insert(std::make_pair(-thetalow,pdf_hist));
588 thetalow = double(i)*(fThetamax)/
double(fThetaBins);
593 std::cout <<
"Generating a new muon flux PDF" << std::endl;
595 std::cout <<
"Writing to PDF to file "+fileName << std::endl;
596 m_File =
new TFile(fileName.c_str(),
"RECREATE");
599 double dnbins_theta = double(fThetaBins);
600 m_thetaHist =
new TH1D(
"pdf_theta",
"pdf_theta", fThetaBins, fThetamin, fThetamax);
601 for(
int i=1; i<=fThetaBins; i++){
602 double di = i==0 ? 0.1 : double(i);
603 double theta = di*(fThetamax)/dnbins_theta;
604 double int_i = muonSpec->Integral(fEmin, fEmax, fThetamin, theta, fEpsilon);
605 m_thetaHist->SetBinContent(i, int_i/TotalMuonFlux);
607 if(fSetWrite) m_thetaHist->Write();
608 std::cout <<
"theta PDF complete... now making the energy PDFs (this will take a little longer)... " << std::endl;
611 double thetalow = fThetamin;
612 for(
int i=1; i<=fThetaBins; i++){
614 double di = double(i);
615 double theta = di*(fThetamax)/fThetaBins;
618 double int_tot = muonSpec->Integral(fEmin, fEmax, thetalow, theta, fEpsilon);
621 int nbins = fEBinsLow;
622 TH1* pdf_lowenergy =
new TH1D(
"pdf_lowenergy",
"pdf_lowenergy", nbins, fEmin, fEmid);
623 double dnbins = double(nbins);
624 for(
int j=1; j<=nbins; j++){
625 double dj = double(j);
626 double int_j = muonSpec->Integral(fEmin, fEmin + dj*(fEmid-fEmin)/dnbins, thetalow, theta, fEpsilon);
629 pdf_lowenergy->SetBinContent(j, int_j/int_tot);
634 dnbins=double(nbins);
635 TH1* pdf_highenergy =
new TH1D(
"pdf_highenergy",
"pdf_highenergy", nbins, fEmid, fEmax);
636 for(
int j=1; j<=nbins; j++){
637 double dj = double(j);
638 double int_j = muonSpec->Integral(fEmin, fEmid + dj*(fEmax-fEmid)/dnbins, thetalow, theta, fEpsilon);
640 pdf_highenergy->SetBinContent(j, int_j/int_tot);
644 std::vector<double> vxbins = GetBinning(pdf_lowenergy->GetXaxis(),
false);
645 std::vector<double> vxbins2 = GetBinning(pdf_highenergy->GetXaxis());
646 vxbins.insert(vxbins.end(), vxbins2.begin(), vxbins2.end());
649 double* xbins =
new double[vxbins.size()];
651 TH1* pdf_energy =
new TH1D(
"pdf_energy",
"pdf_energy", vxbins.size()-1, xbins);
653 for(ibin = 1; ibin<=pdf_lowenergy->GetNbinsX(); ibin++, ibin2++){
654 double content = pdf_lowenergy->GetBinContent(ibin);
655 if(ibin == 1) content = content - 0.00001;
656 pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), content);
658 for(ibin = 1; ibin<=pdf_highenergy->GetNbinsX(); ibin++, ibin2++){
659 pdf_energy->Fill(pdf_energy->GetBinCenter(ibin2), pdf_highenergy->GetBinContent(ibin));
663 std::ostringstream Clonestr;
664 Clonestr <<
"pdf_energy_"<<i;
665 TH1* pdf_energy_noneg = (TH1D*) pdf_energy->Clone( Clonestr.str().c_str() );
666 pdf_energy_noneg->Reset();
671 for(ibin = 1; ibin<=pdf_energy->GetNbinsX(); ibin++){
672 double newPD = pdf_energy->GetBinContent(ibin);
673 double probDiff = newPD - lastPD;
675 if(ibin!=pdf_energy->GetNbinsX()){
681 else PDF += probDiff;
683 for(
int iskip=0; iskip <= nSkip; iskip++) pdf_energy_noneg->Fill(pdf_energy_noneg->GetBinCenter(ibin-iskip), PDF);
690 if(fSetWrite) pdf_energy_noneg->Write();
691 m_PDFmap->insert(std::make_pair(-thetalow,pdf_energy_noneg));
697 delete pdf_lowenergy;
698 delete pdf_highenergy;
701 std::cout <<
"\r===> " << 100.0*double(i)/double(fThetaBins) <<
"% complete... " << std::endl;
703 std::cout <<
"finished the energy pdfs." << std::endl;
711 double GaisserParam::GaisserFlux(
double e,
double theta){
713 double ct = cos(theta);
721 double c1 = sqrt(1.-(1.-pow(ct,2.0))/pow( (1.+32./6370.) ,2.0));
722 double deltae = 2.06e-3 * (1030. / c1 - 120.);
723 double em = e + deltae/2.;
724 double e1 = e + deltae;
725 double pdec = pow( (120. / (1030. / c1)), (1.04 / c1 / em));
726 di=A*pow(e1,-gamma)*(1./(1.+1.1*e1*c1/115.) + 0.054/(1.+1.1*e1*c1/850.) + rc)*pdec;
732 double gamma2 = 1.29;
733 double ct_star = sqrt( (pow(ct,2) + 0.102573*0.102573 - 0.068287*pow(ct,0.958633)
734 + 0.0407253*pow(ct,0.817285) )/(1.0 + 0.102573*0.102573 - 0.068287 + 0.0407253) );
735 double eMod = e*(1.0+C/(e*pow(ct_star,gamma2)));
736 di=A*pow(eMod,-gamma)*(1./(1.+1.1*e*ct_star/115.) + 0.054/(1.+1.1*e*ct_star/850.));
743 double GaisserParam::GaisserMuonFlux_Integrand(Double_t *
x, Double_t*){
746 double flux = 2.0*M_PI*sin(x[1])*GaisserFlux(x[0],x[1]);
752 std::vector<double> GaisserParam::GetBinning(
const TAxis* axis,
bool finalEdge){
753 std::vector<double> vbins;
754 for(
int ibin=1; ibin<=axis->GetNbins()+1; ibin++){
755 if(ibin<=axis->GetNbins()) vbins.push_back(axis->GetBinLowEdge(ibin));
756 else if(finalEdge) vbins.push_back(axis->GetBinLowEdge(ibin) + axis->GetBinWidth(ibin));
762 void GaisserParam::ResetMap(){
763 if(m_thetaHist)
delete m_thetaHist;
765 for(
dhist_Map_it mapit=m_PDFmap->begin(); mapit!=m_PDFmap->end(); mapit++){
766 if(mapit->second)
delete mapit->second;
770 std::cout <<
"Reset PDFmap and thetaHist..." << std::endl;
783
double fEpsilon
Minimum integration sum....
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
double fThetamax
Maximum theta.
void SetOrigin(simb::Origin_t origin)
module to produce single or multiple specified particles in the detector
double fYInput
Max Y position.
int fThetaBins
Number of theta Bins.
double fEmid
Energy to go from low to high (GeV)
bool fSetReWrite
Whether to ReWrite pdfs.
art::ProductID put(std::unique_ptr< PROD > &&)
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
void Add(simb::MCParticle &part)
std::string fInputDir
Input Directory.
void CryostatBoundaries(double *boundaries, geo::CryostatID const &cid) const
Returns the boundaries of the specified cryostat.
int fEBinsLow
Number of low energy Bins.
ProductID put(std::unique_ptr< PROD > &&product)
base_engine_t & getEngine() const
#define DEFINE_ART_MODULE(klass)
std::map< double, TH1 * > dhist_Map
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
single particles thrown at the detector
T get(std::string const &key) const
double fEmin
Minimum Kinetic Energy (GeV)
double fSigmaT
Variation in t position (ns)
bool fSetParam
Which version of Gaissers Param.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
double fEmax
Maximum Kinetic Energy (GeV)
double fXHalfRange
Max X position.
T * make(ARGS...args) const
int fEBinsHigh
Number of high energy Bins.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
bool fSetRead
Whether to Read.
double fThetamin
Minimum theta.
double GaisserMuonFlux_Integrand(Double_t *x, Double_t *par)
int fTDist
How to distribute t (gaus, or uniform)
Event generator information.
double fT0
Central t position (ns) in world coordinates.
std::map< double, TH1 * >::iterator dhist_Map_it
Namespace collecting geometry-related classes utilities.
Event Generation using GENIE, cosmics or single particles.
bool fSetWrite
Whether to Write.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
double fZHalfRange
Max Z position.