All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
larsim/larsim/EventWeight/Calculators/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
18 #include "art/Framework/Principal/Event.h"
19 #include "cetlib_except/exception.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "fhiclcpp/ParameterSet.h"
22 
25 
26 #include "CLHEP/Random/RandGaussQ.h"
27 
28 #include "nugen/EventGeneratorBase/GENIE/GENIE2ART.h"
29 
30 #include "nusimdata/SimulationBase/MCFlux.h"
31 #include "nusimdata/SimulationBase/MCTruth.h"
32 #include "nusimdata/SimulationBase/GTruth.h"
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/RwFramework/GSystSet.h"
45 #include "GENIE/RwFramework/GSyst.h"
46 #include "GENIE/RwFramework/GReWeight.h"
47 #include "GENIE/RwCalculators/GReWeightNuXSecNCEL.h"
48 #include "GENIE/RwCalculators/GReWeightNuXSecCCQE.h"
49 #include "GENIE/RwCalculators/GReWeightNuXSecCCRES.h"
50 #include "GENIE/RwCalculators/GReWeightNuXSecCOH.h"
51 #include "GENIE/RwCalculators/GReWeightNonResonanceBkg.h"
52 #include "GENIE/RwCalculators/GReWeightFGM.h"
53 #include "GENIE/RwCalculators/GReWeightDISNuclMod.h"
54 #include "GENIE/RwCalculators/GReWeightResonanceDecay.h"
55 #include "GENIE/RwCalculators/GReWeightFZone.h"
56 #include "GENIE/RwCalculators/GReWeightINuke.h"
57 #include "GENIE/RwCalculators/GReWeightAGKY.h"
58 #include "GENIE/RwCalculators/GReWeightNuXSecCCQEaxial.h"
59 #include "GENIE/RwCalculators/GReWeightNuXSecCCQEvec.h"
60 #include "GENIE/RwCalculators/GReWeightNuXSecNCRES.h"
61 #include "GENIE/RwCalculators/GReWeightNuXSecDIS.h"
62 #include "GENIE/RwCalculators/GReWeightINukeParams.h"
63 #include "GENIE/RwCalculators/GReWeightNuXSecNC.h"
64 #include "GENIE/RwCalculators/GReWeightXSecEmpiricalMEC.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  { genie::rew::GReWeightNuXSecCCQE::kModeNormAndMaShape,
109  {
110  // Norm + shape
111  kXSecTwkDial_NormCCQE, // tweak CCQE normalization (energy independent)
112  kXSecTwkDial_MaCCQEshape, // tweak Ma CCQE, affects dsigma(CCQE)/dQ2 in shape only (normalized to constant integral)
113  kXSecTwkDial_E0CCQEshape // tweak E0 CCQE RunningMA, affects dsigma(CCQE)/dQ2 in shape only (normalized to constant integral)
114  }
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  },
123  { genie::rew::GReWeightNuXSecCCQE::kModeZExp,
124  {
125  // Z-expansion
126  kXSecTwkDial_ZNormCCQE, // tweak Z-expansion CCQE normalization (energy independent)
127  kXSecTwkDial_ZExpA1CCQE, // tweak Z-expansion coefficient 1, affects dsigma(CCQE)/dQ2 both in shape and normalization
128  kXSecTwkDial_ZExpA2CCQE, // tweak Z-expansion coefficient 2, affects dsigma(CCQE)/dQ2 both in shape and normalization
129  kXSecTwkDial_ZExpA3CCQE, // tweak Z-expansion coefficient 3, affects dsigma(CCQE)/dQ2 both in shape and normalization
130  kXSecTwkDial_ZExpA4CCQE // tweak Z-expansion coefficient 4, affects dsigma(CCQE)/dQ2 both in shape and normalization
131  }
132  },
133  } },
134 
135  // CCRES (genie::rew::GReWeightNuXSecCCRES)
136  { "xsec_ccres", {
137  { genie::rew::GReWeightNuXSecCCRES::kModeNormAndMaMvShape,
138  {
139  // Norm + shape
140  kXSecTwkDial_NormCCRES, /// tweak CCRES normalization
141  kXSecTwkDial_MaCCRESshape, /// tweak Ma CCRES, affects d2sigma(CCRES)/dWdQ2 in shape only (normalized to constant integral)
142  kXSecTwkDial_MvCCRESshape /// tweak Mv CCRES, affects d2sigma(CCRES)/dWdQ2 in shape only (normalized to constant integral)
143  }
144  },
145  { genie::rew::GReWeightNuXSecCCRES::kModeMaMv,
146  {
147  // Ma + Mv
148  kXSecTwkDial_MaCCRES, // tweak Ma CCRES, affects d2sigma(CCRES)/dWdQ2 both in shape and normalization
149  kXSecTwkDial_MvCCRES // tweak Mv CCRES, affects d2sigma(CCRES)/dWdQ2 both in shape and normalization
150  }
151  }
152  } },
153 
154  // NCRES (genie::rew::GReWeightNuXSecNCRES)
155  { "xsec_ncres", {
156  { genie::rew::GReWeightNuXSecNCRES::kModeNormAndMaMvShape,
157  {
158  // Norm + shape
159  kXSecTwkDial_NormNCRES, /// tweak NCRES normalization
160  kXSecTwkDial_MaNCRESshape, /// tweak Ma NCRES, affects d2sigma(NCRES)/dWdQ2 in shape only (normalized to constant integral)
161  kXSecTwkDial_MvNCRESshape /// tweak Mv NCRES, affects d2sigma(NCRES)/dWdQ2 in shape only (normalized to constant integral)
162  }
163  },
164  { genie::rew::GReWeightNuXSecNCRES::kModeMaMv,
165  {
166  // Ma + Mv
167  kXSecTwkDial_MaNCRES, // tweak Ma NCRES, affects d2sigma(NCRES)/dWdQ2 both in shape and normalization
168  kXSecTwkDial_MvNCRES // tweak Mv NCRES, affects d2sigma(NCRES)/dWdQ2 both in shape and normalization
169  }
170  }
171  } },
172 
173  // DIS (genie::rew::GReWeightNuXSecDIS)
174  { "xsec_dis", {
175  { genie::rew::GReWeightNuXSecDIS::kModeABCV12u,
176  {
177  kXSecTwkDial_AhtBY, // tweak the Bodek-Yang model parameter A_{ht} - incl. both shape and normalization effect
178  kXSecTwkDial_BhtBY, // tweak the Bodek-Yang model parameter B_{ht} - incl. both shape and normalization effect
179  kXSecTwkDial_CV1uBY, // tweak the Bodek-Yang model parameter CV1u - incl. both shape and normalization effect
180  kXSecTwkDial_CV2uBY // tweak the Bodek-Yang model parameter CV2u - incl. both shape and normalization effect
181  }
182  },
183  { genie::rew::GReWeightNuXSecDIS::kModeABCV12uShape,
184  {
185  kXSecTwkDial_AhtBYshape, // tweak the Bodek-Yang model parameter A_{ht} - shape only effect to d2sigma(DIS)/dxdy
186  kXSecTwkDial_BhtBYshape, // tweak the Bodek-Yang model parameter B_{ht} - shape only effect to d2sigma(DIS)/dxdy
187  kXSecTwkDial_CV1uBYshape, // tweak the Bodek-Yang model parameter CV1u - shape only effect to d2sigma(DIS)/dxdy
188  kXSecTwkDial_CV2uBYshape // tweak the Bodek-Yang model parameter CV2u - shape only effect to d2sigma(DIS)/dxdy
189  }
190  }
191  } }
192  };
193 
194 
195  // Helper function that checks whether a string storing a GENIE knob name is
196  // valid. Also stores the corresponding GSyst_t enum value for the knob.
197  bool valid_knob_name( const std::string& knob_name, genie::rew::GSyst_t& knob ) {
198  knob = genie::rew::GSyst::FromString( knob_name );
199  if ( knob != kNullSystematic && knob != kNTwkDials ) {
200  if ( UNIMPLEMENTED_GENIE_KNOBS.count(knob) ) {
201  MF_LOG_WARNING("GENIEWeightCalc") << "Ignoring unimplemented GENIE"
202  << " knob " << knob_name;
203  return false;
204  }
205  }
206  else {
207  throw cet::exception(__PRETTY_FUNCTION__) << "Encountered unrecognized"
208  "GENIE knob \"" << knob_name << '\"';
209  return false;
210  }
211  return true;
212  }
213 
214 
215  // Set of FHiCL weight calculator labels for which the tuned CV will be
216  // ignored. If the name of the weight calculator doesn't appear in this set,
217  // then variation weights will be thrown around the tuned CV.
218  std::set< std::string > CALC_NAMES_THAT_IGNORE_TUNED_CV = { "RootinoFix" };
219 
220 } // anonymous namespace
221 
222 namespace evwgh {
223  class GenieWeightCalc : public WeightCalc {
224  public:
225 
226  GenieWeightCalc();
227  void Configure(const fhicl::ParameterSet& pset,
228  CLHEP::HepRandomEngine& engine) override;
229  std::vector< std::vector<double> > GetWeight(art::Event& e) override;
230 
231  private:
232 
233  std::map< std::string, int > CheckForIncompatibleSystematics(
234  const std::vector<genie::rew::GSyst_t>& knob_vec);
235 
236  void SetupWeightCalculators(genie::rew::GReWeight& rw,
237  const std::map<std::string, int>& modes_to_use);
238 
239  std::vector< genie::rew::GReWeight > reweightVector;
240 
241  std::string fGenieModuleLabel;
242 
244 
246  };
247 
249  {}
250 
251  void GenieWeightCalc::Configure(const fhicl::ParameterSet& p,
252  CLHEP::HepRandomEngine& engine)
253  {
254  genie::Messenger* messenger = genie::Messenger::Instance();
255 
256  // By default, run GENIE reweighting in "quiet mode"
257  // (use the logging settings in the "whisper" configuration
258  // of the genie::Messenger class). The user can disable
259  // quiet mode using the boolean FHiCL parameter "quiet_mode"
260  fQuietMode = p.get<bool>( "quiet_mode", true );
261  if ( fQuietMode ) {
262  genie::utils::app_init::MesgThresholds( "Messenger_whisper.xml" );
263  }
264  else {
265  // If quiet mode isn't enabled, then print detailed debugging
266  // messages for GENIE reweighting
267  messenger->SetPriorityLevel( "ReW", log4cpp::Priority::DEBUG );
268 
269  MF_LOG_INFO("GENIEWeightCalc") << "Configuring GENIE weight"
270  << " calculator " << this->GetName();
271  }
272 
273  // Manually silence a couple of annoying GENIE logging messages
274  // that appear a lot when running reweighting. This is done
275  // whether or not "quiet mode" is enabled.
276  messenger->SetPriorityLevel( "TransverseEnhancementFFModel",
278  messenger->SetPriorityLevel( "Nieves", log4cpp::Priority::WARN );
279 
280  // Global Config
281  fGenieModuleLabel = p.get<std::string>( "genie_module_label" );
282 
283  // Parameter central values from a table in the global config
284  // Keys are GENIE knob names, values are knob settings that correspond to a tuned CV
285  const fhicl::ParameterSet& param_CVs = p.get<fhicl::ParameterSet>(
286  "genie_central_values", fhicl::ParameterSet() );
287  std::vector< std::string > CV_knob_names = param_CVs.get_all_keys();
288 
289  // Map to store the CV knob settings
290  std::map< genie::rew::GSyst_t, double > gsyst_to_cv_map;
291  genie::rew::GSyst_t temp_knob;
292 
293  if ( !CV_knob_names.empty() && !fQuietMode ) MF_LOG_INFO("GENIEWeightCalc")
294  << "Configuring non-default GENIE knob central values from input"
295  << " FHiCL parameter set";
296 
297  for ( const auto& knob_name : CV_knob_names ) {
298  double CV_knob_value = param_CVs.get<double>( knob_name );
299  if ( valid_knob_name(knob_name, temp_knob) ) {
300  if ( gsyst_to_cv_map.count( temp_knob ) ) {
301  throw cet::exception(__PRETTY_FUNCTION__) << "Duplicate central values"
302  << " were configured for the " << knob_name << " GENIE knob.";
303  }
304  gsyst_to_cv_map[ temp_knob ] = CV_knob_value;
305  if ( !fQuietMode ) {
306  MF_LOG_INFO("GENIEWeightCalc") << "Central value for the " << knob_name
307  << " knob was set to " << CV_knob_value;
308  }
309  }
310  }
311 
312  // Calc Config
313  const fhicl::ParameterSet& pset = p.get<fhicl::ParameterSet>( GetName() );
314  auto const pars = pset.get< std::vector<std::string> >( "parameter_list",
315  std::vector<std::string>() );
316  auto const par_sigmas = pset.get< std::vector<double> >( "parameter_sigma",
317  std::vector<double>() );
318 
319  // Parameter limits (currently only used in minmax mode)
320  // TODO: Revisit this. Could be useful for other modes.
321  auto const par_mins = pset.get< std::vector<double> >( "parameter_min",
322  std::vector<double>() );
323  auto const par_maxes = pset.get< std::vector<double> >( "parameter_max",
324  std::vector<double>() );
325 
326  auto const mode = pset.get<std::string>( "mode" );
327 
328  bool sigmas_ok = true;
329  std::string array_name_for_exception;
330  if ( mode.find("central_value") == std::string::npos
331  && mode.find("minmax") == std::string::npos )
332  {
333  // For most reweighting modes, make sure that the number 1-sigma values
334  // and the number of reweighting knobs match
335  if ( pars.size() != par_sigmas.size() ) {
336  sigmas_ok = false;
337  array_name_for_exception = "parameter_sigma";
338  }
339  }
340  else if ( mode.find("minmax") != std::string::npos ) {
341  if ( pars.size() != par_mins.size()
342  || pars.size() != par_maxes.size() )
343  {
344  // For "minmax" mode, do the same for both the minimum and maximum
345  // sigma values
346  sigmas_ok = false;
347  array_name_for_exception = "parameter_min and parameter_max";
348  }
349  }
350 
351  if ( !sigmas_ok ) {
352  throw cet::exception(__PRETTY_FUNCTION__) << GetName()
353  << "::Bad fcl configuration. parameter_list and "
354  << array_name_for_exception
355  << " need to have same number of parameters.";
356  }
357 
358  if ( !pars.empty() && !fQuietMode ) MF_LOG_INFO("GENIEWeightCalc") << "Configuring"
359  << " GENIE systematic knobs to be varied from the input FHiCL parameter set";
360 
361  // Convert the list of GENIE knob names from the input FHiCL configuration
362  // into a vector of genie::rew::GSyst_t labels
363  std::vector< genie::rew::GSyst_t > knobs_to_use;
364  for ( const auto& knob_name : pars ) {
365  if ( valid_knob_name(knob_name, temp_knob) ) knobs_to_use.push_back( temp_knob );
366  }
367 
368  // We need to add all of the tuned CV knobs to the list when configuring
369  // the weight calculators and checking for incompatibilities. Maybe all of
370  // the systematic variation knobs are fine to use together, but they also
371  // need to be compatible with the tuned CV. To perform the check, copy the
372  // list of systematic variation knobs to use and add all the CV knobs that
373  // aren't already present.
374  std::vector< genie::rew::GSyst_t > all_knobs_vec = knobs_to_use;
375  for ( const auto& pair : gsyst_to_cv_map ) {
376  genie::rew::GSyst_t cv_knob = pair.first;
377  auto begin = all_knobs_vec.cbegin();
378  auto end = all_knobs_vec.cend();
379  if ( !std::count(begin, end, cv_knob) ) all_knobs_vec.push_back( cv_knob );
380  }
381 
382  // Check that the enabled knobs (both systematic variations and knobs used
383  // for the CV tune) are all compatible with each other. The std::map
384  // returned by this function call provides information needed to fine-tune
385  // the configuration of the GENIE weight calculators.
386  std::map< std::string, int >
387  modes_to_use = this->CheckForIncompatibleSystematics( all_knobs_vec );
388 
389  // If we're working in "pm1sigma" or "minmax" mode, there should only be two
390  // universes regardless of user input.
391  size_t num_universes = 0u;
392  if ( mode.find("pm1sigma") != std::string::npos
393  || mode.find("minmax") != std::string::npos )
394  {
395  num_universes = 2u;
396  }
397  else if ( mode.find("multisim") != std::string::npos ) {
398  num_universes = pset.get<size_t>( "number_of_multisims" );
399 
400  // Since we're in multisim mode, force retrieval of the random
401  // number seed. If it wasn't set, this will trigger an exception.
402  // We want this check because otherwise the multisim universes
403  // will not be easily reproducible.
404  int dummy_seed = pset.get<int>( "random_seed" );
405  MF_LOG_INFO("GENIEWeightCalc") << "GENIE weight calculator "
406  << this->GetName() << " will generate " << num_universes
407  << " multisim universes with random seed " << dummy_seed;
408  }
409  // If we're working in "central_value" or "default" mode, only a single
410  // universe should be used
411  else {
412  num_universes = 1u;
413  }
414 
415  // Create one default-constructed genie::rew::GReWeight object per universe
416  reweightVector.resize( num_universes );
417 
418  // Set up the weight calculators for each universe
419  for ( auto& rwght : reweightVector ) {
420  this->SetupWeightCalculators( rwght, modes_to_use );
421  }
422 
423  // Prepare sigmas
424  size_t num_usable_knobs = knobs_to_use.size();
425  std::vector< std::vector<double> > reweightingSigmas( num_usable_knobs );
426 
427  for ( size_t k = 0u; k < num_usable_knobs; ++k ) {
428  reweightingSigmas[k].resize( num_universes );
429 
430  genie::rew::GSyst_t current_knob = knobs_to_use.at( k );
431 
432  for ( size_t u = 0u; u < num_universes; ++u ) {
433  if ( mode.find("multisim") != std::string::npos ) {
434  reweightingSigmas[k][u] = par_sigmas[k] * CLHEP::RandGaussQ::shoot(&engine, 0., 1.);
435  }
436  else if ( mode.find("pm1sigma") != std::string::npos ) {
437  // u == 0 => +1*sigma; u == 1 => -1*sigma if pm1sigma is specified
438  reweightingSigmas[k][u] = ( u == 0 ? 1. : -1. ) * par_sigmas.at(k);
439  }
440  else if ( mode.find("minmax") != std::string::npos ) {
441  // u == 0 => max; u == 1 => min if minmax is specified
442  reweightingSigmas[k][u] = ( u == 0 ? par_maxes.at(k) : par_mins.at(k) );
443  }
444  else if ( mode.find("central_value") != std::string::npos ) {
445  // We'll correct for a modified CV below if needed
446  reweightingSigmas[k][u] = 0.;
447  }
448  else {
449  // By default, use the exact sigma value given for each knob
450  reweightingSigmas[k][u] = par_sigmas[k];
451  }
452 
453  if ( !fQuietMode ) MF_LOG_INFO("GENIEWeightCalc")
454  << "Set sigma for the " << genie::rew::GSyst::AsString( current_knob )
455  << " knob in universe #" << u << ". sigma = "
456  << reweightingSigmas[k][u];
457 
458  // Add an offset if the central value for the current knob has been
459  // configured (and is thus probably nonzero). Ignore this for minmax
460  // mode (the limits should be chosen to respect a modified central
461  // value)
462  if ( mode.find("minmax") == std::string::npos ) {
463  auto iter = gsyst_to_cv_map.find( current_knob );
464  if ( iter != gsyst_to_cv_map.end() ) {
465  reweightingSigmas[k][u] += iter->second;
466  if ( !fQuietMode ) MF_LOG_INFO("GENIEWeightCalc")
467  << "CV offset added to the "
468  << genie::rew::GSyst::AsString( current_knob )
469  << " knob. New sigma for universe #" << u << " is "
470  << reweightingSigmas[k][u];
471  }
472  }
473  }
474  }
475 
476  // Don't adjust knobs to reflect the tuned CV if this weight calculator
477  // should ignore those (as determined by whether it has one of the special
478  // FHiCL names)
479  if ( !CALC_NAMES_THAT_IGNORE_TUNED_CV.count(this->GetName()) ) {
480 
481  // Add tuned CV knobs which have not been tweaked, and set them to their
482  // modified central values. This ensures that weights are always thrown
483  // around the modified CV.
484  for ( const auto& pair : gsyst_to_cv_map ) {
485  genie::rew::GSyst_t cv_knob = pair.first;
486  double cv_value = pair.second;
487 
488  // If the current tuned CV knob is not present in the list of tweaked
489  // knobs, then add it to the list with its tuned central value
490  if ( !std::count(knobs_to_use.cbegin(), knobs_to_use.cend(), cv_knob) ) {
491  ++num_usable_knobs;
492  knobs_to_use.push_back( cv_knob );
493 
494  // The tuned CV knob will take the same value in every universe
495  reweightingSigmas.emplace_back(
496  std::vector<double>(num_universes, cv_value) );
497 
498  if ( !fQuietMode ) MF_LOG_INFO("GENIEWeightCalc")
499  << "Tuned knob " << genie::rew::GSyst::AsString( cv_knob )
500  << " was not configured. Setting it to " << cv_value
501  << " in all " << num_universes << " universes.";
502  }
503  }
504  }
505 
506  // TODO: deal with parameters that have a priori bounds (e.g., FFCCQEVec,
507  // which can vary on the interval [0,1])
508 
509  // Set up the knob values for each universe
510  for ( size_t u = 0; u < reweightVector.size(); ++u ) {
511 
512  auto& rwght = reweightVector.at( u );
513  genie::rew::GSystSet& syst = rwght.Systematics();
514 
515  for ( unsigned int k = 0; k < knobs_to_use.size(); ++k ) {
516  genie::rew::GSyst_t knob = knobs_to_use.at( k );
517 
518  double twk_dial_value = reweightingSigmas.at( k ).at( u );
519  syst.Set( knob, twk_dial_value );
520 
521  if ( !fQuietMode ) {
522  MF_LOG_INFO("GENIEWeightCalc") << "In universe #" << u << ", knob #" << k
523  << " (" << genie::rew::GSyst::AsString( knob ) << ") was set to"
524  << " the value " << twk_dial_value;
525  }
526  } // loop over tweaked knobs
527 
528  rwght.Reconfigure();
529  rwght.Print();
530  } // loop over universes
531 
532  }
533 
534  // Returns a vector of weights for each neutrino interaction in the event
535  std::vector<std::vector<double> > GenieWeightCalc::GetWeight(art::Event & e)
536  {
537  // Get the MC generator information out of the event
538  // These are both handles to MC information.
539  art::Handle< std::vector<simb::MCTruth> > mcTruthHandle;
540  art::Handle< std::vector<simb::GTruth> > gTruthHandle;
541 
542  // Actually go and get the stuff
543  e.getByLabel( fGenieModuleLabel, mcTruthHandle );
544  e.getByLabel( fGenieModuleLabel, gTruthHandle );
545 
546  std::vector< art::Ptr<simb::MCTruth> > mclist;
547  art::fill_ptr_vector( mclist, mcTruthHandle );
548 
549  std::vector< art::Ptr<simb::GTruth > > glist;
550  art::fill_ptr_vector( glist, gTruthHandle );
551 
552  size_t num_neutrinos = mclist.size();
553  size_t num_knobs = reweightVector.size();
554 
555  // Calculate weight(s) here
556  std::vector< std::vector<double> > weights( num_neutrinos );
557  for ( size_t v = 0u; v < num_neutrinos; ++v ) {
558 
559  // Convert the MCTruth and GTruth objects from the event
560  // back into the original genie::EventRecord needed to
561  // compute the weights
562  std::unique_ptr< genie::EventRecord >
563  genie_event( evgb::RetrieveGHEP(*mclist[v], *glist[v]) );
564 
565  // Set the final lepton kinetic energy and scattering cosine
566  // in the owned GENIE kinematics object. This is done during
567  // event generation but is not reproduced by evgb::RetrieveGHEP().
568  // Several new CCMEC weight calculators developed for MicroBooNE
569  // expect the variables to be set in this way (so that differential
570  // cross sections can be recomputed). Failing to set them results
571  // in inf and NaN weights.
572  // TODO: maybe update evgb::RetrieveGHEP to handle this instead.
573  genie::Interaction* interaction = genie_event->Summary();
574  genie::Kinematics* kine_ptr = interaction->KinePtr();
575 
576  // Final lepton mass
577  double ml = interaction->FSPrimLepton()->Mass();
578  // Final lepton 4-momentum
579  const TLorentzVector& p4l = kine_ptr->FSLeptonP4();
580  // Final lepton kinetic energy
581  double Tl = p4l.E() - ml;
582  // Final lepton scattering cosine
583  double ctl = p4l.CosTheta();
584 
585  kine_ptr->SetKV( kKVTl, Tl );
586  kine_ptr->SetKV( kKVctl, ctl );
587 
588  // All right, the event record is fully ready. Now ask the GReWeight
589  // objects to compute the weights.
590  weights[v].resize( num_knobs );
591  for (size_t k = 0u; k < num_knobs; ++k ) {
592  weights[v][k] = reweightVector.at( k ).CalcWeight( *genie_event );
593  }
594  }
595  return weights;
596 
597  }
598 
600  const std::vector<genie::rew::GSyst_t>& knob_vec)
601  {
602  std::map< std::string, int > modes_to_use;
603 
604  for ( const auto& knob : knob_vec ) {
605  for ( const auto& pair1 : INCOMPATIBLE_GENIE_KNOBS ) {
606  std::string calc_name = pair1.first;
607  const auto& mode_map = pair1.second;
608  for ( const auto& pair2 : mode_map ) {
609  int mode = pair2.first;
610  std::set<genie::rew::GSyst_t> knob_set = pair2.second;
611 
612  if ( knob_set.count(knob) ) {
613  auto search = modes_to_use.find( calc_name );
614  if ( search != modes_to_use.end() ) {
615  if ( search->second != mode ) {
616  auto knob_str = genie::rew::GSyst::AsString( knob );
617  throw cet::exception(__PRETTY_FUNCTION__) << this->GetName()
618  << ": the GENIE knob " << knob_str << " is incompatible"
619  << " with others that are already configured";
620  }
621  }
622  else modes_to_use[ calc_name ] = mode;
623  }
624  }
625  }
626  }
627 
628  return modes_to_use;
629  }
630 
631  void GenieWeightCalc::SetupWeightCalculators(genie::rew::GReWeight& rw,
632  const std::map<std::string, int>& modes_to_use)
633  {
634  // Based on the list from the GENIE command-line tool grwght1p
635  rw.AdoptWghtCalc( "xsec_ncel", new GReWeightNuXSecNCEL );
636  rw.AdoptWghtCalc( "xsec_ccqe", new GReWeightNuXSecCCQE );
637  rw.AdoptWghtCalc( "xsec_ccqe_axial", new GReWeightNuXSecCCQEaxial );
638  rw.AdoptWghtCalc( "xsec_ccqe_vec", new GReWeightNuXSecCCQEvec );
639  rw.AdoptWghtCalc( "xsec_ccres", new GReWeightNuXSecCCRES );
640  rw.AdoptWghtCalc( "xsec_ncres", new GReWeightNuXSecNCRES );
641  rw.AdoptWghtCalc( "xsec_nonresbkg", new GReWeightNonResonanceBkg );
642  rw.AdoptWghtCalc( "xsec_coh", new GReWeightNuXSecCOH );
643  rw.AdoptWghtCalc( "xsec_dis", new GReWeightNuXSecDIS );
644  rw.AdoptWghtCalc( "nuclear_qe", new GReWeightFGM );
645  rw.AdoptWghtCalc( "hadro_res_decay", new GReWeightResonanceDecay );
646  rw.AdoptWghtCalc( "hadro_fzone", new GReWeightFZone );
647  rw.AdoptWghtCalc( "hadro_intranuke", new GReWeightINuke );
648  rw.AdoptWghtCalc( "hadro_agky", new GReWeightAGKY );
649  rw.AdoptWghtCalc( "xsec_nc", new GReWeightNuXSecNC );
650  rw.AdoptWghtCalc( "res_dk", new GReWeightResonanceDecay );
651  rw.AdoptWghtCalc( "xsec_empmec", new GReWeightXSecEmpiricalMEC);
652  // GReWeightDISNuclMod::CalcWeight() is not implemented, so we won't
653  // bother to use it here. - S. Gardiner, 9 Dec 2019
654  //rw.AdoptWghtCalc( "nuclear_dis", new GReWeightDISNuclMod );
655 
656  #ifdef GENIE_UB_PATCH
657 
658  // New weight calculator in GENIE v3.0.4 MicroBooNE patch 01
659  rw.AdoptWghtCalc( "xsec_mec", new GReWeightXSecMEC );
660 
661  // New weight calculators in GENIE v3.0.4 MicroBooNE patch 02
662  rw.AdoptWghtCalc( "deltarad_angle", new GReWeightDeltaradAngle );
663  rw.AdoptWghtCalc( "xsec_coh_ub", new GReWeightNuXSecCOHuB );
664  rw.AdoptWghtCalc( "res_bug_fix", new GReWeightRESBugFix );
665 
666  #endif
667 
668  // Set the modes for the weight calculators that need them to be specified
669  for ( const auto& pair : modes_to_use ) {
670  std::string calc_name = pair.first;
671  int mode = pair.second;
672 
673  genie::rew::GReWeightI* calc = rw.WghtCalc( calc_name );
674  if ( !calc ) throw cet::exception(__PRETTY_FUNCTION__)
675  << "Failed to retrieve the GENIE weight calculator labeled \""
676  << calc_name << '\"';
677 
678  // The GReWeightI base class doesn't have a SetMode(int) function,
679  // so we'll just try dynamic casting until we get the right one.
680  // If none work, then throw an exception.
681  // TODO: Add a virtual function GReWeightI::SetMode( int ) in GENIE's
682  // Reweight framework. Then we can avoid the hacky dynamic casts here.
683  auto* calc_ccqe = dynamic_cast< genie::rew::GReWeightNuXSecCCQE* >( calc );
684  auto* calc_ccres = dynamic_cast< genie::rew::GReWeightNuXSecCCRES* >( calc );
685  auto* calc_ncres = dynamic_cast< genie::rew::GReWeightNuXSecNCRES* >( calc );
686  auto* calc_dis = dynamic_cast< genie::rew::GReWeightNuXSecDIS* >( calc );
687  if ( calc_ccqe ) calc_ccqe->SetMode( mode );
688  else if ( calc_ccres ) calc_ccres->SetMode( mode );
689  else if ( calc_ncres ) calc_ncres->SetMode( mode );
690  else if ( calc_dis ) calc_dis->SetMode( mode );
691  else throw cet::exception(__PRETTY_FUNCTION__)
692  << "Request to set the mode of an unrecognized GENIE weight calculator \""
693  << calc_name << '\"';
694  }
695  }
696 
698 }
pdgs p
Definition: selectors.fcl:22
std::map< std::string, int > CheckForIncompatibleSystematics(const std::vector< genie::rew::GSyst_t > &knob_vec)
const char mode
Definition: noise_ana.cxx:20
MF_LOG_WARNING("SimWire")<< "SimWire is an example module that works for the "<< "MicroBooNE detector. Each experiment should implement "<< "its own version of this module to simulate electronics "<< "response."
std::string FromString(const std::string &value)
Definition: Parser.cxx:8
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
std::vector< std::vector< double > > GetWeight(art::Event &e) override
createEngine this
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
#define REGISTER_WEIGHTCALC(wghcalc)
do i e
void SetupWeightCalculators(genie::rew::GReWeight &rw, const std::map< std::string, int > &modes_to_use)
pdgs k
Definition: selectors.fcl:22
std::size_t count(Cont const &cont)
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
void Configure(const fhicl::ParameterSet &pset, CLHEP::HepRandomEngine &engine) override