Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:09:57

0001 #ifndef ATOOLS_Phys_Event_Weights_H
0002 #define ATOOLS_Phys_Event_Weights_H
0003 
0004 #include "ATOOLS/Org/My_MPI.H"
0005 #include "ATOOLS/Org/MyStrStream.H"
0006 #include "ATOOLS/Phys/Variations.H"
0007 
0008 #include <algorithm>
0009 #include <cassert>
0010 #include <functional>
0011 
0012 namespace ATOOLS {
0013 
0014   class Weights_Map;
0015 
0016   class Weights {
0017 
0018   public:
0019 
0020     Weights(double w = 1.0) : type {Variations_Type::custom}, weights {w} {};
0021     Weights(Variations_Type t, double w=1.0);
0022 
0023     explicit operator double() const { return Nominal(); }
0024 
0025     // general information getters
0026     Variations_Type Type() const { return type; }
0027     size_t Size() const { return weights.size(); }
0028     bool HasVariations() const { return weights.size() > 1; }
0029     bool IsZero() const;
0030 
0031     // content getters/setters to access individual weights, by index or name
0032     std::string Name(size_t, Variations_Source source = Variations_Source::all,
0033                      Variations_Name_Type name_type =
0034                          Variations_Name_Type::weight_name_convention) const;
0035     double& Nominal();
0036     double Nominal() const;
0037     double& Variation(size_t i);
0038     double& operator[](size_t i) { return weights[i]; }
0039     double operator[](size_t i) const { return weights[i]; }
0040     double& operator[](const std::string& name);
0041 
0042     /// Assign the same value to all weights.
0043     Weights& operator=(double);
0044 
0045     /// Multiply or divide all weights by the same value.
0046     Weights& operator*=(double);
0047     friend Weights operator*(Weights, double);
0048     Weights& operator/=(double rhs) { return operator*=(1.0 / rhs); }
0049     friend Weights operator/(Weights, double);
0050 
0051     /// Multiply by another set of weights weight-by-weight. This is only
0052     /// allowed if one set of weights has only a single entry, or both sets of
0053     /// weights have the same number of entries and the same variations type.
0054     Weights& operator*=(const Weights&);
0055     friend Weights operator*(Weights, Weights);
0056 
0057     /// Multiply by a vector of values element-by-element. This is only
0058     /// allowed if the weights or the vector have only a single entry, or
0059     /// they both have the same number of elements. Note that for managed
0060     /// variation types like QCD or Qcut variations, the number of vector
0061     /// elements must be either 1 or match the number of variations plus one
0062     /// (for the nominal entry).
0063     template <class T> Weights& operator*=(const std::vector<T>&);
0064 
0065     /// Add or subtract another set of weights weight-by-weight. This is only
0066     /// allowed if both sets of weights have the same number of entries and the
0067     /// same variations type.
0068     Weights& operator+=(const Weights&);
0069     friend Weights operator+(Weights, Weights);
0070     Weights& operator-=(const Weights&);
0071     friend Weights operator-(Weights, Weights);
0072 
0073     /// Create a copy with the sign of all weights swapped.
0074     Weights operator-() const;
0075 
0076     // Reweight functions for variation types managed by the Variations class,
0077     // that make it easy to iterate over all variations. The variants with the
0078     // suffix "All" also include the nominal entry in the iteration; as such
0079     // they pass the variation parameters as a pointer that is NULL for the
0080     // nominal entry.
0081 
0082     // QCD variations
0083     friend void Reweight(
0084         Weights&,
0085         std::function<double(double, QCD_Variation_Params&)>);
0086     friend void Reweight(
0087         Weights&,
0088         std::function<double(double, size_t varindex, QCD_Variation_Params&)>);
0089     friend void ReweightAll(
0090         Weights&,
0091         std::function<double(double, size_t varindex, QCD_Variation_Params*)>);
0092 
0093     // Qcut variations
0094     friend void Reweight(
0095         Weights&,
0096         std::function<double(double, Qcut_Variation_Params&)>);
0097     friend void Reweight(
0098         Weights&,
0099         std::function<double(double, size_t varindex, Qcut_Variation_Params&)>);
0100     friend void ReweightAll(
0101         Weights&,
0102         std::function<double(double, size_t varindex, Qcut_Variation_Params*)>);
0103 
0104     friend std::ostream& operator<<(std::ostream&, const Weights&);
0105 
0106     friend Weights_Map;
0107 
0108   private:
0109 
0110     /// Check if only a single value is present, and that no type has been set.
0111     bool IsUnnamedScalar() const;
0112 
0113     Variations_Type type;
0114     std::vector<double> weights;
0115     std::vector<std::string> names;
0116   };
0117 
0118   class Weights_Map : public std::map<std::string, Weights> {
0119 
0120   public:
0121 
0122     Weights_Map(double w=1.0) : base_weight{w} {};
0123 
0124     explicit operator double() const { return Nominal(); }
0125 
0126     /// Clears the content and sets the base weight to 1.0. The object is then
0127     /// equal to a newly default-constructed instance. Use this instead of the
0128     /// parent class member function `clear`.
0129     void Clear();
0130 
0131     // general information getters
0132     double Get(const std::string&, size_t) const;
0133     bool HasVariations() const;
0134     bool IsZero() const;
0135     double BaseWeight() const { return base_weight; }
0136 
0137     // Convenience method to fill e.g. an ordinary map with variations; passing
0138     // Variations_Source::main only fills ME QCD-like variations (discarding
0139     // ones that originate from the shower), while passing
0140     // Variations_Source::all fill all variation (including custom one).
0141     template <typename T>
0142     void FillVariations(
0143         T &, Variations_Source source = ATOOLS::Variations_Source::all,
0144         Variations_Name_Type name_type =
0145             ATOOLS::Variations_Name_Type::weight_name_convention) const;
0146 
0147     // calculate nominal values, either including all entries, for a single
0148     // entry `k`, or excluding those that have a certain variation type
0149     double Nominal() const;
0150     double Nominal(const std::string& k) const;
0151     double NominalIgnoringVariationType(Variations_Type) const;
0152 
0153     // return relative Weights entries for a given name
0154     Weights& RelativeValues(const std::string& k) { return (*this)[k]; }
0155     Weights RelativeValues(const std::string& k) const;
0156 
0157     /// Calculate the product of all entries that share the same type, e.g. to
0158     /// get the combined QCD or Qcut variations from different sources. Note
0159     /// that this returns a Weights object, that contains the nominal product
0160     /// and the entry-by-entry product of all variations.
0161     Weights Combine(Variations_Type type) const;
0162 
0163     /// Set all values to exactly 0.0 that are close to zero. The tolerance
0164     /// is the maximum absolute distance from 0.0 defining this "closeness".
0165     /// This might be useful e.g. before calculating the square root.
0166     void SetZeroIfCloseToZero(double tolerance);
0167 
0168     /// Assign a value to the base weight
0169     Weights_Map& operator=(double w) { base_weight = w; return *this; }
0170 
0171     /// Multiply or divide the base weight
0172     Weights_Map& operator*=(double w) { base_weight *= w; return *this; }
0173     friend Weights_Map operator*(Weights_Map, double);
0174     Weights_Map& operator/=(double w) { base_weight /= w; return *this; }
0175     friend Weights_Map operator/(Weights_Map, double);
0176 
0177     /// Multiply by another weights map. If both maps share a key, the
0178     /// associated set of weights are multiplied with each other. If a key
0179     /// exists only in one of the maps, the associated set of weights will be
0180     /// present unchanged in the result. This is in accordance with the
0181     /// implicit assumption that an entry that does not exist explicitly has a
0182     /// weight of unit.
0183     Weights_Map& operator*=(const Weights_Map&);
0184     friend Weights_Map operator*(Weights_Map, const Weights_Map&);
0185 
0186     /// Add or subtract another weights map. This also makes the same implicit
0187     /// assumption that non-existing values are implicitly set to unity.
0188     Weights_Map& operator+=(const Weights_Map&);
0189     Weights_Map& operator-=(const Weights_Map&);
0190     friend Weights_Map operator+(Weights_Map, const Weights_Map&);
0191     friend Weights_Map operator-(Weights_Map, const Weights_Map&);
0192 
0193     friend Weights_Map sqrt(const Weights_Map&);
0194 
0195     friend std::ostream& operator<<(std::ostream&, const Weights_Map&);
0196 
0197     // generate variants where entries are absolute, or relative (the default);
0198     // this can be used to simplify operations dealing with individual entries
0199     // one-by-one, in particular when doing additions/subtractions
0200     void MakeRelative();
0201     void MakeAbsolute();
0202 
0203 #ifdef USING__MPI
0204     // Using MPI Allreduce to combine weight maps from different MPI ranks;
0205     // this should not done too often, as it requires to synchronise the entire
0206     // structure of the weights maps, which in turn requires a nontrivial
0207     // amount of communication between the MPI ranks.
0208     void MPI_Allreduce();
0209 #endif
0210 
0211   private:
0212 
0213     // make sure class users use our Clear() instead map's clear()
0214     using std::map<std::string, Weights>::clear;
0215 
0216     // same as Nominal(), but excluding the nominals_prefactor
0217     double NominalIgnoringPrefactor() const;
0218 
0219     /// While the Weights object in the map store relative factors due to
0220     /// specific variations or additional factors (like branching ratios), the
0221     /// base weight gives the overall scale of all weights. This is always
0222     /// taken as a prefactor when retrieving weights through Weights_Map member
0223     /// functions. A weights map that is implicitly constructed from a double
0224     /// (e.g. by returning 0.0 from a function that has Weights_Map as its
0225     /// return type) will have its base_weight set to this double, while it is
0226     /// otherwise empty.
0227     double base_weight;
0228 
0229     /// This is similar to the base weight, but is only applied to the nominal
0230     /// values of each Weights entry. This should usually be 1.0 or 0.0. While
0231     /// this seems redundant at first, it is not. Since all nominal values will
0232     /// always be applied as prefactors when calculating variations, it can be
0233     /// useful to store a zero in this member variable and set the actual
0234     /// nominal to a finite value like 1.0, even though it is formally zero. By
0235     /// this trick, we can have non-zero variations while all nominals are
0236     /// zero.
0237     double nominals_prefactor {1.0};
0238 
0239     bool is_absolute {false};
0240   };
0241 
0242   template <class T> Weights& Weights::operator*=(const std::vector<T>& rhs)
0243   {
0244     const auto size = weights.size();
0245     // either we have n*1, or 1*n, or n*n
0246     assert(rhs.size() == 1 || weights.size() == 1 ||
0247            weights.size() == rhs.size());
0248     if (size == 1) {
0249       // 1*n
0250       assert(type != Variations_Type::custom);
0251       assert(type == Variations_Type::qcd
0252                  ? rhs.size() == s_variations->Size(Variations_Type::qcd) + 1
0253                  : true);
0254       assert(type == Variations_Type::qcut
0255                  ? rhs.size() == s_variations->Size(Variations_Type::qcut) + 1
0256                  : true);
0257       const auto weight = Nominal();
0258       weights.clear();
0259       weights.reserve(rhs.size());
0260       std::copy(rhs.begin(), rhs.end(), std::back_inserter(weights));
0261       (*this) *= weight;
0262     } else if (rhs.size() > 1) {
0263       // n*n
0264       for (int i {0}; i < weights.size(); ++i) {
0265         weights[i] *= rhs[i];
0266       }
0267     } else {
0268       // n*1
0269       (*this) *= rhs[0];
0270     }
0271     return *this;
0272   }
0273 
0274   Weights operator*(Weights, double);
0275   Weights operator/(Weights, double);
0276   Weights operator*(Weights, Weights);
0277   Weights operator+(Weights, Weights);
0278   Weights operator-(Weights, Weights);
0279 
0280   std::ostream& operator<<(std::ostream&, const Weights&);
0281 
0282   void Reweight(
0283       Weights&,
0284       std::function<double(double, QCD_Variation_Params&)>);
0285   void Reweight(
0286       Weights&,
0287       std::function<double(double, size_t varindex, QCD_Variation_Params&)>);
0288   void ReweightAll(
0289       Weights&,
0290       std::function<double(double, size_t varindex, QCD_Variation_Params*)>);
0291   void Reweight(
0292       Weights&,
0293       std::function<double(double, Qcut_Variation_Params&)>);
0294   void Reweight(
0295       Weights&,
0296       std::function<double(double, size_t varindex, Qcut_Variation_Params&)>);
0297   void ReweightAll(
0298       Weights&,
0299       std::function<double(double, size_t varindex, Qcut_Variation_Params*)>);
0300 
0301   template <typename T>
0302   void Weights_Map::FillVariations(T &map, Variations_Source source,
0303                                    Variations_Name_Type name_type) const {
0304     DEBUG_FUNC(source);
0305 
0306     // Fill "managed" QCD variations, which might need to be combined first,
0307     // since we have QCD variations from "ME", "PS", etc., hence we need to
0308     // build a product over those for each individual QCD variation.
0309     for (const auto type : s_variations->ManagedVariationTypes()) {
0310       // calculate contributions
0311       Weights weights = Weights {type};
0312       double relfac {1.0};
0313       if (source == Variations_Source::all) {
0314         weights *= Combine(type);
0315         relfac = NominalIgnoringVariationType(type);
0316       } else {
0317         // calculate nominal, relfac and weights ignoring shower weights
0318         static const std::unordered_set<std::string> shower_keys {
0319           "PS", "PS_QCUT", "MC@NLO_PS", "MC@NLO_QCUT"};
0320         for (const auto& v : *this) {
0321           if (shower_keys.find(v.first) != shower_keys.end())
0322             continue;
0323           if (v.second.Type() == type) {
0324             weights *= v.second;
0325           } else {
0326             relfac *= v.second.Nominal();
0327           }
0328         }
0329         relfac *= base_weight;
0330       }
0331       // do remaining combination and store resulting weights
0332       size_t num_vars = weights.Size() - 1;
0333       for (size_t i(0); i < num_vars; ++i) {
0334         const std::string varname {weights.Name(i + 1, source, name_type)};
0335         map[varname] = weights.Variation(i) * relfac;
0336         msg_Debugging() << varname << " (" << varname
0337           << "): " << weights.Variation(i) * relfac << '\n';
0338       }
0339     }
0340 
0341     // Fill other "custom" variations. These are simple, because they are all
0342     // assumed to be independent from each other, hence no combination is
0343     // necessary.
0344     if (source == Variations_Source::all) {
0345       for (const auto& kv : *this) {
0346         if (kv.second.Type() != Variations_Type::custom)
0347           continue;
0348         const auto size = kv.second.Size();
0349         // Iterate weights, skipping the nominal entry (at position 0).
0350         for (size_t i {1}; i < size; ++i) {
0351           map[kv.first + "." + kv.second.Name(i)] =
0352               Nominal() / kv.second.Nominal() * kv.second[i];
0353         }
0354       }
0355     }
0356   }
0357 
0358   std::ostream& operator<<(std::ostream& out, const Weights_Map& w);
0359   Weights_Map operator+(Weights_Map lhs, const Weights_Map& rhs);
0360   Weights_Map operator-(Weights_Map lhs, const Weights_Map& rhs);
0361   Weights_Map operator*(Weights_Map lhs, const Weights_Map& rhs);
0362   Weights_Map operator*(Weights_Map lhs, double rhs);
0363   Weights_Map operator/(Weights_Map lhs, const Weights_Map& rhs);
0364   Weights_Map operator/(Weights_Map lhs, double rhs);
0365 
0366 } // namespace ATOOLS
0367 
0368 #endif