10 #include "art/Framework/Core/EDProducer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/SubRun.h"
17 #include "fhiclcpp/ParameterSet.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
23 #include "cetlib/pow.h"
25 #include "CLHEP/Random/RandFlat.h"
26 #include "CLHEP/Random/RandGauss.h"
27 #include "CLHEP/Random/RandGeneral.h"
30 #include "nurandom/RandomUtils/NuRandomService.h"
36 #include "nusimdata/SimulationBase/MCTruth.h"
37 #include "nusimdata/SimulationBase/MCParticle.h"
39 #include "TLorentzVector.h"
40 #include "TDatabasePDG.h"
43 std::vector<int >
pdg;
68 void produce(art::Event &
e)
override;
70 void beginRun(art::Run& run)
override;
76 const double x,
const double y,
const double z);
88 void abort(
const std::string
msg)
const;
106 std::vector<std::vector<unsigned short> >
_tpc_v;
118 std::cerr <<
"\033[93m" << msg.c_str() <<
"\033[00m" << std::endl;
119 throw std::exception();
127 , fFlatEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*
this,
"HepJamesRandom",
"GenRain"))
141 const int nbins(100);
142 double parent[nbins];
143 for (
size_t idx = 0; idx < nbins; ++idx) {
145 parent[idx] = cet::square(((
float) idx)/nbins);
149 produces< std::vector<simb::MCTruth> >();
150 produces< sumdata::RunData, art::InRun >();
152 _debug = p.get<
unsigned short>(
"DebugMode",0);
154 _t0 = p.get<
double>(
"G4Time");
155 _t0_sigma = p.get<
double>(
"G4TimeJitter");
156 if(_t0_sigma < 0) this->
abort(
"Cannot have a negative value for G4 time jitter");
162 _tpc_v = p.get<std::vector<std::vector<unsigned short> > >(
"TPCRange");
163 auto const xrange = p.get<std::vector<double> > (
"XRange");
164 auto const yrange = p.get<std::vector<double> > (
"YRange");
165 auto const zrange = p.get<std::vector<double> > (
"ZRange");
166 auto const part_cfg = p.get<fhicl::ParameterSet>(
"ParticleParameter");
169 auto const pdg_v = part_cfg.get<std::vector<std::vector<int> > > (
"PDGCode");
170 auto const minmult_v = part_cfg.get<std::vector<unsigned short> > (
"MinMulti");
171 auto const maxmult_v = part_cfg.get<std::vector<unsigned short> > (
"MaxMulti");
172 auto const weight_v = part_cfg.get<std::vector<double> > (
"ProbWeight");
174 auto kerange_v = part_cfg.get<std::vector<std::vector<double> > > (
"KERange");
175 auto momrange_v = part_cfg.get<std::vector<std::vector<double> > > (
"MomRange");
177 if( (kerange_v.empty() && momrange_v.empty()) ||
178 (!kerange_v.empty() && !momrange_v.empty()) ) {
179 this->
abort(
"Only one of KERange or MomRange must be empty!");
182 bool use_mom =
false;
183 if(kerange_v.empty()){
184 kerange_v = momrange_v;
188 if( pdg_v.size() != kerange_v.size() ||
189 pdg_v.size() != minmult_v.size() ||
190 pdg_v.size() != maxmult_v.size() ||
191 pdg_v.size() != weight_v.size() )
192 this->
abort(
"configuration parameters have incompatible lengths!");
195 for(
auto const&
r : pdg_v ) {
if(
r.empty() ) this->
abort(
"PDG code not given!"); }
196 for(
auto const&
r : kerange_v) {
if(
r.size()!=2) this->
abort(
"Incompatible legnth @ KE vector!"); }
198 for(
size_t idx=0; idx<minmult_v.size(); ++idx) {
199 if(minmult_v[idx] > maxmult_v[idx]) this->
abort(
"Particle MinMulti > Particle MaxMulti!");
200 if(minmult_v[idx] > _multi_max) this->
abort(
"Particle MinMulti > overall MultiMax!");
204 if(_multi_max <
_multi_min) this->
abort(
"Overall MultiMax <= overall MultiMin!");
206 if(!xrange.empty() && xrange.size() >2) this->
abort(
"Incompatible legnth @ X vector!" );
207 if(!yrange.empty() && yrange.size() >2) this->
abort(
"Incompatible legnth @ Y vector!" );
208 if(!zrange.empty() && zrange.size() >2) this->
abort(
"Incompatible legnth @ Z vector!" );
211 double xmin,xmax,ymin,ymax,zmin,zmax;
212 xmin = ymin = zmin = 1.e20;
213 xmax = ymax = zmax = -1.e20;
215 auto geop = lar::providerFrom<geo::Geometry>();
216 for(
auto const& tpc_id : _tpc_v) {
217 assert(tpc_id.size() == 2);
218 size_t cid = tpc_id[0];
219 size_t tid = tpc_id[1];
220 auto const& cryostat = geop->Cryostat(cid);
221 assert(cryostat.HasTPC(tid));
223 auto const& tpc = cryostat.TPC(tid);
224 auto const& tpcabox = tpc.ActiveBoundingBox();
225 xmin = std::min(tpcabox.MinX(),
xmin);
226 ymin = std::min(tpcabox.MinY(), ymin);
227 zmin = std::min(tpcabox.MinZ(), zmin);
228 xmax = std::max(tpcabox.MaxX(), xmax);
229 ymax = std::max(tpcabox.MaxY(), ymax);
230 zmax = std::max(tpcabox.MaxZ(), zmax);
233 std::cout <<
"Using Cryostat " << tpc_id[0] <<
" TPC " << tpc_id[1]
234 <<
" ... X " << xmin <<
" => " << xmax
235 <<
" ... Y " << ymin <<
" => " << ymax
236 <<
" ... Z " << zmin <<
" => " << zmax
245 if(xrange.size()==2) {
_xrange[0] = xrange[0];
_xrange[1] = xrange[1]; }
246 if(yrange.size()==2) {
_yrange[0] = yrange[0];
_yrange[1] = yrange[1]; }
247 if(zrange.size()==2) {
_zrange[0] = zrange[0];
_zrange[1] = zrange[1]; }
250 _xrange[1] = xmax - _xrange[1];
252 _yrange[1] = ymax - _yrange[1];
254 _zrange[1] = zmax - _zrange[1];
257 assert(_xrange[0] <= _xrange[1]);
258 assert(_yrange[0] <= _yrange[1]);
259 assert(_zrange[0] <= _zrange[1]);
262 std::cout<<
"Particle generation world boundaries..."<<std::endl
263 <<
"X " << _xrange[0] <<
" => " << _xrange[1] << std::endl
264 <<
"Y " << _yrange[0] <<
" => " << _yrange[1] << std::endl
265 <<
"Z " << _zrange[0] <<
" => " << _zrange[1] << std::endl;
271 auto db = TDatabasePDG::Instance();
272 bool direct_inward = p.get<
bool>(
"DirectInward",
true);
273 if (_cosmic_distribution && direct_inward) {
274 std::cout <<
"Cannot satisfy both CosmicDistribution and Inward Directioning at the same time" << std::endl;
275 throw std::exception();
277 for(
size_t idx=0; idx<pdg_v.size(); ++idx) {
278 auto const&
pdg = pdg_v[idx];
279 auto const& kerange = kerange_v[idx];
287 param.
multi[0] = minmult_v[idx];
288 param.
multi[1] = maxmult_v[idx];
289 param.
weight = weight_v[idx];
290 for(
size_t i=0; i<
pdg.size(); ++i)
291 param.
mass[i] =
db->GetParticle(param.
pdg[i])->Mass();
294 if(kerange[0]<0 || kerange[1]<0)
295 this->
abort(
"You provided negative energy? Fuck off Mr. Trump.");
304 << (param.
use_mom ?
" KE range ....... " :
" Mom range ....... ")
305 << param.
kerange[0] <<
" => " << param.
kerange[1] <<
" MeV" << std::endl
316 art::ServiceHandle<geo::Geometry> geo;
318 std::unique_ptr<sumdata::RunData> runData(
new sumdata::RunData(geo->DetectorName()));
320 run.put(std::move(runData));
327 std::vector<size_t> result;
328 std::vector<size_t> gen_count_v(
_param_v.size(),0);
329 std::vector<double> weight_v(
_param_v.size(),0);
330 for(
size_t idx=0; idx<
_param_v.size(); ++idx)
331 weight_v[idx] =
_param_v[idx].weight;
337 double total_weight = 0;
338 for(
auto const& v : weight_v) total_weight += v;
344 for(idx = 0; idx < weight_v.size(); ++idx) {
345 rval -= weight_v[idx];
350 result.push_back(idx);
353 gen_count_v[idx] += 1;
354 if(gen_count_v[idx] >=
_param_v[idx].multi[1])
369 std::cout <<
"Generating a rain particle at ("
370 << x <<
"," << y <<
"," << z <<
")" << std::endl;
380 double sintheta = sqrt(1 - costheta * costheta);
381 pz = cos(phi) * sintheta;
382 px = sin(phi) * sintheta;
388 double p = std::hypot(px, py, pz);
394 std::array<double, 3U> result = {
px,
py, pz};
399 const double x,
const double y,
const double z) {
401 double tot_energy = 0;
407 double mom_mag = sqrt(cet::square(tot_energy) - cet::square(mass));
419 std::cout<<
"No inward directioning..."<<std::endl;
421 px = p[0]; py = p[1]; pz = p[2];
423 double sign_x = ( (x -
_xrange[0]) < (
_xrange[1] - x) ? 1.0 : -1.0 );
424 double sign_y = ( (y -
_yrange[0]) < (
_yrange[1] - y) ? 1.0 : -1.0 );
425 double sign_z = ( (z -
_zrange[0]) < (
_zrange[1] - z) ? 1.0 : -1.0 );
428 std::cout<<
"Generating XYZ direction sign for a particle at (" << x <<
"," << y <<
"," << z <<
")" << std::endl
429 <<
"X: " <<
_xrange[0] <<
" => " <<
_xrange[1] <<
" ... " << sign_x << std::endl
430 <<
"Y: " <<
_yrange[0] <<
" => " <<
_yrange[1] <<
" ... " << sign_y << std::endl
431 <<
"Z: " <<
_zrange[0] <<
" => " <<
_zrange[1] <<
" ... " << sign_z << std::endl
437 px = p[0]; py = p[1]; pz = p[2];
438 if( (px * sign_x) >= 0. &&
439 (py * sign_y) >= 0. &&
440 (pz * sign_z) >= 0. )
448 std::cout <<
" Direction : (" << px <<
"," << py <<
"," << pz <<
")" << std::endl
449 <<
" Momentum : " << mom_mag <<
" [MeV/c]" << std::endl
450 <<
" Energy : " << tot_energy <<
" [MeV/c^2]" << std::endl;
461 std::unique_ptr< std::vector<simb::MCTruth> > mctArray(
new std::vector<simb::MCTruth>);
467 std::vector<simb::MCParticle> part_v;
471 std::cout <<
"Generating" << param_idx_v.size() <<
" particles..." << std::endl;
473 for(
size_t idx=0; idx<param_idx_v.size(); ++idx) {
474 auto const& param =
_param_v[param_idx_v[idx]];
477 size_t pdg_index = (size_t)(
fFlatRandom->fire(0,param.pdg.size()-1.e-10));
478 auto const&
pdg = param.pdg[pdg_index];
479 auto const&
mass = param.mass[pdg_index];
484 TLorentzVector pos(x,y,z,g4_time);
485 std::cout<<
"Generating momentum..."<<std::endl;
488 TLorentzVector mom(px,py,pz,sqrt(cet::square(px)+cet::square(py)+cet::square(pz)+cet::square(
mass)));
489 simb::MCParticle part(part_v.size(),
pdg,
"primary", 0,
mass, 1);
490 part.AddTrajectoryPoint(pos,mom);
491 part_v.emplace_back(std::move(part));
494 if(
_debug)
std::cout <<
"Total number particles: " << mct.NParticles() << std::endl;
512 for(
auto& part : part_v)
515 mctArray->push_back(mct);
517 e.put(std::move(mctArray));
process_name opflash particleana ie ie ie z
Utilities related to art service access.
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
CLHEP::HepRandomEngine & fFlatEngine
std::array< double, 2 > _xrange
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
process_name opflash particleana ie ie y
std::array< double, 3U > extractDirection() const
MultiPartRain & operator=(MultiPartRain const &)=delete
void produce(art::Event &e) override
void GenPosition(double &x, double &y, double &z)
std::array< double, 2 > _zrange
std::vector< PartGenParam > _param_v
void GenMomentum(const PartGenParam ¶m, const double &mass, double &px, double &py, double &pz, const double x, const double y, const double z)
std::unique_ptr< CLHEP::RandFlat > fFlatRandom
void beginRun(art::Run &run) override
std::array< double, 2 > _yrange
process_name physics producers generator physics producers generator physics producers generator py
MultiPartRain(fhicl::ParameterSet const &p)
std::vector< double > mass
constexpr T pi()
Returns the constant pi (up to 35 decimal digits of precision)
std::array< double, 2 > kerange
std::unique_ptr< CLHEP::RandGeneral > fCosmicAngleRandom
Collection of Physical constants used in LArSoft.
height to which particles are projected pnfs larsoft persistent physics cosmics Fermilab CORSIKA standard He_showers_ * db
std::unique_ptr< CLHEP::RandGauss > fNormalRandom
bool _cosmic_distribution
std::array< size_t, 2 > multi
void abort(const std::string msg) const
std::vector< size_t > GenParticles() const
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::vector< std::vector< unsigned short > > _tpc_v