9 #include "TDatabasePDG.h"
14 #include "art/Framework/Core/EDProducer.h"
15 #include "art/Framework/Core/ModuleMacros.h"
16 #include "art/Framework/Principal/Event.h"
17 #include "art/Framework/Principal/Run.h"
18 #include "fhiclcpp/ParameterSet.h"
19 #include "art/Framework/Services/Registry/ServiceHandle.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
23 #include "nurandom/RandomUtils/NuRandomService.h"
26 #include "nusimdata/SimulationBase/MCTruth.h"
27 #include "nusimdata/SimulationBase/MCParticle.h"
32 #include "CLHEP/Random/RandFlat.h"
33 #include "CLHEP/Random/RandPoissonQ.h"
223 explicit CORSIKAGen(fhicl::ParameterSet
const& pset);
231 void openDBs(std::string
const& module_label);
235 double wrapvar(
const double var,
const double low,
const double high);
236 double wrapvarBoxNo(
const double var,
const double low,
const double high,
int& boxno);
293 fProjectToHeight(
p.get<
double >(
"ProjectToHeight",0.)),
294 fShowerInputFiles(
p.get< std::vector< std::string > >(
"ShowerInputFiles")),
295 fShowerCopyType(
p.get< std::string >(
"ShowerCopyType",
"IFDH")),
296 fShowerFluxConstants(
p.get< std::vector< double > >(
"ShowerFluxConstants")),
297 fSampleTime(
p.get<
double >(
"SampleTime",0.)),
298 fToffset(
p.get<
double >(
"TimeOffset",0.)),
299 fBuffBox(
p.get< std::vector< double > >(
"BufferBox",{0.0, 0.0, 0.0, 0.0, 0.0, 0.0})),
302 fGenEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*
this,
"HepJamesRandom",
"gen",
p, {
"Seed",
"SeedGenerator"})),
303 fPoisEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*
this,
"HepJamesRandom",
"pois",
p,
"SeedPoisson"))
305 if(fShowerInputFiles.size() != fShowerFluxConstants.size() || fShowerInputFiles.size()==0 || fShowerFluxConstants.size()==0)
306 throw cet::exception(
"CORSIKAGen") <<
"ShowerInputFiles and ShowerFluxConstants have different or invalid sizes!"<<
"\n";
309 if(fSampleTime==0.)
throw cet::exception(
"CORSIKAGen") <<
"SampleTime not set!";
311 if(fProjectToHeight==0.) mf::LogInfo(
"CORSIKAGen")<<
"Using 0. for fProjectToHeight!"
316 this->
openDBs(
p.get<std::string>(
"module_label"));
320 produces< std::vector<simb::MCTruth> >();
325 CORSIKAGen::~CORSIKAGen(){
327 sqlite3_close(fdb[i]);
334 const double indxyz[],
345 const double dxyz[3]={-indxyz[0],-indxyz[1],-indxyz[2]};
351 if (dxyz[0] > 0.0) { dx = (xhi-xyz[0])/dxyz[0]; }
352 else if (dxyz[0] < 0.0) { dx = (xlo-xyz[0])/dxyz[0]; }
353 if (dxyz[1] > 0.0) { dy = (yhi-xyz[1])/dxyz[1]; }
354 else if (dxyz[1] < 0.0) { dy = (ylo-xyz[1])/dxyz[1]; }
355 if (dxyz[2] > 0.0) { dz = (zhi-xyz[2])/dxyz[2]; }
356 else if (dxyz[2] < 0.0) { dz = (zlo-xyz[2])/dxyz[2]; }
361 if (dx < dy && dx < dz) d = dx;
362 else if (dy < dz && dy < dx) d = dy;
363 else if (dz < dx && dz < dy) d = dz;
366 for (
int i = 0; i < 3; ++i) {
367 xyzout[i] = xyz[i] + dxyz[i]*d;
379 if ( ! fIFDH ) fIFDH =
new ifdh_ns::ifdh;
380 const char* ifdh_debug_env = std::getenv(
"IFDH_DEBUG_LEVEL");
381 if ( ifdh_debug_env ) {
382 mf::LogInfo(
"CORSIKAGen") <<
"IFDH_DEBUG_LEVEL: " << ifdh_debug_env<<
"\n";
383 fIFDH->set_debug(ifdh_debug_env);
390 std::vector<std::pair<std::string,long>> selectedflist;
392 if(fShowerInputFiles[i].find(
"*")==std::string::npos){
394 selectedflist.push_back(std::make_pair(fShowerInputFiles[i],0));
395 mf::LogInfo(
"CorsikaGen") <<
"Selected"<<selectedflist.back().first<<
"\n";
399 std::vector<std::pair<std::string,long>> flist;
400 std::string
path(gSystem->DirName(fShowerInputFiles[i].c_str()));
401 std::string
pattern(gSystem->BaseName(fShowerInputFiles[i].c_str()));
402 flist = fIFDH->findMatchingFiles(path,pattern);
403 unsigned int selIndex=-1;
406 }
else if(flist.size()>1){
407 selIndex= (
unsigned int) (flat()*(flist.size()-1)+0.5);
409 throw cet::exception(
"CORSIKAGen") <<
"No files returned for path:pattern: "<<path<<
":"<<pattern<<std::endl;
411 selectedflist.push_back(flist[selIndex]);
412 mf::LogInfo(
"CorsikaGen") <<
"For "<<fShowerInputFiles[i]<<
":"<<pattern
413 <<
"\nFound "<< flist.size() <<
" candidate files"
414 <<
"\nChoosing file number "<< selIndex <<
"\n"
415 <<
"\nSelected "<<selectedflist.back().first<<
"\n";
421 std::vector<std::string> locallist;
422 for(
unsigned int i=0; i<selectedflist.size(); i++){
423 mf::LogInfo(
"CorsikaGen")
424 <<
"Fetching: "<<selectedflist[i].first<<
" "<<selectedflist[i].second<<
"\n";
425 if (fShowerCopyType ==
"IFDH") {
426 std::string fetchedfile(fIFDH->fetchInput(selectedflist[i].first));
427 MF_LOG_DEBUG(
"CorsikaGen") <<
"Fetched; local path: "<<fetchedfile <<
"; copy type: IFDH";
428 locallist.push_back(fetchedfile);
430 else if (fShowerCopyType ==
"DIRECT") {
431 std::string fetchedfile(selectedflist[i].
first);
432 MF_LOG_DEBUG(
"CorsikaGen") <<
"Fetched; local path: "<<fetchedfile <<
"; copy type: DIRECT";
433 locallist.push_back(fetchedfile);
435 else throw cet::exception(
"CORSIKAGen") <<
"Error copying shower db: ShowerCopyType must be \"IFDH\" or \"DIRECT\"\n";
439 for(
unsigned int i=0; i<locallist.size(); i++){
441 int res=sqlite3_open(locallist[i].c_str(),&fdb[i]);
443 throw cet::exception(
"CORSIKAGen") <<
"Error opening db: (" <<locallist[i].c_str()<<
") ("<<res<<
"): " << sqlite3_errmsg(fdb[i]) <<
"; memory used:<<"<<sqlite3_memory_used()<<
"/"<<sqlite3_memory_highwater(0)<<
"\n";
445 mf::LogInfo(
"CORSIKAGen")<<
"Attached db "<< locallist[i]<<
"\n";
449 double CORSIKAGen::wrapvar(
const double var,
const double low,
const double high){
451 return (var - (high - low) * floor(var/(high-low))) +
low;
454 double CORSIKAGen::wrapvarBoxNo(
const double var,
const double low,
const double high,
int& boxno){
456 boxno=int(floor(var/(high-low)));
457 return (var - (high - low) * floor(var/(high-low))) +
low;
463 sqlite3_stmt *statement;
464 const std::string kStatement(
"select min(t) from particles");
469 if ( sqlite3_prepare(fdb[i], kStatement.c_str(), -1, &statement, 0 ) == SQLITE_OK ){
471 res = sqlite3_step(statement);
472 if ( res == SQLITE_ROW ){
473 t=sqlite3_column_double(statement,0);
474 mf::LogInfo(
"CORSIKAGen")<<
"For showers input "<< i<<
" found particles.min(t)="<<t<<
"\n";
475 if (i==0 || t<fToffset_corsika) fToffset_corsika=t;
477 throw cet::exception(
"CORSIKAGen") <<
"Unexpected sqlite3_step return value: (" <<res<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
480 throw cet::exception(
"CORSIKAGen") <<
"Error preparing statement: (" <<kStatement<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
484 mf::LogInfo(
"CORSIKAGen")<<
"Found corsika timeoffset [ns]: "<< fToffset_corsika<<
"\n";
497 art::ServiceHandle<geo::Geometry const> geom;
498 for(
unsigned int c = 0; c < geom->Ncryostats(); ++c){
499 double bounds[6] = {0.};
500 geom->CryostatBoundaries(bounds, c);
501 for (
unsigned int bnd = 0; bnd<6; bnd++){
502 mf::LogVerbatim(
"CORSIKAGen")<<
"Cryo Boundary: "<<bnd<<
"="<<bounds[bnd]<<
" ( + Buffer="<<fBuffBox[bnd]<<
")\n";
503 if(fabs(bounds[bnd])>fabs(fShowerBounds[bnd])){
504 fShowerBounds[bnd]=bounds[bnd];
514 double showersArea=(fShowerBounds[1]/100-fShowerBounds[0]/100)*(fShowerBounds[5]/100-fShowerBounds[4]/100);
516 mf::LogInfo(
"CORSIKAGen")
517 <<
"Area extended by : "<<fShowerAreaExtension
518 <<
"\nShowers to be distributed betweeen: x="<<fShowerBounds[0]<<
","<<fShowerBounds[1]
519 <<
" & z="<<fShowerBounds[4]<<
","<<fShowerBounds[5]
520 <<
"\nShowers to be distributed with random XZ shift: "<<
fRandomXZShift<<
" cm"
521 <<
"\nShowers to be distributed over area: "<<showersArea<<
" m^2"
522 <<
"\nShowers to be distributed over time: "<<fSampleTime<<
" s"
523 <<
"\nShowers to be distributed with time offset: "<<fToffset<<
" s"
524 <<
"\nShowers to be distributed at y: "<<fShowerBounds[3]<<
" cm"
528 sqlite3_stmt *statement;
529 const std::string kStatement(
"select erange_high,erange_low,eslope,nshow from input");
530 double upperLimitOfEnergyRange=0.,lowerLimitOfEnergyRange=0.,energySlope=0.,oneMinusGamma=0.,EiToOneMinusGamma=0.,EfToOneMinusGamma=0.;
535 if ( sqlite3_prepare(fdb[i], kStatement.c_str(), -1, &statement, 0 ) == SQLITE_OK ){
537 res = sqlite3_step(statement);
538 if ( res == SQLITE_ROW ){
539 upperLimitOfEnergyRange=sqlite3_column_double(statement,0);
540 lowerLimitOfEnergyRange=sqlite3_column_double(statement,1);
541 energySlope = sqlite3_column_double(statement,2);
542 fMaxShowers.push_back(sqlite3_column_int(statement,3));
543 oneMinusGamma = 1 + energySlope;
544 EiToOneMinusGamma = pow(lowerLimitOfEnergyRange, oneMinusGamma);
545 EfToOneMinusGamma = pow(upperLimitOfEnergyRange, oneMinusGamma);
546 mf::LogVerbatim(
"CORSIKAGen")<<
"For showers input "<< i<<
" found e_hi="<<upperLimitOfEnergyRange<<
", e_lo="<<lowerLimitOfEnergyRange<<
", slope="<<energySlope<<
", k="<<fShowerFluxConstants[i]<<
"\n";
548 throw cet::exception(
"CORSIKAGen") <<
"Unexpected sqlite3_step return value: (" <<res<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
551 throw cet::exception(
"CORSIKAGen") <<
"Error preparing statement: (" <<kStatement<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
555 double NShowers=( M_PI * showersArea * fShowerFluxConstants[i] * (EfToOneMinusGamma - EiToOneMinusGamma) / oneMinusGamma )*fSampleTime;
556 fNShowersPerEvent.push_back(NShowers);
557 mf::LogVerbatim(
"CORSIKAGen")<<
"For showers input "<< i
558 <<
" the number of showers per event is "<<(int)NShowers<<
"\n";
562 void CORSIKAGen::GetSample(simb::MCTruth& mctruth){
575 static TDatabasePDG* pdgt = TDatabasePDG::Instance();
578 sqlite3_stmt *statement;
579 const TString kStatement(
"select shower,pdg,px,py,pz,x,z,t,e from particles where shower in (select id from showers ORDER BY substr(id*%f,length(id)+2) limit %d) ORDER BY substr(shower*%f,length(shower)+2)");
582 CLHEP::RandPoissonQ randpois(fPoisEngine);
585 art::ServiceHandle<geo::Geometry const> geom;
589 geom->WorldBox(&x1, &x2, &y1, &y2, &z1, &z2);
593 double fBoxDelta=1.e-5;
597 y2 = fProjectToHeight;
607 double px,
py,
pz,
x,
z,tParticleTime,etot,showerTime=0.,showerTimex=0.,showerTimez=0.,showerXOffset=0.,showerZOffset=0.,t;
609 nShowerCntr=randpois.fire(fNShowersPerEvent[i]);
610 mf::LogInfo(
"CORSIKAGEN") <<
" Shower input " << i <<
" with mean " << fNShowersPerEvent[i] <<
" generating " << nShowerCntr;
612 while(nShowerCntr>0){
614 if(nShowerCntr>fMaxShowers[i]){
615 nShowerQry=fMaxShowers[i];
617 nShowerQry=nShowerCntr;
620 double thisrnd=flat();
621 TString kthisStatement=TString::Format(kStatement.Data(),thisrnd,nShowerQry,thisrnd);
622 MF_LOG_DEBUG(
"CORSIKAGen")<<
"Executing: "<<kthisStatement;
623 if ( sqlite3_prepare(fdb[i], kthisStatement.Data(), -1, &statement, 0 ) == SQLITE_OK ){
627 res = sqlite3_step(statement);
628 if ( res == SQLITE_ROW ){
641 shower=sqlite3_column_int(statement,0);
642 if(shower!=lastShower){
644 showerTime=1e9*(flat()*fSampleTime);
645 showerTimex=1e9*(flat()*fSampleTime);
646 showerTimez=1e9*(flat()*fSampleTime);
651 pdg=sqlite3_column_int(statement,1);
654 TParticlePDG* pdgp = pdgt->GetParticle(pdg);
655 if (pdgp) m = pdgp->Mass();
659 px=sqlite3_column_double(statement,4);
660 py=sqlite3_column_double(statement,3);
661 pz=-sqlite3_column_double(statement,2);
662 etot=sqlite3_column_double(statement,8);
665 int boxnoX=0,boxnoZ=0;
666 x=wrapvarBoxNo(sqlite3_column_double(statement,6)+showerXOffset,fShowerBounds[0],fShowerBounds[1],boxnoX);
667 z=wrapvarBoxNo(-sqlite3_column_double(statement,5)+showerZOffset,fShowerBounds[4],fShowerBounds[5],boxnoZ);
668 tParticleTime=sqlite3_column_double(statement,7);
674 t=tParticleTime+showerTime+(1e9*fToffset)-fToffset_corsika + showerTimex*boxnoX + showerTimez*boxnoZ;
676 t=wrapvar(t,(1e9*fToffset),1e9*(fToffset+fSampleTime));
678 simb::MCParticle
p(ntotalCtr,pdg,
"primary",-200,m,1);
690 double x0[3]={
x,fShowerBounds[3],z};
691 double dx[3]={
px,
py,pz};
694 TLorentzVector pos(xyzo[0],xyzo[1],xyzo[2],t);
695 TLorentzVector mom(px,py,pz,etot);
696 p.AddTrajectoryPoint(pos,mom);
700 }
else if ( res == SQLITE_DONE ){
703 throw cet::exception(
"CORSIKAGen") <<
"Unexpected sqlite3_step return value: (" <<res<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
707 throw cet::exception(
"CORSIKAGen") <<
"Error preparing statement: (" <<kthisStatement<<
"); "<<
"ERROR:"<<sqlite3_errmsg(fdb[i])<<
"\n";
709 nShowerCntr=nShowerCntr-nShowerQry;
714 void CORSIKAGen::beginRun(art::Run& run)
716 art::ServiceHandle<geo::Geometry const> geo;
717 run.put(std::make_unique<sumdata::RunData>(geo->DetectorName()));
720 void CORSIKAGen::produce(art::Event&
evt){
721 std::unique_ptr< std::vector<simb::MCTruth> > truthcol(
new std::vector<simb::MCTruth>);
723 art::ServiceHandle<geo::Geometry const> geom;
728 simb::MCTruth pretruth;
730 mf::LogInfo(
"CORSIKAGen")<<
"GetSample number of particles returned: "<<pretruth.NParticles()<<
"\n";
732 for(
int i = 0; i < pretruth.NParticles(); ++i){
733 simb::MCParticle particle = pretruth.GetParticle(i);
734 const TLorentzVector& v4 = particle.Position();
735 const TLorentzVector& p4 = particle.Momentum();
736 double x0[3] = {v4.X(), v4.Y(), v4.Z() };
737 double dx[3] = {p4.Px(), p4.Py(), p4.Pz()};
741 for(
unsigned int c = 0; c < geom->Ncryostats(); ++c){
742 double bounds[6] = {0.};
743 geom->CryostatBoundaries(bounds, c);
747 for (
unsigned int cb=0; cb<6; cb++)
748 bounds[cb] = bounds[cb]+fBuffBox[cb];
751 bool intersects_cryo =
false;
752 for (
int bnd=0; bnd!=6; ++bnd) {
754 double p2[3] = {bounds[bnd], x0[1] + (dx[1]/dx[0])*(bounds[bnd] - x0[0]), x0[2] + (dx[2]/dx[0])*(bounds[bnd] - x0[0])};
755 if ( p2[1] >= bounds[2] && p2[1] <= bounds[3] &&
756 p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
757 intersects_cryo =
true;
761 else if (bnd>=2 && bnd<4) {
762 double p2[3] = {x0[0] + (dx[0]/dx[1])*(bounds[bnd] - x0[1]), bounds[bnd], x0[2] + (dx[2]/dx[1])*(bounds[bnd] - x0[1])};
763 if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
764 p2[2] >= bounds[4] && p2[2] <= bounds[5] ) {
765 intersects_cryo =
true;
770 double p2[3] = {x0[0] + (dx[0]/dx[2])*(bounds[bnd] - x0[2]), x0[1] + (dx[1]/dx[2])*(bounds[bnd] - x0[2]), bounds[bnd]};
771 if ( p2[0] >= bounds[0] && p2[0] <= bounds[1] &&
772 p2[1] >= bounds[2] && p2[1] <= bounds[3] ) {
773 intersects_cryo =
true;
779 if (intersects_cryo){
787 mf::LogInfo(
"CORSIKAGen")<<
"Number of particles from getsample crossing cryostat + bounding box: "<<truth.NParticles()<<
"\n";
789 truthcol->push_back(truth);
790 evt.put(std::move(truthcol));
800 DEFINE_ART_MODULE(CORSIKAGen)
fGenEngine(art::ServiceHandle< rndm::NuRandomService >{}->createEngine(*this,"HepJamesRandom","gen", p,{"Seed","SeedGenerator"}))
process_name opflash particleana ie ie ie z
double fToffset
Time offset of sample, defaults to zero (no offset) [s].
double wrapvar(const double var, const double low, const double high)
double fSampleTime
Duration of sample [s].
double fProjectToHeight
Height to which particles will be projected [cm].
process_name opflash particleana ie x
LArSoft interface to CORSIKA event generator.
produces< sumdata::RunData, art::InRun >()
fShowerAreaExtension(p.get< double >("ShowerAreaExtension", 0.))
ifdh_ns::ifdh * fIFDH
(optional) flux file handling
std::vector< std::string > fShowerInputFiles
Set of CORSIKA shower data files to use.
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
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
int fShowerInputs
Number of shower inputs to process from.
sqlite3 * fdb[5]
Pointers to sqlite3 database object, max of 5.
std::vector< double > fShowerFluxConstants
Set of flux constants to be associated with each shower data file.
void ProjectToBoxEdge(const double xyz[], const double dxyz[], const double xlo, const double xhi, const double ylo, const double yhi, const double zlo, const double zhi, double xyzout[])
Propagates a point back to the surface of a box.
CLHEP::HepRandomEngine & fPoisEngine
double wrapvarBoxNo(const double var, const double low, const double high, int &boxno)
std::vector< int > fMaxShowers
double fToffset_corsika
Timing offset to account for propagation time through atmosphere, populated from db.
std::string fShowerCopyType
void produce(art::Event &evt)
process_name physics producers generator physics producers generator physics producers generator py
double fRandomXZShift
Each shower will be shifted by a random amount in xz so that showers won't repeatedly sample the same...
double fShowerBounds[6]
Boundaries of area over which showers are to be distributed (x(min), x(max), unused, y, z(min), z(max) )
CORSIKAGen(fhicl::ParameterSet const &pset)
void beginRun(art::Run &run)
void ProjectToBoxEdge(const double xyz[], const double dxyz[], double xlo, double xhi, double ylo, double yhi, double zlo, double zhi, double xyzout[])
void GetSample(simb::MCTruth &)
std::vector< double > fNShowersPerEvent
Number of showers to put in each event of duration fSampleTime; one per showerinput.
CLHEP::HepRandomEngine & fGenEngine
if(fSampleTime==0.) throw cet if(fProjectToHeight==0.) mf this openDBs(p.get< std::string >("module_label"))
fRandomXZShift(p.get< double >("RandomXZShift", 0.))
void openDBs(std::string const &module_label)
double fShowerAreaExtension
Extend distribution of corsika particles in x,z by this much (e.g. 1000 will extend 10 m in -x...
art framework interface to geometry description
std::vector< double > fBuffBox
Buffer box extensions to cryostat in each direction (6 of them: x_lo,x_hi,y_lo,y_hi,z_lo,z_hi) [cm].