LDMX Software
GenieReweightProducer.cxx
1//
2// Created by Wesley Ketchum on 4/29/24.
3//
4
5#include "SimCore/Reweight/GenieReweightProducer.h"
6
7#include <iostream>
8#include <memory>
9#include <random>
10
11#include "Framework/EventGen/HepMC3Converter.h"
12#include "Framework/Interaction/Interaction.h"
13#include "Framework/Messenger/Messenger.h"
14#include "Framework/Utils/AppInit.h"
15#include "Framework/Utils/RunOpt.h"
16#include "HepMC3/GenEvent.h"
17#include "HepMC3/PrintStreams.h" // IWYU pragma: keep
18#include "RwCalculators/GReWeightFZone.h"
19#include "RwCalculators/GReWeightINuke.h"
20#include "RwCalculators/GReWeightXSecEmpiricalMEC.h"
21#include "RwFramework/GReWeight.h"
22#include "RwFramework/GSyst.h"
23#include "RwFramework/GSystSet.h"
24#include "SimCore/Event/EventWeights.h"
25#include "SimCore/Event/HepMC3GenEvent.h"
26
27namespace simcore {
28
29GenieReweightProducer::GenieReweightProducer(const std::string& name,
30 framework::Process& process)
31 : Producer(name, process) {
32 hep_mc3_converter_ = std::make_unique<genie::HepMC3Converter>();
33 genie_rw_ = std::make_unique<genie::rew::GReWeight>();
34}
35
36void GenieReweightProducer::configure(framework::config::Parameters& ps) {
37 hepmc3_coll_name_ = ps.get<std::string>("hepmc3_coll_name");
38 hepmc3_pass_name_ = ps.get<std::string>("hepmc3_pass_name");
39 event_weights_coll_name_ = ps.get<std::string>("event_weights_coll_name");
40 seed_ = ps.get<int>("seed");
41 n_weights_ = static_cast<size_t>(ps.get<int>("n_weights"));
42 auto var_types_strings = ps.get<std::vector<std::string> >("var_types");
43
44 message_threshold_file_ = ps.get<std::string>("message_threshold_file");
45
46 std::default_random_engine generator(seed_);
47 std::normal_distribution<double> normal_distribution;
48
49 for (auto const& vt_str : var_types_strings) {
50 auto vtype = ldmx::EventWeights::stringToVariationType(vt_str);
51 for (size_t i_w = 0; i_w < n_weights_; ++i_w)
52 variation_map_[vtype].push_back(normal_distribution(generator));
53 }
54}
55
56void GenieReweightProducer::reinitializeGenieReweight() {
57 genie_rw_ = std::make_unique<genie::rew::GReWeight>();
58
59 // set message thresholds
60 genie::utils::app_init::MesgThresholds(message_threshold_file_);
61
62 genie::RunOpt::Instance()->SetTuneName(tune_);
63 if (!genie::RunOpt::Instance()->Tune()) {
64 EXCEPTION_RAISE("ConfigurationException", "No TuneId in RunOption.");
65 }
66 genie::RunOpt::Instance()->BuildTune();
67
68 genie_rw_->AdoptWghtCalc("hadro_fzone", new genie::rew::GReWeightFZone);
69 genie_rw_->AdoptWghtCalc("hadro_intranuke", new genie::rew::GReWeightINuke);
70
71 auto& syst = genie_rw_->Systematics();
72 for (auto var : variation_map_)
73 syst.Init(variationTypeToGenieDial(var.first));
74}
75
76void GenieReweightProducer::onNewRun(const ldmx::RunHeader& runHeader) {
77 const std::string genie_tune_par = "GenieTune";
78 std::string new_tune;
79 for (auto par : runHeader.getStringParameters())
80 if (par.first.size() >= genie_tune_par.size() &&
81 par.first.compare(par.first.size() - genie_tune_par.size(),
82 genie_tune_par.size(), genie_tune_par) == 0) {
83 new_tune = par.second;
84 break;
85 }
86
87 if (tune_ != new_tune) {
88 ldmx_log(debug) << "Found new tune " << new_tune << " (used to be " << tune_
89 << ")" << std::endl;
90 tune_ = new_tune;
91 reinitializeGenieReweight();
92 }
93}
94
95void GenieReweightProducer::reconfigureGenieReweight(size_t i_w) {
96 auto& syst = genie_rw_->Systematics();
97 for (auto var : variation_map_) {
98 if (var.first ==
99 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_MFP_pi)
100 syst.Set(genie::rew::GSyst::FromString("MFP_pi"), var.second[i_w]);
101 else if (var.first ==
102 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_MFP_N)
103 syst.Set(genie::rew::GSyst::FromString("MFP_N"), var.second[i_w]);
104 else if (var.first ==
105 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrCEx_pi)
106 syst.Set(genie::rew::GSyst::FromString("FrCEx_pi"), var.second[i_w]);
107 else if (var.first ==
108 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrInel_pi)
109 syst.Set(genie::rew::GSyst::FromString("FrInel_pi"), var.second[i_w]);
110 else if (var.first ==
111 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrAbs_pi)
112 syst.Set(genie::rew::GSyst::FromString("FrAbs_pi"), var.second[i_w]);
113 else if (var.first ==
114 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrPiProd_pi)
115 syst.Set(genie::rew::GSyst::FromString("FrPiProd_pi"), var.second[i_w]);
116 else if (var.first ==
117 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrCEx_N)
118 syst.Set(genie::rew::GSyst::FromString("FrCEx_N"), var.second[i_w]);
119 else if (var.first ==
120 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrInel_N)
121 syst.Set(genie::rew::GSyst::FromString("FrInel_N"), var.second[i_w]);
122 else if (var.first ==
123 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrAbs_N)
124 syst.Set(genie::rew::GSyst::FromString("FrAbs_N"), var.second[i_w]);
125 else if (var.first ==
126 ldmx::EventWeights::VariationType::kGENIE_INukeTwkDial_FrPiProd_N)
127 syst.Set(genie::rew::GSyst::FromString("FrPiProd_N"), var.second[i_w]);
128 else if (var.first ==
129 ldmx::EventWeights::VariationType::kGENIE_HadrNuclTwkDial_FormZone)
130 syst.Set(genie::rew::GSyst::FromString("FormZone"), var.second[i_w]);
131 }
132 genie_rw_->Reconfigure();
133}
134
135void GenieReweightProducer::produce(framework::Event& event) {
136 // When GENIE runs as a G4VDiscreteProcess rather than a PrimaryGenerator,
137 // not every event will have an electronuclear interaction. Guard against
138 // a missing or empty HepMC3 collection.
139 if (!event.exists(hepmc3_coll_name_, hepmc3_pass_name_)) {
140 ldmx::EventWeights ev_weights(variation_map_);
141 for (size_t i_w = 0; i_w < n_weights_; ++i_w) {
142 ev_weights.addWeight(1.0);
143 }
144 event.add(event_weights_coll_name_, ev_weights);
145 return;
146 }
147
148 const auto& hepmc3_col = event.getObject<std::vector<ldmx::HepMC3GenEvent> >(
149 hepmc3_coll_name_, hepmc3_pass_name_);
150
151 if (hepmc3_col.empty()) {
152 ldmx::EventWeights ev_weights(variation_map_);
153 for (size_t i_w = 0; i_w < n_weights_; ++i_w) {
154 ev_weights.addWeight(1.0);
155 }
156 event.add(event_weights_coll_name_, ev_weights);
157 return;
158 }
159
160 // create an output weights
161 ldmx::EventWeights ev_weights(variation_map_);
162
163 for (size_t i_w = 0; i_w < n_weights_; ++i_w) {
164 double running_weight = 1;
165
166 reconfigureGenieReweight(i_w);
167
168 // setup a loop here ... but we're going to force only looping over one
169 // interaction if it exists for now.
170 for (size_t i_ev = 0; i_ev < 1; ++i_ev) {
171 auto const& hepmc3_ev = hepmc3_col.at(i_ev);
172 // fill our event data into a HepMC3GenEvent
173 HepMC3::GenEvent hepmc3_genev;
174 hepmc3_genev.read_data(hepmc3_ev);
175
176 // print it out to check it ...
177 if (i_w == 0) ldmx_log(debug) << hepmc3_genev;
178
179 // now convert to genie event record
180 auto genie_ev_record_ptr = hep_mc3_converter_->RetrieveGHEP(hepmc3_genev);
181
182 // print that out too ...
183 if (i_w == 0) ldmx_log(debug) << *genie_ev_record_ptr;
184
185 // auto this_weight = 1.0 + var_value*0.05;
186 auto this_weight = genie_rw_->CalcWeight(*genie_ev_record_ptr);
187
188 running_weight = running_weight * this_weight;
189
190 } // end loop over interactions in event
191
192 ev_weights.addWeight(running_weight);
193
194 } // end loop over weights
195
196 ldmx_log(trace) << ev_weights;
197
198 event.add(event_weights_coll_name_, ev_weights);
199}
200} // namespace simcore
201
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Implements an event buffer system for storing event data.
Definition Event.h:40
bool exists(const std::string &name, const std::string &passName, bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Definition Event.cxx:107
Class which represents the process under execution.
Definition Process.h:34
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:68
const std::map< std::string, std::string > & getStringParameters() const
Get a const reference to all string parameters.
Definition RunHeader.h:251
Dynamically loadable photonuclear models either from SimCore or external libraries implementing this ...