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"
22 #include "cetlib/pow.h"
24 #include "CLHEP/Random/RandFlat.h"
25 #include "CLHEP/Random/RandGauss.h"
27 #include "nurandom/RandomUtils/NuRandomService.h"
33 #include "nusimdata/SimulationBase/MCTruth.h"
34 #include "nusimdata/SimulationBase/MCParticle.h"
36 #include "TLorentzVector.h"
37 #include "TDatabasePDG.h"
40 std::vector<int >
pdg;
41 std::vector<double >
mass;
42 std::array <size_t, 2 >
multi;
43 std::array <double, 2 >
kerange;
64 void produce(art::Event &
e)
override;
66 void beginRun(art::Run& run)
override;
82 void abort(
const std::string
msg)
const;
97 std::vector<std::vector<unsigned short> >
_tpc_v;
109 std::cerr <<
"\033[93m" << msg.c_str() <<
"\033[00m" << std::endl;
110 throw std::exception();
118 , fFlatEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(*
this,
"HepJamesRandom",
"GenVertex"))
129 produces< std::vector<simb::MCTruth> >();
130 produces< sumdata::RunData, art::InRun >();
132 _debug = p.get<
unsigned short>(
"DebugMode",0);
134 _t0 = p.get<
double>(
"G4Time");
135 _t0_sigma = p.get<
double>(
"G4TimeJitter");
136 if(_t0_sigma < 0) this->
abort(
"Cannot have a negative value for G4 time jitter");
141 _tpc_v = p.get<std::vector<std::vector<unsigned short> > >(
"TPCRange");
142 auto const xrange = p.get<std::vector<double> > (
"XRange");
143 auto const yrange = p.get<std::vector<double> > (
"YRange");
144 auto const zrange = p.get<std::vector<double> > (
"ZRange");
146 auto const part_cfg = p.get<fhicl::ParameterSet>(
"ParticleParameter");
149 auto const pdg_v = part_cfg.get<std::vector<std::vector<int> > > (
"PDGCode");
150 auto const minmult_v = part_cfg.get<std::vector<unsigned short> > (
"MinMulti");
151 auto const maxmult_v = part_cfg.get<std::vector<unsigned short> > (
"MaxMulti");
152 auto const weight_v = part_cfg.get<std::vector<double> > (
"ProbWeight");
154 auto kerange_v = part_cfg.get<std::vector<std::vector<double> > > (
"KERange");
155 auto momrange_v = part_cfg.get<std::vector<std::vector<double> > > (
"MomRange");
157 if( (kerange_v.empty() && momrange_v.empty()) ||
158 (!kerange_v.empty() && !momrange_v.empty()) ) {
159 this->
abort(
"Only one of KERange or MomRange must be empty!");
162 bool use_mom =
false;
163 if(kerange_v.empty()){
164 kerange_v = momrange_v;
168 if( pdg_v.size() != kerange_v.size() ||
169 pdg_v.size() != minmult_v.size() ||
170 pdg_v.size() != maxmult_v.size() ||
171 pdg_v.size() != weight_v.size() )
172 this->
abort(
"configuration parameters have incompatible lengths!");
175 for(
auto const&
r : pdg_v ) {
if(
r.empty() ) this->
abort(
"PDG code not given!"); }
176 for(
auto const&
r : kerange_v) {
if(
r.size()!=2) this->
abort(
"Incompatible legnth @ KE vector!"); }
178 size_t multi_min = 0;
179 for(
size_t idx=0; idx<minmult_v.size(); ++idx) {
180 if(minmult_v[idx] > maxmult_v[idx]) this->
abort(
"Particle MinMulti > Particle MaxMulti!");
181 if(minmult_v[idx] > _multi_max) this->
abort(
"Particle MinMulti > overall MultiMax!");
182 multi_min += minmult_v[idx];
185 if(_multi_max <
_multi_min) this->
abort(
"Overall MultiMax <= overall MultiMin!");
201 if(!xrange.empty() && xrange.size() >2) this->
abort(
"Incompatible legnth @ X vector!" );
202 if(!yrange.empty() && yrange.size() >2) this->
abort(
"Incompatible legnth @ Y vector!" );
203 if(!zrange.empty() && zrange.size() >2) this->
abort(
"Incompatible legnth @ Z vector!" );
206 double xmin,xmax,ymin,ymax,zmin,zmax;
207 xmin = ymin = zmin = 1.e20;
208 xmax = ymax = zmax = -1.e20;
210 auto geop = lar::providerFrom<geo::Geometry>();
211 for(
auto const& tpc_id : _tpc_v) {
212 assert(tpc_id.size() == 2);
213 size_t cid = tpc_id[0];
214 size_t tid = tpc_id[1];
215 auto const& cryostat = geop->Cryostat(cid);
216 assert(cryostat.HasTPC(tid));
218 auto const& tpc = cryostat.TPC(tid);
219 auto const& tpcabox = tpc.ActiveBoundingBox();
220 xmin = std::min(tpcabox.MinX(),
xmin);
221 ymin = std::min(tpcabox.MinY(), ymin);
222 zmin = std::min(tpcabox.MinZ(), zmin);
223 xmax = std::max(tpcabox.MaxX(), xmax);
224 ymax = std::max(tpcabox.MaxY(), ymax);
225 zmax = std::max(tpcabox.MaxZ(), zmax);
228 std::cout <<
"Using Cryostat " << tpc_id[0] <<
" TPC " << tpc_id[1]
229 <<
" ... X " << xmin <<
" => " << xmax
230 <<
" ... Y " << ymin <<
" => " << ymax
231 <<
" ... Z " << zmin <<
" => " << zmax
240 if(xrange.size()==2) {
_xrange[0] = xrange[0];
_xrange[1] = xrange[1]; }
241 if(yrange.size()==2) {
_yrange[0] = yrange[0];
_yrange[1] = yrange[1]; }
242 if(zrange.size()==2) {
_zrange[0] = zrange[0];
_zrange[1] = zrange[1]; }
245 _xrange[1] = xmax - _xrange[1];
247 _yrange[1] = ymax - _yrange[1];
249 _zrange[1] = zmax - _zrange[1];
252 assert(_xrange[0] <= _xrange[1]);
253 assert(_yrange[0] <= _yrange[1]);
254 assert(_zrange[0] <= _zrange[1]);
257 std::cout<<
"Particle generation world boundaries..."<<std::endl
258 <<
"X " << _xrange[0] <<
" => " << _xrange[1] << std::endl
259 <<
"Y " << _yrange[0] <<
" => " << _yrange[1] << std::endl
260 <<
"Z " << _zrange[0] <<
" => " << _zrange[1] << std::endl;
266 auto db = TDatabasePDG::Instance();
267 for(
size_t idx=0; idx<pdg_v.size(); ++idx) {
268 auto const&
pdg = pdg_v[idx];
269 auto const& kerange = kerange_v[idx];
276 param.
multi[0] = minmult_v[idx];
277 param.
multi[1] = maxmult_v[idx];
278 param.
weight = weight_v[idx];
279 for(
size_t i=0; i<
pdg.size(); ++i)
280 param.
mass[i] =
db->GetParticle(param.
pdg[i])->Mass();
283 if(kerange[0]<0 || kerange[1]<0)
284 this->
abort(
"You provided negative energy? Fuck off Mr. Trump.");
293 << (param.
use_mom ?
" KE range ....... " :
" Mom range ....... ")
294 << param.
kerange[0] <<
" => " << param.
kerange[1] <<
" MeV" << std::endl
305 art::ServiceHandle<geo::Geometry> geo;
307 std::unique_ptr<sumdata::RunData> runData(
new sumdata::RunData(geo->DetectorName()));
309 run.put(std::move(runData));
316 std::vector<size_t> result;
317 std::vector<size_t> gen_count_v(
_param_v.size(),0);
322 std::vector<double> weight_v(
_param_v.size(),0);
323 for(
size_t idx=0; idx<
_param_v.size(); ++idx) {
324 weight_v[idx] =
_param_v[idx].weight;
325 for(
size_t ctr=0; ctr<
_param_v[idx].multi[0]; ++ctr) {
326 result.push_back(idx);
327 gen_count_v[idx] += 1;
330 if(gen_count_v[idx] >=
_param_v[idx].multi[1])
334 assert(num_part >= 0);
338 double total_weight = 0;
339 for(
auto const& v : weight_v) total_weight += v;
345 for(idx = 0; idx < weight_v.size(); ++idx) {
346 rval -= weight_v[idx];
351 result.push_back(idx);
354 gen_count_v[idx] += 1;
355 if(gen_count_v[idx] >=
_param_v[idx].multi[1])
371 std::cout <<
"Generating a rain particle at ("
372 << x <<
"," << y <<
"," << z <<
")" << std::endl;
409 double p = std::hypot(px, py, pz);
413 std::array<double, 3U> result = {
px,
py, pz };
419 double tot_energy = 0;
425 double mom_mag = sqrt(cet::square(tot_energy) - cet::square(mass));
437 px = p[0]; py = p[1]; pz = p[2];
440 std::cout <<
" Direction : (" << px <<
"," << py <<
"," << pz <<
")" << std::endl
441 <<
" Momentum : " << mom_mag <<
" [MeV/c]" << std::endl
442 <<
" Energy : " << tot_energy <<
" [MeV/c^2]" << std::endl;
453 std::unique_ptr< std::vector<simb::MCTruth> > mctArray(
new std::vector<simb::MCTruth>);
459 TLorentzVector pos(x,y,z,g4_time);
463 mct.SetOrigin(simb::kBeamNeutrino);
465 std::vector<simb::MCParticle> part_v;
469 std::cout <<
"Event Vertex @ (" << x <<
"," << y <<
"," << z <<
") ... " << param_idx_v.size() <<
" particles..." << std::endl;
471 for(
size_t idx=0; idx<param_idx_v.size(); ++idx) {
472 auto const& param =
_param_v[param_idx_v[idx]];
475 size_t pdg_index = (size_t)(
fFlatRandom->fire(0,param.pdg.size()-1.e-10));
476 auto const&
pdg = param.pdg[pdg_index];
477 auto const&
mass = param.mass[pdg_index];
480 TLorentzVector mom(px,py,pz,sqrt(cet::square(px)+cet::square(py)+cet::square(pz)+cet::square(
mass)));
482 simb::MCParticle part(part_v.size(),
pdg,
"primary", 0,
mass, 1);
483 part.AddTrajectoryPoint(pos,mom);
484 part_v.emplace_back(std::move(part));
487 if(
_debug)
std::cout <<
"Total number particles: " << mct.NParticles() << std::endl;
489 simb::MCParticle
nu(mct.NParticles(), 16,
"primary", mct.NParticles(), 0, 0);
494 for(
auto const& part : part_v) {
495 px += part.Momentum().Px();
496 py += part.Momentum().Py();
497 pz += part.Momentum().Pz();
498 en += part.Momentum().E();
500 TLorentzVector mom(px,py,pz,en);
501 nu.AddTrajectoryPoint(pos,mom);
504 for(
auto& part : part_v)
520 mctArray->push_back(mct);
522 e.put(std::move(mctArray));
process_name opflash particleana ie ie ie z
std::vector< std::vector< unsigned short > > _tpc_v
MultiPartVertex(fhicl::ParameterSet const &p)
MultiPartVertex & operator=(MultiPartVertex const &)=delete
Utilities related to art service access.
CLHEP::HepRandomEngine & fFlatEngine
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
std::unique_ptr< CLHEP::RandFlat > fFlatRandom
std::array< double, 2 > _xrange
std::vector< size_t > GenParticles() const
std::vector< PartGenParam > _param_v
std::array< double, 3U > extractDirection() const
void GenMomentum(const PartGenParam ¶m, const double &mass, double &px, double &py, double &pz)
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
Charged-current interactions.
process_name opflash particleana ie ie y
void GenPosition(double &x, double &y, double &z)
void beginRun(art::Run &run) override
void produce(art::Event &e) override
process_name physics producers generator physics producers generator physics producers generator py
std::array< double, 2 > _zrange
std::vector< double > mass
charged current quasi-elastic
std::array< double, 2 > kerange
void abort(const std::string msg) const
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
std::array< size_t, 2 > multi
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::array< double, 2 > _yrange