MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
Weighter.cc
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17// Standard library includes
18#include <unordered_set>
19
20// HepMC3 includes
21#include "HepMC3/GenEvent.h"
22
23// MARLEY includes
24#include "marley/Error.hh"
25#include "marley/Generator.hh"
26#include "marley/JSON.hh"
27#include "marley/OMPWeightCalculator.hh"
28#include "marley/StrengthVariationWeightCalculator.hh"
29#include "marley/WeightCalculator.hh"
30#include "marley/Weighter.hh"
31
32// The fixed name of the central-value weight is defined by the NuHepMC
33// standard
34const std::string marley::Weighter::CV_WEIGHT_NAME = "CV";
35
36marley::Weighter::Weighter( const marley::JSON& config,
37 marley::Generator& gen ) {
38
39 // Always create a trivial weight calculator to handle the central-value
40 // weights, and add it to the vector of owned calculators
41 auto cv_wgt = make_cv_weight_calc();
42 calc_vec_.push_back( cv_wgt );
43
44 // Track all used weight names to detect duplicates
45 std::unordered_set< std::string > used_names{ CV_WEIGHT_NAME };
46
47 // Now parse the JSON configuration to instantiate any other requested
48 // weight calculators
49 if ( !config.is_array() ) {
50 throw marley::Error( "Non-array JSON configuration passed to constructor"
51 " of marley::Weighter" );
52 }
53
54 for ( const auto& obj : config.array_range() ) {
55
56 if ( !obj.is_object() ) {
57 throw marley::Error( "Each weight calculator configuration must be"
58 " specified as a JSON object" );
59 }
60
61 if ( !obj.has_key("type") ) {
62 throw marley::Error( "Missing \"type\" key in a weight calculator"
63 " JSON configuration" );
64 }
65
66 // Based on the type key included with each weight calculator
67 // configuration, build the appropriate kind of WeightCalculator object
68 std::shared_ptr< WeightCalculator > wc;
69 auto type = obj.at( "type" ).to_string();
70 if ( type == "trivial" ) {
71 auto twc = std::make_shared< marley::TrivialWeightCalculator >( obj );
72 wc = std::static_pointer_cast< marley::WeightCalculator >( twc );
73 }
74 else if ( type == "optical_model" ) {
75 auto omp_wc = std::make_shared< marley::OMPWeightCalculator >( obj );
76 wc = std::static_pointer_cast< marley::WeightCalculator >( omp_wc );
77 }
78 else if ( type == "strength_variation" ) {
79
80 // Delegate all config parsing to the static factory
81 auto instances = marley::StrengthVariationWeightCalculator
82 ::create_instances( obj, gen );
83
84 for ( auto& svc : instances ) {
85 if ( !used_names.insert( svc->name() ).second ) {
86 throw marley::Error( "Duplicate weight calculator name \""
87 + svc->name() + "\"" );
88 }
89 calc_vec_.push_back( svc );
90 }
91
92 // Skip the generic add at the bottom of the loop
93 continue;
94 }
95 // TODO: add more weight calculator types here
96 else {
97 throw marley::Error( "Unrecognized weight calculator type"
98 " specification \"" + type + '\"' );
99 }
100
101 // Check for duplicate weight names
102 if ( !used_names.insert( wc->name() ).second ) {
103 throw marley::Error( "Duplicate weight calculator name \""
104 + wc->name() + "\"" );
105 }
106
107 // Add the completed WeightCalculator object to the owned vector
108 calc_vec_.push_back( wc );
109
110 } // loop over weight calculator configuration JSON objects
111}
112
114 marley::Generator& gen )
115{
116 // Get non-const access to the vector of weights in the input event
117 auto& weights_vec = event.weights();
118 size_t num_weights = weights_vec.size();
119
120 // Double-check that we have exactly the right number of weight
121 // calculators configured
122 if ( num_weights != calc_vec_.size() ) {
123 throw marley::Error( "The number of configured weights is not the same"
124 " as the number of configured weight calculators" );
125 }
126
127 // Evaluate all configured weights and store the results in the event
128 auto temp_weights = compute_weights( event, gen );
129
130 for ( size_t w = 0u; w < num_weights; ++w ) {
131 double wgt = temp_weights.at( w );
132
133 // Preserve any pre-existing event weights by multiplying the
134 // current values in the event by the calculated result
135 double& evw = weights_vec.at( w );
136 evw *= wgt;
137 }
138
139}
140
141std::vector< double > marley::Weighter::compute_weights(
142 HepMC3::GenEvent& event, marley::Generator& gen ) const
143{
144 // Evaluate all configured weights and store the results in the output vector
145 std::vector< double > weights;
146 for ( const auto& weight_calc : calc_vec_ ) {
147 double wgt = weight_calc->weight( event, gen );
148 weights.push_back( wgt );
149 }
150 return weights;
151}
152
153std::vector< std::string > marley::Weighter::get_weight_names() const {
154 // Look up the name of each owned weight calculator and store the results in
155 // the output vector
156 std::vector< std::string > names;
157 for ( const auto& wgt_calc : calc_vec_ ) {
158 names.push_back( wgt_calc->name() );
159 }
160 return names;
161}
162
164 // Determine whether or not the CV weight is currently enabled by
165 // checking the first element of the vector of weight calculators
166 bool currently_using = false;
167 if ( !calc_vec_.empty() ) {
168 auto first_calc_name = calc_vec_.front()->name();
169 currently_using = ( first_calc_name == marley::Weighter::CV_WEIGHT_NAME );
170 }
171
172 // If the requested setting matches the current state, return without
173 // doing anything
174 if ( currently_using == use_it ) return;
175
176 // If we need to add it, then put a TrivialWeightCalculator with the
177 // correct name at the start of the vector
178 else if ( use_it ) {
179 auto cv_wgt_calc = make_cv_weight_calc();
180 calc_vec_.insert( calc_vec_.begin(), cv_wgt_calc );
181 return;
182 }
183
184 // If we need to remove it, then do so
185 else {
186 calc_vec_.erase( calc_vec_.begin() );
187 }
188}
189
190// Helper function to construct a trivial weight calculator to manage
191// the central-value weight assignment
192std::shared_ptr< marley::WeightCalculator > marley::Weighter
193 ::make_cv_weight_calc()
194{
195 marley::JSON temp_js;
196 temp_js[ "name" ] = marley::Weighter::CV_WEIGHT_NAME;
197 auto cv_wgt = std::make_shared< marley
198 ::TrivialWeightCalculator >( temp_js );
199 return std::static_pointer_cast< marley::WeightCalculator >( cv_wgt );
200}
Stores event-related information.
Definition GenEvent.h:47
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
The MARLEY Event generator.
Definition Generator.hh:54
static const std::string CV_WEIGHT_NAME
Reserved name for the central-value weights (required for compliance with the NuHepMC standard)
Definition Weighter.hh:63
std::vector< std::shared_ptr< WeightCalculator > > calc_vec_
Owned vector of weight calculators used to actually compute weights.
Definition Weighter.hh:67
std::vector< std::string > get_weight_names() const
Returns the names of the weights associated with all configured weight calculators.
Definition Weighter.cc:153
void set_use_cv_weight(bool use_it)
Toggles inclusion of the central-value weight.
Definition Weighter.cc:163
std::shared_ptr< marley::WeightCalculator > make_cv_weight_calc()
Helper function to create the weight calculator that handles the central-value weights during event g...
Definition Weighter.cc:193
virtual void process_event(HepMC3::GenEvent &event, marley::Generator &gen) override
Processes an input GenEvent object.
Definition Weighter.cc:113