13 #include <initializer_list> 25 #include "cetlib/filesystem.h" 26 #include "cetlib/search_path.h" 27 #include "cetlib_except/exception.h" 42 #include "TDatabasePDG.h" 48 #include "CLHEP/Random/RandFlat.h" 49 #include "CLHEP/Random/RandGaussQ.h" 62 Name(
"ParticleSelectionMode"),
63 Comment(
"generate one particle, or one particle per PDG ID: " +
67 Name(
"PadOutVectors"),
68 Comment(
"if true, all per-PDG-ID quantities must contain only one value, which is then " 69 "used for all PDG IDs")};
72 Comment(
"PDG ID of the particles to be generated; this is the key " 73 "for the other options marked as \"per PDG ID\"")};
81 Comment(
"central momentum (GeV/c) to generate"),
85 Comment(
"variation in momenta (GeV/c)"),
90 Comment(
"central x position (cm) in world coordinates [per PDG ID]")};
94 Comment(
"central y position (cm) in world coordinates [per PDG ID]")};
98 Comment(
"central z position (cm) in world coordinates [per PDG ID]")};
104 Comment(
"variation (radius or RMS) in x position (cm) [per PDG ID]")};
108 Comment(
"variation (radius or RMS) in y position (cm) [per PDG ID]")};
112 Comment(
"variation (radius or RMS) in z position (cm) [per PDG ID]")};
116 Comment(
"variation (semi-interval or RMS) in time (s) [per PDG ID]")};
119 Comment(
"distribution of starting position: " +
127 Name(
"SingleVertex"),
128 Comment(
"if true, all particles are produced at the same location"),
132 Comment(
"angle from Z axis on world X-Z plane (degrees)")};
135 Comment(
"angle from Z axis on world Y-Z plane (degrees)")};
138 Comment(
"variation in angle in X-Z plane (degrees)")};
141 Comment(
"variation in angle in Y-Z plane (degrees)")};
149 Name(
"HistogramFile"),
150 Comment(
"ROOT file containing the required distributions for the generation"),
155 Comment(
"name of the histograms of momentum distributions"),
159 Name(
"ThetaXzYzHist"),
160 Comment(
"name of the histograms of angular (X-Z and Y-Z) distribution"),
165 Comment(
"override the random number generator seed")};
189 void printVecs(std::vector<std::string>
const& list);
190 bool PadVector(std::vector<double>& vec);
214 std::vector<int>
fPDG;
241 std::vector<std::unique_ptr<TH1>>
hPHist;
242 std::vector<std::unique_ptr<TH2>>
284 template <
typename OptionList>
285 static auto selectOption(std::string Option, OptionList
const& allowedOptions)
301 template <
typename OptionList>
303 OptionList
const& allowedOptions,
305 std::initializer_list<typename OptionList::value_type::first_type> exclude);
307 template <
typename OptionList>
308 static std::string
presentOptions(OptionList
const& allowedOptions,
bool printKey =
true)
314 template <
typename OptionList>
315 static std::string
optionName(
typename OptionList::value_type::first_type optionKey,
316 OptionList
const& allowedOptions,
317 std::string defName =
"<unknown>");
326 std::map<int, std::string> names;
334 std::map<int, std::string> names;
335 names[int(
kUNIF)] =
"uniform";
336 names[int(
kGAUS)] =
"Gaussian";
337 names[int(
kHIST)] =
"histograms";
346 template <
typename OptionList>
350 using key_type =
typename OptionList::value_type::first_type;
351 using tolower_type = int (*)(int);
352 auto toLower = [](
auto const& S) {
355 std::transform(S.cbegin(), S.cend(), std::back_inserter(s), (tolower_type)&std::tolower);
358 auto option = toLower(Option);
359 for (
auto const& candidate : allowedOptions) {
360 if (toLower(candidate.second) == option)
return candidate.first;
364 key_type num = std::stoi(Option, &end);
365 if (allowedOptions.count(num) && (end == Option.length()))
return num;
367 catch (std::invalid_argument
const&) {
369 throw std::runtime_error(
"Option '" + Option +
"' not supported.");
372 template <
typename OptionList>
374 OptionList
const& allowedOptions,
376 std::initializer_list<typename OptionList::value_type::first_type> exclude
382 for (
auto const& option : allowedOptions) {
383 auto const& key = option.first;
384 if (std::find(exclude.begin(), exclude.end(), key) != exclude.end())
continue;
385 if (n++ > 0) msg +=
", ";
386 msg +=
'\"' + std::string(option.second) +
'\"';
392 template <
typename OptionList>
394 OptionList
const& allowedOptions,
398 auto iOption = allowedOptions.find(optionKey);
399 return (iOption != allowedOptions.end()) ? iOption->second : defName;
413 ,
fPDG(config().PDG())
434 ,
fPHist(config().PHist())
440 if (config().Seed(seed)) {
fEngine.setSeed(seed, 0 ); }
442 produces<std::vector<simb::MCTruth>>();
454 std::vector<std::string> vlist(15);
464 vlist[9] =
"Theta0XZ";
465 vlist[10] =
"Theta0YZ";
466 vlist[11] =
"SigmaThetaXZ";
467 vlist[12] =
"SigmaThetaYZ";
469 vlist[14] =
"SigmaT";
474 if (!this->
PadVector(
fP0)) { list.append(vlist[1].append(
", \n")); }
477 if (!this->
PadVector(
fX0)) { list.append(vlist[3].append(
", \n")); }
478 if (!this->
PadVector(
fY0)) { list.append(vlist[4].append(
", \n")); }
479 if (!this->
PadVector(
fZ0)) { list.append(vlist[5].append(
", \n")); }
487 if (!this->
PadVector(
fT0)) { list.append(vlist[13].append(
", \n")); }
492 <<
"The " << list <<
"\n vector(s) defined in the fhicl files has/have " 493 <<
"a different size than the PDG vector " 494 <<
"\n and it has (they have) more than one value, " 495 <<
"\n disallowing sensible padding " 496 <<
" and/or you have set fPadOutVectors to false. \n";
501 TFile* histFile =
nullptr;
507 if (!histFile || histFile->IsZombie() || !histFile->IsOpen()) {
511 <<
"Cannot open ROOT file specified in parameter HistogramFile: \"" <<
fHistFileName 517 <<
"ROOT file specified in parameter HistogramFile: \"" <<
fHistFileName 518 <<
"\" does not exist!";
523 std::string relative_filename{
"./"};
525 if (cet::file_exists(relative_filename)) {
526 histFile =
new TFile(relative_filename.c_str());
527 if (!histFile || histFile->IsZombie() || !histFile->IsOpen()) {
531 <<
"Cannot open ROOT file found using relative path and originally specified in " 532 "parameter HistogramFile: \"" 533 << relative_filename <<
'"';
537 cet::search_path sp{
"FW_SEARCH_PATH"};
538 std::string found_filename;
542 <<
"Cannot find ROOT file in current directory nor on FW_SEARCH_PATH specified in " 543 "parameter HistogramFile: \"" 546 histFile =
new TFile(found_filename.c_str());
547 if (!histFile || histFile->IsZombie() || !histFile->IsOpen()) {
551 <<
"Cannot open ROOT file found on FW_SEARCH_PATH and originally specified in " 552 "parameter HistogramFile: \"" 553 << found_filename <<
'"';
590 <<
fPHist.size() <<
" momentum histograms to describe " <<
fPDG.size()
591 <<
" particle types...";
594 for (
auto const& histName :
fPHist) {
595 TH1* pHist =
dynamic_cast<TH1*
>(histFile->Get(histName.c_str()));
598 <<
"Failed to read momentum histogram '" << histName <<
"' from '" 599 << histFile->GetPath() <<
"\'";
601 pHist->SetDirectory(
nullptr);
602 hPHist.emplace_back(pHist);
614 <<
" particle types...";
618 TH2* pHist =
dynamic_cast<TH2*
>(histFile->Get(histName.c_str()));
621 <<
"Failed to read direction histogram '" << histName <<
"' from '" 622 << histFile->GetPath() <<
"\'";
624 pHist->SetDirectory(
nullptr);
638 if (vec.size() !=
fPDG.size()) {
651 if (vec.size() != 1)
return false;
654 vec.resize(
fPDG.size(), vec[0]);
667 std::unique_ptr<std::vector<simb::MCTruth>> truthcol(
new std::vector<simb::MCTruth>);
675 truthcol->push_back(truth);
677 evt.
put(std::move(truthcol));
689 CLHEP::RandGaussQ gauss(
fEngine);
699 p =
fP0[i] +
fSigmaP[i] * (2.0 * flat.fire() - 1.0);
703 static TDatabasePDG pdgt;
704 TParticlePDG* pdgp = pdgt.GetParticle(
fPDG[i]);
705 if (pdgp) m = pdgp->Mass();
716 x[0] =
fX0[i] +
fSigmaX[i] * (2.0 * flat.fire() - 1.0);
717 x[1] =
fY0[i] +
fSigmaY[i] * (2.0 * flat.fire() - 1.0);
718 x[2] =
fZ0[i] +
fSigmaZ[i] * (2.0 * flat.fire() - 1.0);
724 t =
fT0[i] +
fSigmaT[i] * (2.0 * flat.fire() - 1.0);
727 TLorentzVector pos(x[0], x[1], x[2], t);
734 double thyzradsplussigma = 0;
735 double thyzradsminussigma = 0;
745 thxz = (180. / M_PI) * thetaxz;
746 thyz = (180. / M_PI) * thetayz;
755 thyzrads = std::asin(std::sin(
760 TMath::Min((thyzrads + ((M_PI / 180.) * fabs(
fSigmaThetaYZ[i]))), M_PI / 2.);
762 TMath::Max((thyzrads - ((M_PI / 180.) * fabs(
fSigmaThetaYZ[i]))), -M_PI / 2.);
767 double sinthyzmin = std::sin(thyzradsminussigma);
768 double sinthyzmax = std::sin(thyzradsplussigma);
769 double sinthyz = sinthyzmin + flat.fire() * (sinthyzmax - sinthyzmin);
770 thyz = (180. / M_PI) * std::asin(sinthyz);
773 double thxzrad = thxz * M_PI / 180.0;
774 double thyzrad = thyz * M_PI / 180.0;
776 TLorentzVector pvec(p * std::cos(thyzrad) * std::sin(thxzrad),
777 p * std::sin(thyzrad),
778 p * std::cos(thxzrad) * std::cos(thyzrad),
779 std::sqrt(p * p + m * m));
782 int trackid = -1 * (i + 1);
783 std::string primary(
"primary");
803 CLHEP::RandGaussQ gauss(
fEngine);
814 x[0] =
fX0[0] +
fSigmaX[0] * (2.0 * flat.fire() - 1.0);
815 x[1] =
fY0[0] +
fSigmaY[0] * (2.0 * flat.fire() - 1.0);
816 x[2] =
fZ0[0] +
fSigmaZ[0] * (2.0 * flat.fire() - 1.0);
822 t =
fT0[0] +
fSigmaT[0] * (2.0 * flat.fire() - 1.0);
825 TLorentzVector pos(x[0], x[1], x[2], t);
828 for (
unsigned int i(0); i <
fPDG.size(); ++i) {
837 p =
fP0[i] +
fSigmaP[i] * (2.0 * flat.fire() - 1.0);
840 static TDatabasePDG pdgt;
841 TParticlePDG* pdgp = pdgt.GetParticle(
fPDG[i]);
842 if (pdgp) m = pdgp->Mass();
849 double thyzradsplussigma = 0;
850 double thyzradsminussigma = 0;
860 thxz = (180. / M_PI) * thetaxz;
861 thyz = (180. / M_PI) * thetayz;
870 thyzrads = std::asin(std::sin(
875 TMath::Min((thyzrads + ((M_PI / 180.) * fabs(
fSigmaThetaYZ[i]))), M_PI / 2.);
877 TMath::Max((thyzrads - ((M_PI / 180.) * fabs(
fSigmaThetaYZ[i]))), -M_PI / 2.);
882 double sinthyzmin = std::sin(thyzradsminussigma);
883 double sinthyzmax = std::sin(thyzradsplussigma);
884 double sinthyz = sinthyzmin + flat.fire() * (sinthyzmax - sinthyzmin);
885 thyz = (180. / M_PI) * std::asin(sinthyz);
888 double thxzrad = thxz * M_PI / 180.0;
889 double thyzrad = thyz * M_PI / 180.0;
891 TLorentzVector pvec(p * std::cos(thyzrad) * std::sin(thxzrad),
892 p * std::sin(thyzrad),
893 p * std::cos(thxzrad) * std::cos(thyzrad),
894 std::sqrt(p * p + m * m));
897 int trackid = -1 * (i + 1);
898 std::string primary(
"primary");
919 for (
unsigned int i = 0; i <
fPDG.size(); ++i) {
929 unsigned int i = flat.fireInt(
fPDG.size());
934 <<
"larg4SingleGen does not recognize ParticleSelectionMode " <<
fMode;
946 <<
" You are using vector values for larg4SingleGen configuration.\n " 947 <<
" Some of the configuration vectors may have been padded out ," 948 <<
" because they (weren't) as long as the pdg vector" 949 <<
" in your configuration. \n" 950 <<
" The new input particle configuration is:\n";
953 for (
size_t i = 0; i <= 1; ++i) {
955 values.append(list[i]);
956 values.append(
": [ ");
958 for (
size_t e = 0;
e <
fPDG.size(); ++
e) {
959 std::stringstream buf;
961 if (i == 0) buf <<
fPDG[
e] <<
", ";
963 if (i == 1) buf <<
fP0[
e] <<
", ";
964 if (i == 2) buf <<
fSigmaP[
e] <<
", ";
965 if (i == 3) buf <<
fX0[
e] <<
", ";
966 if (i == 4) buf <<
fY0[
e] <<
", ";
967 if (i == 5) buf <<
fZ0[
e] <<
", ";
968 if (i == 6) buf <<
fSigmaX[
e] <<
", ";
969 if (i == 7) buf <<
fSigmaY[
e] <<
", ";
970 if (i == 8) buf <<
fSigmaZ[
e] <<
", ";
975 if (i == 13) buf <<
fT0[
e] <<
", ";
976 if (i == 14) buf <<
fSigmaT[
e] <<
", ";
977 values.append(buf.str());
980 values.erase(values.find_last_of(
","));
981 values.append(
" ] \n");
995 double throw_value = h.Integral() * flat.fire();
997 for (
int i(0); i < h.GetNbinsX() + 1; ++i) {
998 cum_value += h.GetBinContent(i);
999 if (throw_value < cum_value) {
return flat.fire() * h.GetBinWidth(i) + h.GetBinLowEdge(i); }
1008 CLHEP::RandFlat flat(
fEngine);
1010 double throw_value = h.Integral() * flat.fire();
1011 double cum_value(0);
1012 for (
int i(0); i < h.GetNbinsX() + 1; ++i) {
1013 for (
int j(0); j < h.GetNbinsY() + 1; ++j) {
1014 cum_value += h.GetBinContent(i, j);
1015 if (throw_value < cum_value) {
1016 x = flat.fire() * h.GetXaxis()->GetBinWidth(i) + h.GetXaxis()->GetBinLowEdge(i);
1017 y = flat.fire() * h.GetYaxis()->GetBinWidth(j) + h.GetYaxis()->GetBinLowEdge(j);
static constexpr int kHIST
int fTDist
How to distribute t (gaus, or uniform)
void setup()
Performs checks and initialization based on the current configuration.
base_engine_t & createEngine(seed_t seed)
fhicl::Sequence< double > SigmaThetaYZ
std::vector< double > fSigmaZ
Variation in z position (cm)
static std::string presentOptions(OptionList const &allowedOptions, bool printKey, std::initializer_list< typename OptionList::value_type::first_type > exclude)
Returns a string describing all options in the list.
std::vector< std::unique_ptr< TH2 > > hThetaXzYzHist
actual TH1 for momentum distributions
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
fhicl::Atom< bool > SingleVertex
std::vector< double > fSigmaP
Variation in momenta (GeV/c)
void SetOrigin(simb::Origin_t origin)
fhicl::Atom< std::string > PDist
static constexpr int kSelectAllParts
One particle per entry is generated.
fhicl::Sequence< double > Theta0YZ
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
fhicl::Sequence< double > SigmaT
std::vector< double > fSigmaThetaYZ
Variation in angle in YZ plane.
fhicl::Sequence< double > SigmaZ
EDProducer(fhicl::ParameterSet const &pset)
static constexpr int kSelectOneRandPart
fhicl::Sequence< double > SigmaX
double SelectFromHist(const TH1 &h)
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
static std::map< int, std::string > makeDistributionNames()
Returns a vector with the name of distribution keywords.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
CLHEP::HepRandomEngine & fEngine
actual TH2 for angle distributions - Xz on x axis .
larg4SingleGen(Parameters const &config)
std::vector< int > fPDG
PDG code of particles to generate.
fhicl::Sequence< double > X0
void SampleOne(unsigned int i, simb::MCTruth &mct)
static std::map< int, std::string > makeParticleSelectionModeNames()
Returns a vector with the name of particle selection mode keywords.
fhicl::Atom< std::string > TDist
std::vector< double > fSigmaT
Variation in t position (s)
#define DEFINE_ART_MODULE(klass)
static const std::map< int, std::string > DistributionNames
Names of all distribution modes.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
std::vector< double > fZ0
Central z position (cm) in world coordinates.
single particles thrown at the detector
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
std::vector< double > fT0
Central t position (s) in world coordinates.
bool PadVector(std::vector< double > &vec)
bool fSingleVertex
if true - all particles produced at the same location
fhicl::Atom< bool > PadOutVectors
fhicl::Sequence< int > PDG
bool fromHistogram(std::string const &key) const
Returns whether the specified mode is an histogram distribution.
fhicl::Atom< std::string > HistogramFile
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
fhicl::Atom< std::string > PosDist
fhicl::OptionalAtom< rndm::NuRandomService::seed_t > Seed
void beginRun(art::Run &run) override
Act on begin of run: write "RunData" information (sumdata::RunData).
fhicl::Sequence< double > P0
std::vector< double > fTheta0XZ
Angle in XZ plane (degrees)
static std::string presentOptions(OptionList const &allowedOptions, bool printKey=true)
static auto selectOption(std::string Option, OptionList const &allowedOptions) -> decltype(auto)
Parses an option string and returns the corresponding option number.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
void SampleMany(simb::MCTruth &mct)
fhicl::Sequence< double > SigmaThetaXZ
void Add(simb::MCParticle const &part)
fhicl::Sequence< std::string > PHist
std::string fHistFileName
Filename containing histogram of momenta.
int fAngleDist
How to distribute angles (gaus, uniform)
fhicl::Atom< std::string > ParticleSelectionMode
std::vector< double > fX0
Central x position (cm) in world coordinates.
void produce(art::Event &evt) override
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
module to produce single or multiple specified particles in the detector
std::vector< double > fSigmaY
Variation in y position (cm)
static constexpr int kUNIF
Uniform distribution.
std::vector< double > fY0
Central y position (cm) in world coordinates.
fhicl::Sequence< std::string > ThetaXzYzHist
Event generator information.
std::vector< double > fSigmaX
Variation in x position (cm)
void Sample(simb::MCTruth &mct)
std::vector< std::string > fThetaXzYzHist
name of histogram for thetaxz/thetayz distribution
fhicl::Sequence< double > Theta0XZ
fhicl::Sequence< double > Y0
std::vector< std::string > fPHist
name of histogram of momenta
Event Generation using GENIE, cosmics or single particles.
fhicl::Sequence< double > Z0
std::vector< double > fTheta0YZ
Angle in YZ plane (degrees)
static constexpr int kGAUS
Gaussian distribution.
std::vector< std::unique_ptr< TH1 > > hPHist
static std::string optionName(typename OptionList::value_type::first_type optionKey, OptionList const &allowedOptions, std::string defName="<unknown>")
Returns the name of the specified option key, or defName if not known.
std::vector< double > fP0
Central momentum (GeV/c) to generate.
std::vector< double > fSigmaThetaXZ
Variation in angle in XZ plane.
cet::coded_exception< error, detail::translate > exception
fhicl::Sequence< double > T0
int fPDist
How to distribute momenta (gaus or uniform)
art::detail::EngineCreator::seed_t seed_t
int fPosDist
How to distribute xyz (gaus, or uniform)
fhicl::Sequence< double > SigmaP
static const std::map< int, std::string > ParticleSelectionModeNames
Names of all particle selection modes.
fhicl::Atom< std::string > AngleDist
void printVecs(std::vector< std::string > const &list)
fhicl::Sequence< double > SigmaY