ATLAS Offline Software
Loading...
Searching...
No Matches
Rivet_i.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Implementation file for Athena-Rivet interface
6
7#include "Rivet_i.h"
8#include "LogLevels.h"
9
10#include "AtlasHepMC/GenEvent.h"
12
16
17#include "GaudiKernel/IAppMgrUI.h"
18#include "GaudiKernel/Bootstrap.h"
19#include "GaudiKernel/ITHistSvc.h"
20
21#include "Rivet/Rivet.hh"
22#include "Rivet/Analysis.hh"
23#include "Rivet/Config/RivetConfig.hh"
24#include "Rivet/Tools/RivetYODA.hh"
25
26
27#include <cstdlib>
28#include <cstdio>
29#include <memory>
30#include <regex>
31
32
34
35Rivet_i::Rivet_i(const std::string& name, ISvcLocator* pSvcLocator) :
36 AthAlgorithm(name, pSvcLocator),
37 m_needsConversion(false),
39 m_init(false)
40{
41 // Options
42 declareProperty("McEventKey", m_genEventKey="GEN_EVENT");
44 declareProperty("CrossSection", m_crossSection=0.0);
45 declareProperty("CrossSectionUncertainty", m_crossSection_uncert=0.0);
46 declareProperty("Stream", m_stream="/Rivet");
47 declareProperty("RunName", m_runname="");
48 declareProperty("HistoFile", m_file="Rivet.yoda.gz");
49 declareProperty("HistoPreload", m_preload="");
50 declareProperty("AnalysisPath", m_anapath="");
51 declareProperty("IgnoreBeamCheck", m_ignorebeams=false);
52 declareProperty("DoRootHistos", m_doRootHistos=false);
53 declareProperty("SkipWeights", m_skipweights=false);
54 declareProperty("MatchWeights", m_matchWeights="");
55 declareProperty("UnmatchWeights", m_unmatchWeights="");
56 declareProperty("NominalWeightName", m_nominalWeightName="");
57 declareProperty("WeightCap", m_weightcap=-1.0);
58 declareProperty("AddMissingBeamParticles",m_patchBeams=false);
59}
60
61std::string getenv_str(const std::string& key) {
62 char const* val = getenv(key.c_str());
63 return val == NULL ? std::string() : std::string(val);
64}
65
66
67StatusCode Rivet_i::initialize ATLAS_NOT_THREAD_SAFE () {
68 // ^ use of setenv
69 ATH_MSG_INFO("Using Rivet version " << Rivet::version());
70
71 ATH_CHECK(m_evtInfoKey.initialize());
72
73 // Get tool for xAOD::Truth to HepMC::GenEvent conversion
74 ATH_CHECK(m_xAODtoHepMCTool.retrieve());
75
76
77 // Set RIVET_ANALYSIS_PATH based on alg setup
78
79 // First set (overwrite, if necessary) the RIVET_ANALYSIS_PATH variable
80 std::string env_rap(getenv_str("RIVET_ANALYSIS_PATH"));
81 if (!m_anapath.empty()) {
82 ATH_MSG_INFO("Setting Rivet plugin analyses loader env path: " << m_anapath);
83 if (!env_rap.empty()) ATH_MSG_INFO("Overwriting environment's RIVET_ANALYSIS_PATH = " << env_rap << "!");
84 setenv("RIVET_ANALYSIS_PATH", m_anapath.c_str(), 1);
85 }
86
87 // Get the final form of RIVET_ANALYSIS_PATH and talk about it
88 env_rap = getenv_str("RIVET_ANALYSIS_PATH");
89 if (!env_rap.empty()) ATH_MSG_DEBUG("Loading Rivet plugin analyses from env path: " << env_rap);
90
91 // Set up analysis handler
92 #if RIVET_VERSION_CODE >= 40100
93 m_analysisHandler = new Rivet::AnalysisHandler();
94 #else
95 m_analysisHandler = new Rivet::AnalysisHandler(m_runname);
96 #endif
97 assert(m_analysisHandler);
98
99 #if RIVET_VERSION_CODE >= 40000
100 m_analysisHandler->setCheckBeams(!m_ignorebeams); //< Whether to do beam ID/energy consistency checks
101 m_analysisHandler->matchWeightNames(m_matchWeights); //< Only run on a subset of the multi-weights
102 m_analysisHandler->unmatchWeightNames(m_unmatchWeights); //< Veto a subset of the multi-weights
103 #else
104 m_analysisHandler->setIgnoreBeams(m_ignorebeams); //< Whether to do beam ID/energy consistency checks
105 m_analysisHandler->selectMultiWeights(m_matchWeights); //< Only run on a subset of the multi-weights
106 m_analysisHandler->deselectMultiWeights(m_unmatchWeights); //< Veto a subset of the multi-weights
107 #endif
108 m_analysisHandler->skipMultiWeights(m_skipweights); //< Only run on the nominal weight
109 m_analysisHandler->setNominalWeightName(m_nominalWeightName);
110 if (m_weightcap>0) m_analysisHandler->setWeightCap(m_weightcap);
111
112 // Set Rivet native log level to match Athena
113 Rivet::Log::setLevel("Rivet", rivetLevel(msg().level()));
114
115 // Get all available analysis names
116 if (msgLvl(MSG::VERBOSE)) {
117 std::vector<std::string> analysisNames = Rivet::AnalysisLoader::analysisNames();
118 ATH_MSG_VERBOSE("List of available Rivet analyses:");
119 for (const std::string& a : analysisNames) ATH_MSG_VERBOSE(" " + a);
120 }
121
122 // Add analyses
123 for (const std::string& a : m_analysisNames) {
124 ATH_MSG_INFO("Loading Rivet analysis " << a);
125 m_analysisHandler->addAnalysis(a);
126 Rivet::Log::setLevel("Rivet.Analysis."+a, rivetLevel(msg().level()));
127 }
128
129 // Initialise Rivet
130 // m_analysisHandler->init();
131
132 //load a pre-existing yoda file to initialize histograms
133 if (m_preload!= "") {
134 m_analysisHandler->readData(m_preload);
135 }
136
137 return StatusCode::SUCCESS;
138}
139
140
141StatusCode Rivet_i::execute(const EventContext& ctx) {
142 ATH_MSG_DEBUG("Rivet_i execute");
143
144
146 ATH_MSG_DEBUG("Rivet_i needs xAOD::Truth to HepMC::GenEvent conversion? " << m_needsConversion);
147
148 std::unique_ptr<HepMC::GenEvent> checkedEvent;
149 if (m_needsConversion) {
150 const xAOD::TruthEventContainer* truthCollection = nullptr;
151 if (evtStore()->retrieve(truthCollection, "TruthEvents").isFailure()) {
152 ATH_MSG_ERROR("Could not retrieve TruthEvents collection, aborting.");
153 return StatusCode::FAILURE;
154 }
155
157 ATH_MSG_DEBUG("Attempt xAOD::Truth to HepMC::GenEvent conversion.");
158 std::vector<HepMC::GenEvent>&& hepmc_evts = m_xAODtoHepMCTool->getHepMCEvents(truthCollection, eventInfo.cptr());
159
160 if (hepmc_evts.empty()) {
161 ATH_MSG_ERROR("Conversion didn't yield HepMC::GenEvent, aborting.");
162 return StatusCode::FAILURE;
163 }
164 checkedEvent = checkEvent(std::move(hepmc_evts[0]), ctx);
165 }
166 else {
167 // Get the event collection
169 const McEventCollection* eventCollection = nullptr;
170 StatusCode sc = evtStore()->retrieve(eventCollection, m_genEventKey);
171 if (sc.isFailure() || eventCollection == 0) {
172 ATH_MSG_ERROR("Unable to retrieve event collection from StoreGate with key " << m_genEventKey);
173 return StatusCode::FAILURE;
174 } else {
175 ATH_MSG_DEBUG("Retrieved event collection from StoreGate with key " << m_genEventKey);
176 }
177
178 // Get the first event in the event collection
181 const HepMC::GenEvent* event = eventCollection->front();
182 if (event == nullptr) {
183 ATH_MSG_ERROR("Rivet_i received a null HepMC event");
184 return StatusCode::FAILURE;
185 }
186
187 // Modify the event units etc. if necessary
188 checkedEvent = checkEvent(*event, ctx);
189 }
190
191 if(!checkedEvent) {
192 ATH_MSG_ERROR("Check on HepMC event failed!");
193 return StatusCode::FAILURE;
194 }
195
196 // Initialize Rivet (on the first event only)
197 if (!m_init) {
198 m_analysisHandler->init(*checkedEvent);
199 m_init = true;
200 }
201
202 // Analyse the event
203 m_analysisHandler->analyze(*checkedEvent);
204
205 return StatusCode::SUCCESS;
206}
207
208
209StatusCode Rivet_i::finalize() {
210 ATH_MSG_INFO("Rivet_i finalizing");
211
212 // Setting cross-section in Rivet
213 // If no user-specified cross-section available,
214 // take whatever is in the GenEvent
216
217 // Call Rivet finalize
218 m_analysisHandler->finalize();
219
220
221
222 // Write out YODA file (add .yoda suffix if missing)
223 if (m_file.find(".yoda") == std::string::npos) m_file += ".yoda.gz";
224 auto pos = m_file.find(".gz.");
225 if (pos == std::string::npos) {
226 m_analysisHandler->writeData(m_file);
227 }
228 else {//filename is e.g. something.yoda.gz.1
229 //write to output file name without the ".1"
230 m_analysisHandler->writeData(m_file.substr(0, pos)+".gz");
231 // then rename it as the requested output filename
232 if (std::rename((m_file.substr(0, pos)+".gz").c_str(), m_file.c_str()) !=0) {
233 std::string error_msg = "Impossible to rename ";
234 error_msg += m_file.substr(0, pos)+".gz";
235 error_msg += " as ";
236 error_msg += m_file;
237 ATH_MSG_ERROR(error_msg.c_str());
238 return StatusCode::FAILURE;
239 }
240 }
241
242 return StatusCode::SUCCESS;
243}
244
245
249 return a->momentum().e() > b->momentum().e();
250}
251
252inline std::vector<std::string> split(const std::string& input, const std::string& regex) {
253 // passing -1 as the submatch index parameter performs splitting
254 std::regex re(regex);
255 std::sregex_token_iterator
256 first{input.begin(), input.end(), re, -1},
257 last;
258 return {first, last};
259}
260
261std::unique_ptr<HepMC::GenEvent> Rivet_i::checkEvent(const HepMC::GenEvent& event, const EventContext& ctx) {
262 auto modEvent = std::make_unique<HepMC::GenEvent>(event);
263
264 if (!m_needsConversion) {
265 // overwrite the HEPMC dummy event number with the proper ATLAS event number
267 modEvent->set_event_number(static_cast<int>(evtInfo->eventNumber()));
268 }
269
270 // weight-name cleaning
271 std::shared_ptr<HepMC3::GenRunInfo> modRunInfo;
272 if (event.run_info()) {
273 modRunInfo = std::make_shared<HepMC3::GenRunInfo>(*(event.run_info().get()));
274 if (event.run_info()->weight_names().empty() && event.weights().size() == 1) {
275 modRunInfo->set_weight_names({"Default"});
276 }
277 }
278 else {
279 ATH_MSG_DEBUG("No run info, event weights size is " << event.weights().size() );
280 modRunInfo = std::make_shared<HepMC3::GenRunInfo>();
281 std::vector<std::string> w_names;
282 for (size_t i = 0; i < event.weights().size(); i++) { w_names.push_back(std::string("badweight") + std::to_string(i)); }
283 modRunInfo->set_weight_names(w_names);
284 }
285 modEvent->set_run_info(std::move(modRunInfo));
286 std::vector<std::string> w_names = modEvent->weight_names();
287 if (w_names.size()) {
288 std::vector<std::pair<std::string,std::string> > w_subs = {
289 {" nominal ",""},
290 {" set = ","_"},
291 {" = ","_"},
292 {"=",""},
293 {",",""},
294 {".",""},
295 {":",""},
296 {" ","_"},
297 {"#","num"},
298 {"\n","_"},
299 {"/","over"}
300 };
301 for (std::string& wname : w_names) {
302 for (const auto& sub : w_subs) {
303 size_t start_pos = wname.find(sub.first);
304 while (start_pos != std::string::npos) {
305 wname.replace(start_pos, sub.first.length(), sub.second);
306 start_pos = wname.find(sub.first);
307 }
308 }
309 }
310 modEvent->run_info()->set_weight_names(w_names);
311 }
312
313 modEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM);
314 if (modEvent->particles().size() == 1) modEvent->set_beam_particles(modEvent->particles().front(), modEvent->particles().front());
315 if (m_patchBeams) {
316 // workaround in case beam particles were missing in xAOD::Truth
317 // first work out centre-of-mass energy
318 double etotal = 0;
319 for (const auto& p : modEvent->particles()) {
320 if (!MC::isStable(p)) continue;
321 etotal += p->momentum().e();
322 }
323 const double ebeam = 0.5*etotal;
324 // create dummy beam particles
325 HepMC::GenParticlePtr b1 = std::make_shared<HepMC::GenParticle>(HepMC::FourVector(0,0,ebeam,ebeam),2212,4);
326 HepMC::GenParticlePtr b2 = std::make_shared<HepMC::GenParticle>(HepMC::FourVector(0,0,-1*ebeam,ebeam),2212,4);
327 // remove particles incorrectly labelled as beam particles
328 std::vector<HepMC::GenParticlePtr> notBeams;
329 for (const HepMC::GenParticlePtr& p : modEvent->beams()) {
330 if (!MC::isBeam(p)) notBeams.push_back(p);
331 }
332 //AV: the loop is over shared pointers! Should be const auto&
333 for (const auto& bp : notBeams) bp->production_vertex()->remove_particle_out(bp);
334 // add dummy beam particles
335 modEvent->set_beam_particles(std::move(b1), std::move(b2));
336 }
337 if (modEvent->beams().front()->momentum().e() > 50000.0) {
338 MeV2GeV(*modEvent);
339 }
340
341 return modEvent;
342}
343
345 for (auto& p: evt.particles()) {
346 p->set_momentum(p->momentum()*0.001);
347 p->set_generated_mass(p->generated_mass()*0.001);
348 }
349}
const std::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Helpers for checking error return status codes and reporting errors.
ATLAS-specific HepMC functions.
static Double_t a
static Double_t sc
Rivet::Log::Level rivetLevel(MSG::Level gaudiLevel)
Definition LogLevels.h:21
bool cmpGenParticleByEDesc(HepMC::ConstGenParticlePtr a, HepMC::ConstGenParticlePtr b)
Helper function to sort GenParticles by descending energy.
Definition Rivet_i.cxx:248
std::string getenv_str(const std::string &key)
Definition Rivet_i.cxx:61
StatusCode Rivet_i::initialize ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
Definition Rivet_i.cxx:67
std::vector< std::string > split(const std::string &input, const std::string &regex)
Definition Rivet_i.cxx:252
size_t size() const
Number of registered mappings.
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
const T * front() const
Access the first element in the collection as an rvalue.
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
bool m_skipweights
Skip variation weights and only run nominal.
Definition Rivet_i.h:122
double m_weightcap
Weight cap to set allowed maximum for weights.
Definition Rivet_i.h:134
std::vector< std::string > m_analysisNames
A list of names of the analyses to run (set from the job properties).
Definition Rivet_i.h:110
bool m_ignorebeams
Whether to avoid the beam consistency checks.
Definition Rivet_i.h:80
double m_crossSection
The cross section for this run of events, set from the job properties.
Definition Rivet_i.h:113
bool m_patchBeams
Flag to insert beam protons when they are unavailable in the event.
Definition Rivet_i.h:88
virtual StatusCode finalize() override
Finalise each analysis and commit the plots to the YODA tree and the THistSvc ROOT tree.
Definition Rivet_i.cxx:209
virtual StatusCode execute(const EventContext &ctx) override
Run the Rivet analyses on one event, which is retrieved from StoreGate.
Definition Rivet_i.cxx:141
std::string m_anapath
The analysis plugin search path.
Definition Rivet_i.h:74
bool m_init
Flag to determine whether Rivet init has already happened (in execute()).
Definition Rivet_i.h:119
ToolHandle< IxAODtoHepMCTool > m_xAODtoHepMCTool
A tool to convert xAOD::Truth to HepMC::GenEvent.
Definition Rivet_i.h:91
std::string m_file
The base file name to write results to.
Definition Rivet_i.h:66
std::string m_unmatchWeights
String of weight names (or regex) to veto multiweights.
Definition Rivet_i.h:128
std::string m_matchWeights
String of weight names (or regex) to select multiweights.
Definition Rivet_i.h:125
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfoKey
Definition Rivet_i.h:136
double m_crossSection_uncert
The uncertainity of the cross section for this run of events, set from the job properties.
Definition Rivet_i.h:116
bool m_needsConversion
Do we need to convert xAOD::Truth back to HepMC::GenEvemt?
Definition Rivet_i.h:85
Rivet::AnalysisHandler * m_analysisHandler
A Rivet analysis handler.
Definition Rivet_i.h:107
bool m_doRootHistos
Will we convert Rivet's internal histo format into a ROOT histo for streaming with THistSvc?
Definition Rivet_i.h:98
std::string m_stream
A pointer to the THistSvc.
Definition Rivet_i.h:63
std::string m_preload
Definition Rivet_i.h:69
Rivet_i(const std::string &name, ISvcLocator *pSvcLocator)
Standard algorithm constructor.
Definition Rivet_i.cxx:35
std::unique_ptr< HepMC::GenEvent > checkEvent(const HepMC::GenEvent &event, const EventContext &ctx)
Definition Rivet_i.cxx:261
std::string m_genEventKey
The GenEvent StoreGate key (default "GEN_EVENT").
Definition Rivet_i.h:104
std::string m_nominalWeightName
String to specify non-standard nominal weight.
Definition Rivet_i.h:131
void MeV2GeV(HepMC::GenEvent &event)
Definition Rivet_i.cxx:344
std::string m_runname
The name of the run (prepended to plot paths).
Definition Rivet_i.h:101
const_pointer_type cptr()
Dereference the pointer.
HepMC3::FourVector FourVector
HepMC3::GenParticlePtr GenParticlePtr
Definition GenParticle.h:19
HepMC3::ConstGenParticlePtr ConstGenParticlePtr
Definition GenParticle.h:20
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
bool isBeam(const T &p)
Identify if the particle is beam particle.
TruthEventContainer_v1 TruthEventContainer
Declare the latest version of the truth event container.
MsgStream & msg
Definition testRead.cxx:32