LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
GenieWeightCalc.cxx
Go to the documentation of this file.
1 // GenieWeightCalc.cxx
2 //
3 // Handles event weights for GENIE systematics studies
4 //
5 // Updated for merge into larsim develop branch on Feb 22 2021 by Steven Gardiner
6 // Heavily rewritten on Dec 9 2019
7 // by Steven Gardiner <gardiner@fnal.gov>
8 // Updated by Marco Del Tutto on Feb 18 2017
9 // Ported from uboonecode to larsim on Feb 14 2017
10 // by Marco Del Tutto <marco.deltutto@physics.ox.ac.uk>
11 
12 // Standard library includes
13 #include <map>
14 #include <memory>
15 #include <set>
16 
17 // Framework includes
19 #include "cetlib_except/exception.h"
20 #include "fhiclcpp/ParameterSet.h"
22 
25 
26 #include "CLHEP/Random/RandGaussQ.h"
27 
29 
33 
34 // GENIE includes
35 // TODO: add legacy support for GENIE v2 (mostly changes to header file
36 // locations would be needed)
37 #include "GENIE/Framework/Conventions/KineVar.h"
38 #include "GENIE/Framework/EventGen/EventRecord.h"
39 #include "GENIE/Framework/Interaction/Interaction.h"
40 #include "GENIE/Framework/Interaction/Kinematics.h"
41 #include "GENIE/Framework/Messenger/Messenger.h"
42 #include "GENIE/Framework/Utils/AppInit.h"
43 
44 #include "GENIE/RwCalculators/GReWeightAGKY.h"
45 #include "GENIE/RwCalculators/GReWeightDISNuclMod.h"
46 #include "GENIE/RwCalculators/GReWeightFGM.h"
47 #include "GENIE/RwCalculators/GReWeightFZone.h"
48 #include "GENIE/RwCalculators/GReWeightINuke.h"
49 #include "GENIE/RwCalculators/GReWeightINukeParams.h"
50 #include "GENIE/RwCalculators/GReWeightNonResonanceBkg.h"
51 #include "GENIE/RwCalculators/GReWeightNuXSecCCQE.h"
52 #include "GENIE/RwCalculators/GReWeightNuXSecCCQEaxial.h"
53 #include "GENIE/RwCalculators/GReWeightNuXSecCCQEvec.h"
54 #include "GENIE/RwCalculators/GReWeightNuXSecCCRES.h"
55 #include "GENIE/RwCalculators/GReWeightNuXSecCOH.h"
56 #include "GENIE/RwCalculators/GReWeightNuXSecDIS.h"
57 #include "GENIE/RwCalculators/GReWeightNuXSecNC.h"
58 #include "GENIE/RwCalculators/GReWeightNuXSecNCEL.h"
59 #include "GENIE/RwCalculators/GReWeightNuXSecNCRES.h"
60 #include "GENIE/RwCalculators/GReWeightResonanceDecay.h"
61 #include "GENIE/RwCalculators/GReWeightXSecEmpiricalMEC.h"
62 #include "GENIE/RwFramework/GReWeight.h"
63 #include "GENIE/RwFramework/GSyst.h"
64 #include "GENIE/RwFramework/GSystSet.h"
65 
66 // MicroBooNE-specific reweighting tools go here. These require a special genie
67 // ups product.
68 #ifdef GENIE_UB_PATCH
69 
70 // New weight calculator in GENIE v3.0.4 MicroBooNE patch 01
71 #include "GENIE/RwCalculators/GReWeightXSecMEC.h"
72 
73 // New weight calculators in GENIE v3.0.4 MicroBooNE patch 02
74 #include "GENIE/RwCalculators/GReWeightDeltaradAngle.h"
75 #include "GENIE/RwCalculators/GReWeightNuXSecCOHuB.h"
76 #include "GENIE/RwCalculators/GReWeightRESBugFix.h"
77 
78 #endif
79 
80 namespace {
81 
82  // These GENIE knobs are listed in the GSyst_t enum type but are not actually implemented.
83  // They will be skipped and a warning message will be printed.
84  // Last updated 9 Dec 2019 by S. Gardiner
85  std::set<genie::rew::GSyst_t> UNIMPLEMENTED_GENIE_KNOBS = {
86  kXSecTwkDial_RnubarnuCC, // tweak the ratio of \sigma(\bar\nu CC) / \sigma(\nu CC)
87  kXSecTwkDial_NormCCQEenu, // tweak CCQE normalization (maintains dependence on neutrino energy)
88  kXSecTwkDial_NormDISCC, // tweak the inclusive DIS CC normalization
89  kXSecTwkDial_DISNuclMod // unclear intent, does anyone else know? - S. Gardiner
90  };
91 
92  // Some GENIE weight calculators can work with sets of knobs that should not be used simultaneously.
93  // For instance, the CCQE weight calculator can vary parameters for the dipole axial form factor model
94  // (the axial mass Ma) or for the z-expansion model, but using both together is invalid. The map below
95  // is used to check that all of the requested knobs from the FHiCL input are compatible with each
96  // other. Assuming they pass this check, the code will then configure the weight calculators to use
97  // the correct "basis" of reweighting knobs as appropriate.
98 
99  // Outer keys are names of GENIE weight calculators that use sets of incompatible knobs. The names
100  // need to match those used in GenieWeightCalc::SetupWeightCalculators(), specifically in the
101  // calls to genie::rew::GReWeight::AdoptWeightCalc().
102  // Inner keys are integer codes used to represent (and configure) each of the mutually exclusive
103  // modes (i.e., to select one of the sets of incompatible knobs to use for the weight calculation).
104  // Values are GSyst_t knob labels that belong to the given mode.
105  std::map<std::string, std::map<int, std::set<genie::rew::GSyst_t>>> INCOMPATIBLE_GENIE_KNOBS = {
106  // CCQE (genie::rew::GReWeightNuXSecCCQE)
107  {"xsec_ccqe",
108  {
109  {genie::rew::GReWeightNuXSecCCQE::kModeNormAndMaShape,
110  {
111  // Norm + shape
112  kXSecTwkDial_NormCCQE, // tweak CCQE normalization (energy independent)
113  kXSecTwkDial_MaCCQEshape, // tweak Ma CCQE, affects dsigma(CCQE)/dQ2 in shape only (normalized to constant integral)
114  kXSecTwkDial_E0CCQEshape // tweak E0 CCQE RunningMA, affects dsigma(CCQE)/dQ2 in shape only (normalized to constant integral)
115  }},
116  {genie::rew::GReWeightNuXSecCCQE::kModeMa,
117  {
118  // Ma
119  kXSecTwkDial_MaCCQE, // tweak Ma CCQE, affects dsigma(CCQE)/dQ2 both in shape and normalization
120  kXSecTwkDial_E0CCQE, // tweak E0 CCQE RunningMA, affects dsigma(CCQE)/dQ2 both in shape and normalization
121  }},
122  {genie::rew::GReWeightNuXSecCCQE::kModeZExp,
123  {
124  // Z-expansion
125  kXSecTwkDial_ZNormCCQE, // tweak Z-expansion CCQE normalization (energy independent)
126  kXSecTwkDial_ZExpA1CCQE, // tweak Z-expansion coefficient 1, affects dsigma(CCQE)/dQ2 both in shape and normalization
127  kXSecTwkDial_ZExpA2CCQE, // tweak Z-expansion coefficient 2, affects dsigma(CCQE)/dQ2 both in shape and normalization
128  kXSecTwkDial_ZExpA3CCQE, // tweak Z-expansion coefficient 3, affects dsigma(CCQE)/dQ2 both in shape and normalization
129  kXSecTwkDial_ZExpA4CCQE // tweak Z-expansion coefficient 4, affects dsigma(CCQE)/dQ2 both in shape and normalization
130  }},
131  }},
132 
133  // CCRES (genie::rew::GReWeightNuXSecCCRES)
134  {"xsec_ccres",
135  {{genie::rew::GReWeightNuXSecCCRES::kModeNormAndMaMvShape,
136  {
137  // Norm + shape
138  kXSecTwkDial_NormCCRES,
139  kXSecTwkDial_MaCCRESshape,
140  kXSecTwkDial_MvCCRESshape
141  }},
142  {genie::rew::GReWeightNuXSecCCRES::kModeMaMv,
143  {
144  // Ma + Mv
145  kXSecTwkDial_MaCCRES, // tweak Ma CCRES, affects d2sigma(CCRES)/dWdQ2 both in shape and normalization
146  kXSecTwkDial_MvCCRES // tweak Mv CCRES, affects d2sigma(CCRES)/dWdQ2 both in shape and normalization
147  }}}},
148 
149  // NCRES (genie::rew::GReWeightNuXSecNCRES)
150  {"xsec_ncres",
151  {{genie::rew::GReWeightNuXSecNCRES::kModeNormAndMaMvShape,
152  {
153  // Norm + shape
154  kXSecTwkDial_NormNCRES,
155  kXSecTwkDial_MaNCRESshape,
156  kXSecTwkDial_MvNCRESshape
157  }},
158  {genie::rew::GReWeightNuXSecNCRES::kModeMaMv,
159  {
160  // Ma + Mv
161  kXSecTwkDial_MaNCRES, // tweak Ma NCRES, affects d2sigma(NCRES)/dWdQ2 both in shape and normalization
162  kXSecTwkDial_MvNCRES // tweak Mv NCRES, affects d2sigma(NCRES)/dWdQ2 both in shape and normalization
163  }}}},
164 
165  // DIS (genie::rew::GReWeightNuXSecDIS)
166  {"xsec_dis",
167  {{genie::rew::GReWeightNuXSecDIS::kModeABCV12u,
168  {
169  kXSecTwkDial_AhtBY, // tweak the Bodek-Yang model parameter A_{ht} - incl. both shape and normalization effect
170  kXSecTwkDial_BhtBY, // tweak the Bodek-Yang model parameter B_{ht} - incl. both shape and normalization effect
171  kXSecTwkDial_CV1uBY, // tweak the Bodek-Yang model parameter CV1u - incl. both shape and normalization effect
172  kXSecTwkDial_CV2uBY // tweak the Bodek-Yang model parameter CV2u - incl. both shape and normalization effect
173  }},
174  {genie::rew::GReWeightNuXSecDIS::kModeABCV12uShape,
175  {
176  kXSecTwkDial_AhtBYshape, // tweak the Bodek-Yang model parameter A_{ht} - shape only effect to d2sigma(DIS)/dxdy
177  kXSecTwkDial_BhtBYshape, // tweak the Bodek-Yang model parameter B_{ht} - shape only effect to d2sigma(DIS)/dxdy
178  kXSecTwkDial_CV1uBYshape, // tweak the Bodek-Yang model parameter CV1u - shape only effect to d2sigma(DIS)/dxdy
179  kXSecTwkDial_CV2uBYshape // tweak the Bodek-Yang model parameter CV2u - shape only effect to d2sigma(DIS)/dxdy
180  }}}}};
181 
182  // Helper function that checks whether a string storing a GENIE knob name is
183  // valid. Also stores the corresponding GSyst_t enum value for the knob.
184  bool valid_knob_name(const std::string& knob_name, genie::rew::GSyst_t& knob)
185  {
186  knob = genie::rew::GSyst::FromString(knob_name);
187  if (knob != kNullSystematic && knob != kNTwkDials) {
188  if (UNIMPLEMENTED_GENIE_KNOBS.count(knob)) {
189  MF_LOG_WARNING("GENIEWeightCalc") << "Ignoring unimplemented GENIE"
190  << " knob " << knob_name;
191  return false;
192  }
193  }
194  else {
195  throw cet::exception(__PRETTY_FUNCTION__) << "Encountered unrecognized"
196  "GENIE knob \""
197  << knob_name << '\"';
198  return false;
199  }
200  return true;
201  }
202 
203  // Set of FHiCL weight calculator labels for which the tuned CV will be
204  // ignored. If the name of the weight calculator doesn't appear in this set,
205  // then variation weights will be thrown around the tuned CV.
206  std::set<std::string> CALC_NAMES_THAT_IGNORE_TUNED_CV = {"RootinoFix"};
207 
208 } // anonymous namespace
209 
210 namespace evwgh {
211  class GenieWeightCalc : public WeightCalc {
212  public:
213  GenieWeightCalc();
214  void Configure(const fhicl::ParameterSet& pset, CLHEP::HepRandomEngine& engine) override;
215  std::vector<std::vector<double>> GetWeight(art::Event& e) override;
216 
217  private:
218  std::map<std::string, int> CheckForIncompatibleSystematics(
219  const std::vector<genie::rew::GSyst_t>& knob_vec);
220 
221  void SetupWeightCalculators(genie::rew::GReWeight& rw,
222  const std::map<std::string, int>& modes_to_use);
223 
224  std::vector<genie::rew::GReWeight> reweightVector;
225 
226  std::string fGenieModuleLabel;
227 
229 
231  };
232 
234 
235  void GenieWeightCalc::Configure(const fhicl::ParameterSet& p, CLHEP::HepRandomEngine& engine)
236  {
237  genie::Messenger* messenger = genie::Messenger::Instance();
238 
239  // By default, run GENIE reweighting in "quiet mode"
240  // (use the logging settings in the "whisper" configuration
241  // of the genie::Messenger class). The user can disable
242  // quiet mode using the boolean FHiCL parameter "quiet_mode"
243  fQuietMode = p.get<bool>("quiet_mode", true);
244  if (fQuietMode) { genie::utils::app_init::MesgThresholds("Messenger_whisper.xml"); }
245  else {
246  // If quiet mode isn't enabled, then print detailed debugging
247  // messages for GENIE reweighting
248  messenger->SetPriorityLevel("ReW", log4cpp::Priority::DEBUG);
249 
250  MF_LOG_INFO("GENIEWeightCalc") << "Configuring GENIE weight"
251  << " calculator " << this->GetName();
252  }
253 
254  // Manually silence a couple of annoying GENIE logging messages
255  // that appear a lot when running reweighting. This is done
256  // whether or not "quiet mode" is enabled.
257  messenger->SetPriorityLevel("TransverseEnhancementFFModel", log4cpp::Priority::WARN);
258  messenger->SetPriorityLevel("Nieves", log4cpp::Priority::WARN);
259 
260  // Global Config
261  fGenieModuleLabel = p.get<std::string>("genie_module_label");
262 
263  // Parameter central values from a table in the global config
264  // Keys are GENIE knob names, values are knob settings that correspond to a tuned CV
265  const fhicl::ParameterSet& param_CVs =
266  p.get<fhicl::ParameterSet>("genie_central_values", fhicl::ParameterSet());
267  std::vector<std::string> CV_knob_names = param_CVs.get_all_keys();
268 
269  // Map to store the CV knob settings
270  std::map<genie::rew::GSyst_t, double> gsyst_to_cv_map;
271  genie::rew::GSyst_t temp_knob;
272 
273  if (!CV_knob_names.empty() && !fQuietMode)
274  MF_LOG_INFO("GENIEWeightCalc")
275  << "Configuring non-default GENIE knob central values from input"
276  << " FHiCL parameter set";
277 
278  for (const auto& knob_name : CV_knob_names) {
279  double CV_knob_value = param_CVs.get<double>(knob_name);
280  if (valid_knob_name(knob_name, temp_knob)) {
281  if (gsyst_to_cv_map.count(temp_knob)) {
282  throw cet::exception(__PRETTY_FUNCTION__)
283  << "Duplicate central values"
284  << " were configured for the " << knob_name << " GENIE knob.";
285  }
286  gsyst_to_cv_map[temp_knob] = CV_knob_value;
287  if (!fQuietMode) {
288  MF_LOG_INFO("GENIEWeightCalc")
289  << "Central value for the " << knob_name << " knob was set to " << CV_knob_value;
290  }
291  }
292  }
293 
294  // Calc Config
296  auto const pars =
297  pset.get<std::vector<std::string>>("parameter_list", std::vector<std::string>());
298  auto const par_sigmas = pset.get<std::vector<double>>("parameter_sigma", std::vector<double>());
299 
300  // Parameter limits (currently only used in minmax mode)
301  // TODO: Revisit this. Could be useful for other modes.
302  auto const par_mins = pset.get<std::vector<double>>("parameter_min", std::vector<double>());
303  auto const par_maxes = pset.get<std::vector<double>>("parameter_max", std::vector<double>());
304 
305  auto const mode = pset.get<std::string>("mode");
306 
307  bool sigmas_ok = true;
308  std::string array_name_for_exception;
309  if (mode.find("central_value") == std::string::npos &&
310  mode.find("minmax") == std::string::npos) {
311  // For most reweighting modes, make sure that the number 1-sigma values
312  // and the number of reweighting knobs match
313  if (pars.size() != par_sigmas.size()) {
314  sigmas_ok = false;
315  array_name_for_exception = "parameter_sigma";
316  }
317  }
318  else if (mode.find("minmax") != std::string::npos) {
319  if (pars.size() != par_mins.size() || pars.size() != par_maxes.size()) {
320  // For "minmax" mode, do the same for both the minimum and maximum
321  // sigma values
322  sigmas_ok = false;
323  array_name_for_exception = "parameter_min and parameter_max";
324  }
325  }
326 
327  if (!sigmas_ok) {
328  throw cet::exception(__PRETTY_FUNCTION__)
329  << GetName() << "::Bad fcl configuration. parameter_list and " << array_name_for_exception
330  << " need to have same number of parameters.";
331  }
332 
333  if (!pars.empty() && !fQuietMode)
334  MF_LOG_INFO("GENIEWeightCalc")
335  << "Configuring"
336  << " GENIE systematic knobs to be varied from the input FHiCL parameter set";
337 
338  // Convert the list of GENIE knob names from the input FHiCL configuration
339  // into a vector of genie::rew::GSyst_t labels
340  std::vector<genie::rew::GSyst_t> knobs_to_use;
341  for (const auto& knob_name : pars) {
342  if (valid_knob_name(knob_name, temp_knob)) knobs_to_use.push_back(temp_knob);
343  }
344 
345  // We need to add all of the tuned CV knobs to the list when configuring
346  // the weight calculators and checking for incompatibilities. Maybe all of
347  // the systematic variation knobs are fine to use together, but they also
348  // need to be compatible with the tuned CV. To perform the check, copy the
349  // list of systematic variation knobs to use and add all the CV knobs that
350  // aren't already present.
351  std::vector<genie::rew::GSyst_t> all_knobs_vec = knobs_to_use;
352  for (const auto& pair : gsyst_to_cv_map) {
353  genie::rew::GSyst_t cv_knob = pair.first;
354  auto begin = all_knobs_vec.cbegin();
355  auto end = all_knobs_vec.cend();
356  if (!std::count(begin, end, cv_knob)) all_knobs_vec.push_back(cv_knob);
357  }
358 
359  // Check that the enabled knobs (both systematic variations and knobs used
360  // for the CV tune) are all compatible with each other. The std::map
361  // returned by this function call provides information needed to fine-tune
362  // the configuration of the GENIE weight calculators.
363  std::map<std::string, int> modes_to_use = this->CheckForIncompatibleSystematics(all_knobs_vec);
364 
365  // If we're working in "pm1sigma" or "minmax" mode, there should only be two
366  // universes regardless of user input.
367  size_t num_universes = 0u;
368  if (mode.find("pm1sigma") != std::string::npos || mode.find("minmax") != std::string::npos) {
369  num_universes = 2u;
370  }
371  else if (mode.find("multisim") != std::string::npos) {
372  num_universes = pset.get<size_t>("number_of_multisims");
373 
374  // Since we're in multisim mode, force retrieval of the random
375  // number seed. If it wasn't set, this will trigger an exception.
376  // We want this check because otherwise the multisim universes
377  // will not be easily reproducible.
378  int dummy_seed = pset.get<int>("random_seed");
379  MF_LOG_INFO("GENIEWeightCalc")
380  << "GENIE weight calculator " << this->GetName() << " will generate " << num_universes
381  << " multisim universes with random seed " << dummy_seed;
382  }
383  // If we're working in "central_value" or "default" mode, only a single
384  // universe should be used
385  else {
386  num_universes = 1u;
387  }
388 
389  // Create one default-constructed genie::rew::GReWeight object per universe
390  reweightVector.resize(num_universes);
391 
392  // Set up the weight calculators for each universe
393  for (auto& rwght : reweightVector) {
394  this->SetupWeightCalculators(rwght, modes_to_use);
395  }
396 
397  // Prepare sigmas
398  size_t num_usable_knobs = knobs_to_use.size();
399  std::vector<std::vector<double>> reweightingSigmas(num_usable_knobs);
400 
401  for (size_t k = 0u; k < num_usable_knobs; ++k) {
402  reweightingSigmas[k].resize(num_universes);
403 
404  genie::rew::GSyst_t current_knob = knobs_to_use.at(k);
405 
406  for (size_t u = 0u; u < num_universes; ++u) {
407  if (mode.find("multisim") != std::string::npos) {
408  reweightingSigmas[k][u] = par_sigmas[k] * CLHEP::RandGaussQ::shoot(&engine, 0., 1.);
409  }
410  else if (mode.find("pm1sigma") != std::string::npos) {
411  // u == 0 => +1*sigma; u == 1 => -1*sigma if pm1sigma is specified
412  reweightingSigmas[k][u] = (u == 0 ? 1. : -1.) * par_sigmas.at(k);
413  }
414  else if (mode.find("minmax") != std::string::npos) {
415  // u == 0 => max; u == 1 => min if minmax is specified
416  reweightingSigmas[k][u] = (u == 0 ? par_maxes.at(k) : par_mins.at(k));
417  }
418  else if (mode.find("central_value") != std::string::npos) {
419  // We'll correct for a modified CV below if needed
420  reweightingSigmas[k][u] = 0.;
421  }
422  else {
423  // By default, use the exact sigma value given for each knob
424  reweightingSigmas[k][u] = par_sigmas[k];
425  }
426 
427  if (!fQuietMode)
428  MF_LOG_INFO("GENIEWeightCalc")
429  << "Set sigma for the " << genie::rew::GSyst::AsString(current_knob)
430  << " knob in universe #" << u << ". sigma = " << reweightingSigmas[k][u];
431 
432  // Add an offset if the central value for the current knob has been
433  // configured (and is thus probably nonzero). Ignore this for minmax
434  // mode (the limits should be chosen to respect a modified central
435  // value)
436  if (mode.find("minmax") == std::string::npos) {
437  auto iter = gsyst_to_cv_map.find(current_knob);
438  if (iter != gsyst_to_cv_map.end()) {
439  reweightingSigmas[k][u] += iter->second;
440  if (!fQuietMode)
441  MF_LOG_INFO("GENIEWeightCalc")
442  << "CV offset added to the " << genie::rew::GSyst::AsString(current_knob)
443  << " knob. New sigma for universe #" << u << " is " << reweightingSigmas[k][u];
444  }
445  }
446  }
447  }
448 
449  // Don't adjust knobs to reflect the tuned CV if this weight calculator
450  // should ignore those (as determined by whether it has one of the special
451  // FHiCL names)
452  if (!CALC_NAMES_THAT_IGNORE_TUNED_CV.count(this->GetName())) {
453 
454  // Add tuned CV knobs which have not been tweaked, and set them to their
455  // modified central values. This ensures that weights are always thrown
456  // around the modified CV.
457  for (const auto& pair : gsyst_to_cv_map) {
458  genie::rew::GSyst_t cv_knob = pair.first;
459  double cv_value = pair.second;
460 
461  // If the current tuned CV knob is not present in the list of tweaked
462  // knobs, then add it to the list with its tuned central value
463  if (!std::count(knobs_to_use.cbegin(), knobs_to_use.cend(), cv_knob)) {
464  ++num_usable_knobs;
465  knobs_to_use.push_back(cv_knob);
466 
467  // The tuned CV knob will take the same value in every universe
468  reweightingSigmas.emplace_back(std::vector<double>(num_universes, cv_value));
469 
470  if (!fQuietMode)
471  MF_LOG_INFO("GENIEWeightCalc") << "Tuned knob " << genie::rew::GSyst::AsString(cv_knob)
472  << " was not configured. Setting it to " << cv_value
473  << " in all " << num_universes << " universes.";
474  }
475  }
476  }
477 
478  // TODO: deal with parameters that have a priori bounds (e.g., FFCCQEVec,
479  // which can vary on the interval [0,1])
480 
481  // Set up the knob values for each universe
482  for (size_t u = 0; u < reweightVector.size(); ++u) {
483 
484  auto& rwght = reweightVector.at(u);
485  genie::rew::GSystSet& syst = rwght.Systematics();
486 
487  for (unsigned int k = 0; k < knobs_to_use.size(); ++k) {
488  genie::rew::GSyst_t knob = knobs_to_use.at(k);
489 
490  double twk_dial_value = reweightingSigmas.at(k).at(u);
491  syst.Set(knob, twk_dial_value);
492 
493  if (!fQuietMode) {
494  MF_LOG_INFO("GENIEWeightCalc") << "In universe #" << u << ", knob #" << k << " ("
495  << genie::rew::GSyst::AsString(knob) << ") was set to"
496  << " the value " << twk_dial_value;
497  }
498  } // loop over tweaked knobs
499 
500  rwght.Reconfigure();
501  rwght.Print();
502  } // loop over universes
503  }
504 
505  // Returns a vector of weights for each neutrino interaction in the event
506  std::vector<std::vector<double>> GenieWeightCalc::GetWeight(art::Event& e)
507  {
508  auto const& mcTruth = e.getProduct<std::vector<simb::MCTruth>>(fGenieModuleLabel);
509  auto const& gTruth = e.getProduct<std::vector<simb::GTruth>>(fGenieModuleLabel);
510 
511  size_t num_neutrinos = mcTruth.size();
512  size_t num_knobs = reweightVector.size();
513 
514  // Calculate weight(s) here
515  std::vector<std::vector<double>> weights(num_neutrinos);
516  for (size_t v = 0u; v < num_neutrinos; ++v) {
517 
518  // Convert the MCTruth and GTruth objects from the event
519  // back into the original genie::EventRecord needed to
520  // compute the weights
521  std::unique_ptr<genie::EventRecord> genie_event(evgb::RetrieveGHEP(mcTruth[v], gTruth[v]));
522 
523  // Set the final lepton kinetic energy and scattering cosine
524  // in the owned GENIE kinematics object. This is done during
525  // event generation but is not reproduced by evgb::RetrieveGHEP().
526  // Several new CCMEC weight calculators developed for MicroBooNE
527  // expect the variables to be set in this way (so that differential
528  // cross sections can be recomputed). Failing to set them results
529  // in inf and NaN weights.
530  // TODO: maybe update evgb::RetrieveGHEP to handle this instead.
531  genie::Interaction* interaction = genie_event->Summary();
532  genie::Kinematics* kine_ptr = interaction->KinePtr();
533 
534  // Final lepton mass
535  double ml = interaction->FSPrimLepton()->Mass();
536  // Final lepton 4-momentum
537  const TLorentzVector& p4l = kine_ptr->FSLeptonP4();
538  // Final lepton kinetic energy
539  double Tl = p4l.E() - ml;
540  // Final lepton scattering cosine
541  double ctl = p4l.CosTheta();
542 
543  kine_ptr->SetKV(kKVTl, Tl);
544  kine_ptr->SetKV(kKVctl, ctl);
545 
546  // All right, the event record is fully ready. Now ask the GReWeight
547  // objects to compute the weights.
548  weights[v].resize(num_knobs);
549  for (size_t k = 0u; k < num_knobs; ++k) {
550  weights[v][k] = reweightVector.at(k).CalcWeight(*genie_event);
551  }
552  }
553  return weights;
554  }
555 
557  const std::vector<genie::rew::GSyst_t>& knob_vec)
558  {
559  std::map<std::string, int> modes_to_use;
560 
561  for (const auto& knob : knob_vec) {
562  for (const auto& pair1 : INCOMPATIBLE_GENIE_KNOBS) {
563  std::string calc_name = pair1.first;
564  const auto& mode_map = pair1.second;
565  for (const auto& pair2 : mode_map) {
566  int mode = pair2.first;
567  std::set<genie::rew::GSyst_t> knob_set = pair2.second;
568 
569  if (knob_set.count(knob)) {
570  auto search = modes_to_use.find(calc_name);
571  if (search != modes_to_use.end()) {
572  if (search->second != mode) {
573  auto knob_str = genie::rew::GSyst::AsString(knob);
574  throw cet::exception(__PRETTY_FUNCTION__)
575  << this->GetName() << ": the GENIE knob " << knob_str << " is incompatible"
576  << " with others that are already configured";
577  }
578  }
579  else
580  modes_to_use[calc_name] = mode;
581  }
582  }
583  }
584  }
585 
586  return modes_to_use;
587  }
588 
589  void GenieWeightCalc::SetupWeightCalculators(genie::rew::GReWeight& rw,
590  const std::map<std::string, int>& modes_to_use)
591  {
592  // Based on the list from the GENIE command-line tool grwght1p
593  rw.AdoptWghtCalc("xsec_ncel", new GReWeightNuXSecNCEL);
594  rw.AdoptWghtCalc("xsec_ccqe", new GReWeightNuXSecCCQE);
595  rw.AdoptWghtCalc("xsec_ccqe_axial", new GReWeightNuXSecCCQEaxial);
596  rw.AdoptWghtCalc("xsec_ccqe_vec", new GReWeightNuXSecCCQEvec);
597  rw.AdoptWghtCalc("xsec_ccres", new GReWeightNuXSecCCRES);
598  rw.AdoptWghtCalc("xsec_ncres", new GReWeightNuXSecNCRES);
599  rw.AdoptWghtCalc("xsec_nonresbkg", new GReWeightNonResonanceBkg);
600  rw.AdoptWghtCalc("xsec_coh", new GReWeightNuXSecCOH);
601  rw.AdoptWghtCalc("xsec_dis", new GReWeightNuXSecDIS);
602  rw.AdoptWghtCalc("nuclear_qe", new GReWeightFGM);
603  rw.AdoptWghtCalc("hadro_res_decay", new GReWeightResonanceDecay);
604  rw.AdoptWghtCalc("hadro_fzone", new GReWeightFZone);
605  rw.AdoptWghtCalc("hadro_intranuke", new GReWeightINuke);
606  rw.AdoptWghtCalc("hadro_agky", new GReWeightAGKY);
607  rw.AdoptWghtCalc("xsec_nc", new GReWeightNuXSecNC);
608  rw.AdoptWghtCalc("res_dk", new GReWeightResonanceDecay);
609  rw.AdoptWghtCalc("xsec_empmec", new GReWeightXSecEmpiricalMEC);
610  // GReWeightDISNuclMod::CalcWeight() is not implemented, so we won't
611  // bother to use it here. - S. Gardiner, 9 Dec 2019
612  //rw.AdoptWghtCalc( "nuclear_dis", new GReWeightDISNuclMod );
613 
614 #ifdef GENIE_UB_PATCH
615 
616  // New weight calculator in GENIE v3.0.4 MicroBooNE patch 01
617  rw.AdoptWghtCalc("xsec_mec", new GReWeightXSecMEC);
618 
619  // New weight calculators in GENIE v3.0.4 MicroBooNE patch 02
620  rw.AdoptWghtCalc("deltarad_angle", new GReWeightDeltaradAngle);
621  rw.AdoptWghtCalc("xsec_coh_ub", new GReWeightNuXSecCOHuB);
622  rw.AdoptWghtCalc("res_bug_fix", new GReWeightRESBugFix);
623 
624 #endif
625 
626  // Set the modes for the weight calculators that need them to be specified
627  for (const auto& pair : modes_to_use) {
628  std::string calc_name = pair.first;
629  int mode = pair.second;
630 
631  genie::rew::GReWeightI* calc = rw.WghtCalc(calc_name);
632  if (!calc)
633  throw cet::exception(__PRETTY_FUNCTION__)
634  << "Failed to retrieve the GENIE weight calculator labeled \"" << calc_name << '\"';
635 
636  // The GReWeightI base class doesn't have a SetMode(int) function,
637  // so we'll just try dynamic casting until we get the right one.
638  // If none work, then throw an exception.
639  // TODO: Add a virtual function GReWeightI::SetMode( int ) in GENIE's
640  // Reweight framework. Then we can avoid the hacky dynamic casts here.
641  auto* calc_ccqe = dynamic_cast<genie::rew::GReWeightNuXSecCCQE*>(calc);
642  auto* calc_ccres = dynamic_cast<genie::rew::GReWeightNuXSecCCRES*>(calc);
643  auto* calc_ncres = dynamic_cast<genie::rew::GReWeightNuXSecNCRES*>(calc);
644  auto* calc_dis = dynamic_cast<genie::rew::GReWeightNuXSecDIS*>(calc);
645  if (calc_ccqe)
646  calc_ccqe->SetMode(mode);
647  else if (calc_ccres)
648  calc_ccres->SetMode(mode);
649  else if (calc_ncres)
650  calc_ncres->SetMode(mode);
651  else if (calc_dis)
652  calc_dis->SetMode(mode);
653  else
654  throw cet::exception(__PRETTY_FUNCTION__)
655  << "Request to set the mode of an unrecognized GENIE weight calculator \"" << calc_name
656  << '\"';
657  }
658  }
659 
661 }
genie::EventRecord * RetrieveGHEP(const simb::MCTruth &truth, const simb::GTruth &gtruth, bool useFirstTrajPosition=true)
return genie::EventRecord pointer; callee takes possession
Definition: GENIE2ART.cxx:540
Functions for transforming GENIE objects into ART objects (and back)
std::string GetName()
Definition: WeightCalc.h:26
std::map< std::string, int > CheckForIncompatibleSystematics(const std::vector< genie::rew::GSyst_t > &knob_vec)
object containing MC flux information
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
#define DECLARE_WEIGHTCALC(wghcalc)
T get(std::string const &key) const
Definition: ParameterSet.h:314
std::vector< std::vector< double > > GetWeight(art::Event &e) override
#define MF_LOG_INFO(category)
std::vector< std::string > get_all_keys() const
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
void SetupWeightCalculators(genie::rew::GReWeight &rw, const std::map< std::string, int > &modes_to_use)
#define MF_LOG_WARNING(category)
Float_t e
Definition: plot.C:35
PROD const & getProduct(InputTag const &tag) const
std::vector< genie::rew::GReWeight > reweightVector
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
#define REGISTER_WEIGHTCALC(wghcalc)
void Configure(const fhicl::ParameterSet &pset, CLHEP::HepRandomEngine &engine) override