Skip to content

Resolve "Refactor event weight propagation"

Closes #27

This MR unifies the various (partly even redundant) methods of propagating event weights within Sherpa, namely in-out double parameters in Event_Phase calls, the weights stored in the signal blob, and the variation weights (also stored in the signal blob).

Instead, now there is only instances of the new Event_Weights class, which always has a nominal weight and if needed variation weights stored within. It can be used for arithmetic operations like adding, multiplying and so on, and there is apply-methods that allow to modify the weights dependent on different variation parameters for reweighting purposes.

Event weights instances are stored in the signal blob, hence every Treat method must eventually modify these to change the final event weights stored in HepMC. There are three of them (in order to allow e.g. to output ME_ONLY variations):

  • "Weights" (general event weights)
  • "Shower_Weights" (everything that happens in CSS/DIRE)
  • "MC@NLO_Shower_Weights (everything that happens in MCATNLO/DIM)

The product of the three entries gives the total event weight(s). Blob_List has convenience methods to obtain those total results.

Code examples for using the Event_Weights class

Creating a new instance, with all weights set to 1.0. Variation weights will also be set up for each variation defined in the run card:

m_weights = Event_Weights {1.0};

The same, but explicitly asking for 0 variation weights, i.e. there will only be a single nominal weight:

m_weights = Event_Weights {0, 1.0};

Multiply the nominal and all variation weights by a factor of two, then print the nominal weight:

m_weights *= 2.0;
msg_Out << m_weights.Nominal() << "\n";

Iterate over all weights (nominal and variations), and add a scale-dependent term to each one. Note that the nominal weight has varindex == 0 and no variation parameters, i.e. varparams == nullptr.

m_weights.ApplyAll([this](double varweight,
                          size_t varindex,
                          Variation_Parameters* varparams) -> double {
  double fac(varparams ? varparams->m_muR2fac : 1.0);
  return varweight + CalcScaleDependentTerm(fac);
});

The same, but only iterating over variation weights. Hence, varindex == 0 now refers to the first variation and varparams is now a reference (since it is now guaranteed to be non-null):

m_weights.Apply([this](double varweight,
                       size_t varindex,
                       Variation_Parameters& varparams) -> double {
  return varweight + CalcScaleDependentTerm(varparams.m_muR2fac);
});

Each NLO subevent has its own set of event weights (or "results"). Here, we add them all together and store them in the signal blob database:

Event_Weights weights {0.0};
for (const auto* sub : m_nlos) {
  weights += sub->m_results;
}
signalblob->AddData("Weights",new Blob_Data<Event_Weights>(weights));

The Differential of a process has now a parameter that determines whether only one nominal weight, or a nominal weight and all variation weights, are calculated:

ATOOLS::Event_Weights Differential(const ATOOLS::Cluster_Amplitude& ampl,
                                   ATOOLS::Weight_Type type=ATOOLS::Weight_Type::nominal,
                                   int mode=0);

Note that nominal is the default. To get all weights, pass ATOOLS::Weight_Type::all instead.

Other useful API examples:

if (m_weights.ContainsVariations()) { ... }  // only do something if the instance has var weights
weight = m_weights[i];  // retrieve the ith weight, where 0 denotes the nominal, and 1 the first variation
weight = m_weights.Variation(i);  // retrieve the ith variation, where 0 denotes the first variation
m_weights *= weights;  // multiply with weights from another instance

Multiplication works if both weights instances have the same number of variation entries, or if one of them has only one entry (then, all entries of the other one are multiplied by this double).

Closure/timing tests

I have tested against the previous commit on master (726e2034) with respect to outputting exactly the same event weights (nominal, varied and "ME_ONLY"-varied) for a Z+jets set-up at LO, NLO, LOPS, NLOPS, MEPS (0,1j), MENLOPS (0j @ NLO, 1j @ LO) and MEPS@NLO (0,1j @ NLO):

Some patches are needed to get full closure (for various reasons):

For none of those tests did I see any significant difference in CPU time usage between the two commits.

The original commit history has been archived on my own fork on the branch "27-refactor-event-weight-propagation+attempt-2+commit-history"

Edited by Enrico Bothmann

Merge request reports