Project
Loading...
Searching...
No Matches
GeneratorHepMC.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13
18#include "SimConfig/SimConfig.h"
19#include "HepMC3/ReaderFactory.h"
20#include "HepMC3/GenEvent.h"
21#include "HepMC3/GenParticle.h"
22#include "HepMC3/GenVertex.h"
23#include "HepMC3/FourVector.h"
24#include "HepMC3/Version.h"
25#include "TParticle.h"
26
27#include <fairlogger/Logger.h>
28#include "FairPrimaryGenerator.h"
29#include <cmath>
30
31namespace o2
32{
33namespace eventgen
34{
35
36/*****************************************************************/
37/*****************************************************************/
38
40 : GeneratorHepMC("ALICEo2", "ALICEo2 HepMC Generator")
41{
42}
43
44/*****************************************************************/
45
46GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title)
47 : Generator(name, title)
48{
51 mEvent = new HepMC3::GenEvent();
52 mInterface = reinterpret_cast<void*>(mEvent);
53 mInterfaceName = "hepmc";
54}
55
56/*****************************************************************/
57
59{
61 LOG(info) << "Destructing GeneratorHepMC";
62 if (mReader) {
63 mReader->close();
64 }
65 if (mEvent) {
66 delete mEvent;
67 }
68 if (not mCmd.empty()) {
69 // Must be executed before removing the temporary file
70 // otherwise the current child process might still be writing on it
71 // causing unwanted stdout messages which could slow down the system
73 }
74 removeTemp();
75}
76
77/*****************************************************************/
80 const conf::SimConfig& config)
81{
82 if (not param.fileName.empty()) {
83 LOG(warn) << "The use of the key \"HepMC.fileName\" is "
84 << "deprecated, use \"GeneratorFileOrCmd.fileNames\" instead";
85 }
86
87 GeneratorFileOrCmd::setup(param0, config);
88 if (not param.fileName.empty()) {
89 setFileNames(param.fileName);
90 }
91
92 mVersion = param.version;
93 mPrune = param.prune;
94 setEventsToSkip(param.eventsToSkip);
95
96 // we are skipping ahead in the HepMC stream now
97 for (int i = 0; i < mEventsToSkip; ++i) {
99 }
100
101 if (param.version != 0 and mCmd.empty()) {
102 LOG(warn) << "The key \"HepMC.version\" is no longer needed when "
103 << "reading from files. The format version of the input files "
104 << "are automatically deduced. However, it is mandatory when reading "
105 << "from a pipe containing HepMC2 data.";
106 }
107}
108
109/*****************************************************************/
111 const HepMCGenConfig& param,
112 const conf::SimConfig& config)
113{
114 if (not param.fileName.empty()) {
115 LOG(warn) << "The use of the key \"HepMC.fileName\" is "
116 << "deprecated, use \"GeneratorFileOrCmd.fileNames\" instead";
117 }
118
119 GeneratorFileOrCmd::setup(param0, config);
120 if (not param.fileName.empty()) {
121 setFileNames(param.fileName);
122 }
123
124 mVersion = param.version;
125 mPrune = param.prune;
126 setEventsToSkip(param.eventsToSkip);
127
128 // we are skipping ahead in the HepMC stream now
129 for (int i = 0; i < mEventsToSkip; ++i) {
131 }
132
133 if (param.version != 0 and mCmd.empty()) {
134 LOG(warn) << "The key \"HepMC.version\" is no longer needed when "
135 << "reading from files. The format version of the input files "
136 << "are automatically deduced. However, it is mandatory when reading "
137 << "from a pipe containing HepMC2 data.";
138 }
139}
140
141/*****************************************************************/
143{
144 LOG(debug) << "Generating an event";
146 int tries = 0;
147 constexpr int max_tries = 3;
148 do {
149 LOG(debug) << " try # " << tries;
150 if (not mReader and not makeReader()) {
151 return false;
152 }
153
155 mEvent->clear();
156 mReader->read_event(*mEvent);
157 if (not mReader->failed()) {
159 mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM);
160 LOG(debug) << "Read one event " << mEvent->event_number();
161 return true;
162 } else {
163 LOG(error) << "Event reading from HepMC failed ...";
164 }
165 tries++;
166 } while (tries < max_tries);
167
168 LOG(error) << "HepMC event gen failed (Does the file/stream have enough events)?";
169
171 return false;
172}
173
174/*****************************************************************/
176{
177 HepMC3::GenEvent& event = *mEvent;
178
179 auto particles = event.particles();
180 auto vertices = event.vertices();
181 std::list<HepMC3::GenParticlePtr> toRemove;
182
183 LOG(debug) << "HepMC events has " << particles.size()
184 << " particles and " << vertices.size()
185 << " vertices" << std::endl;
186
187 size_t nSelect = 0;
188 for (size_t i = 0; i < particles.size(); ++i) {
189 auto particle = particles[i];
190 if (select(particle)) {
191 nSelect++;
192 continue;
193 }
194
195 // Remove particle from the event
196 toRemove.push_back(particle);
197 LOG(debug) << " Remove " << std::setw(3) << particle->id();
198
199 auto endVtx = particle->end_vertex();
200 auto prdVtx = particle->production_vertex();
201 if (endVtx) {
202 // Disconnect this particle from its out going vertex
203 endVtx->remove_particle_in(particle);
204 LOG(debug) << " end " << std::setw(3) << endVtx->id();
205
206 if (prdVtx and prdVtx->id() != endVtx->id()) {
207 auto outbound = endVtx->particles_out();
208 auto inbound = endVtx->particles_in();
209 LOG(debug) << " prd " << std::setw(3) << prdVtx->id() << " "
210 << std::setw(3) << outbound.size() << " out "
211 << " "
212 << std::setw(3) << inbound.size() << " in ";
213
214 // Other out-bound particles of the end vertex are attached as
215 // out-going to the production vertex of this particle.
216 for (auto outgoing : outbound) {
217 // This should also detach the particle from its old
218 // end-vertex.
219 if (outgoing) {
220 auto ee = outgoing->end_vertex();
221 if (not ee or ee->id() != prdVtx->id()) {
222 prdVtx->add_particle_out(outgoing);
223 }
224 LOG(debug) << " " << std::setw(3) << outgoing->id();
225 }
226 }
227
228 // Other incoming particles to the end vertex of this
229 // particles are attached incoming particles to the production
230 // vertex of this particle.
231 for (auto incoming : inbound) {
232 if (incoming) {
233 auto pp = incoming->production_vertex();
234 if (not pp or pp->id() != prdVtx->id()) {
235 prdVtx->add_particle_in(incoming);
236 }
237
238 LOG(debug) << " " << std::setw(3) << incoming->id();
239 }
240 }
241 }
242 }
243 if (prdVtx) {
244 prdVtx->remove_particle_out(particle);
245 }
246 }
247
248 LOG(debug) << "Selected " << nSelect << " particles\n"
249 << "Removing " << toRemove.size() << " particles";
250 size_t oldSize = particles.size();
251 for (auto particle : toRemove) {
252 event.remove_particle(particle);
253 }
254
255 std::list<HepMC3::GenVertexPtr> remVtx;
256 for (auto vtx : event.vertices()) {
257 if (not vtx or
258 (vtx->particles_out().empty() and
259 vtx->particles_in().empty())) {
260 remVtx.push_back(vtx);
261 }
262 }
263 LOG(debug) << "Removing " << remVtx.size() << " vertexes";
264 for (auto vtx : remVtx) {
265 event.remove_vertex(vtx);
266 }
267
268 LOG(debug) << "HepMC events was pruned from " << oldSize
269 << " particles to " << event.particles().size()
270 << " particles and " << event.vertices().size()
271 << " vertices";
272}
273
274/*****************************************************************/
275
277{
279 if (mPrune) {
280 auto select = [](HepMC3::ConstGenParticlePtr particle) {
281 switch (particle->status()) {
282 case 1: // Final st
283 case 2: // Decayed
284 case 4: // Beam
285 return true;
286 }
287 // To also keep diffractive particles
288 // if (particle->pid() == 9902210) return true;
289 return false;
290 };
292 }
293
295 mParticles.clear();
296 auto particles = mEvent->particles();
297 for (int i = 0; i < particles.size(); ++i) {
298
300 auto particle = particles.at(i);
301 auto momentum = particle->momentum();
302 auto vertex = particle->production_vertex()->position();
303 auto parents = particle->parents();
304 auto children = particle->children();
305
307 auto m1 = parents.empty() ? -1 : parents.front()->id() - 1;
308 auto m2 = parents.empty() ? -1 : parents.back()->id() - 1;
309
311 auto d1 = children.empty() ? -1 : children.front()->id() - 1;
312 auto d2 = children.empty() ? -1 : children.back()->id() - 1;
313
315 mParticles.push_back(TParticle(particle->pid(), // Particle type
316 particle->status(), // Status code
317 m1, // First mother
318 m2, // Second mother
319 d1, // First daughter
320 d2, // Last daughter
321 momentum.x(), // X-momentum
322 momentum.y(), // Y-momentum
323 momentum.z(), // Z-momentum
324 momentum.t(), // Energy
325 vertex.x(), // Production X
326 vertex.y(), // Production Y
327 vertex.z(), // Production Z
328 vertex.t())); // Production time
330 mParticles.back(), // Add to back
331 particle->status() == 1); // only final state are to be propagated
332
333 }
336 return kTRUE;
337}
338
339namespace
340{
341template <typename AttributeType, typename TargetType>
342bool putAttributeInfoImpl(o2::dataformats::MCEventHeader* eventHeader,
343 const std::string& name,
344 const std::shared_ptr<HepMC3::Attribute>& a)
345{
346 if (auto* p = dynamic_cast<AttributeType*>(a.get())) {
347 eventHeader->putInfo<TargetType>(name, p->value());
348 return true;
349 }
350 return false;
351}
352
353void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader,
354 const std::string& name,
355 const std::shared_ptr<HepMC3::Attribute>& a)
356{
357 using IntAttribute = HepMC3::IntAttribute;
358 using LongAttribute = HepMC3::LongAttribute;
359 using FloatAttribute = HepMC3::FloatAttribute;
360 using DoubleAttribute = HepMC3::DoubleAttribute;
361 using StringAttribute = HepMC3::StringAttribute;
362 using CharAttribute = HepMC3::CharAttribute;
363 using LongLongAttribute = HepMC3::LongLongAttribute;
364 using LongDoubleAttribute = HepMC3::LongDoubleAttribute;
365 using UIntAttribute = HepMC3::UIntAttribute;
366 using ULongAttribute = HepMC3::ULongAttribute;
367 using ULongLongAttribute = HepMC3::ULongLongAttribute;
368 using BoolAttribute = HepMC3::BoolAttribute;
369
370 if (putAttributeInfoImpl<IntAttribute, int>(eventHeader, name, a)) {
371 return;
372 }
373 if (putAttributeInfoImpl<LongAttribute, int>(eventHeader, name, a)) {
374 return;
375 }
376 if (putAttributeInfoImpl<FloatAttribute, float>(eventHeader, name, a)) {
377 return;
378 }
379 if (putAttributeInfoImpl<DoubleAttribute, float>(eventHeader, name, a)) {
380 return;
381 }
382 if (putAttributeInfoImpl<StringAttribute, std::string>(eventHeader, name, a)) {
383 return;
384 }
385 if (putAttributeInfoImpl<CharAttribute, char>(eventHeader, name, a)) {
386 return;
387 }
388 if (putAttributeInfoImpl<LongLongAttribute, int>(eventHeader, name, a)) {
389 return;
390 }
391 if (putAttributeInfoImpl<LongDoubleAttribute, float>(eventHeader, name, a)) {
392 return;
393 }
394 if (putAttributeInfoImpl<UIntAttribute, int>(eventHeader, name, a)) {
395 return;
396 }
397 if (putAttributeInfoImpl<ULongAttribute, int>(eventHeader, name, a)) {
398 return;
399 }
400 if (putAttributeInfoImpl<ULongLongAttribute, int>(eventHeader, name, a)) {
401 return;
402 }
403 if (putAttributeInfoImpl<BoolAttribute, bool>(eventHeader, name, a)) {
404 return;
405 }
406}
407} // namespace
408
409/*****************************************************************/
410
412{
415
416 eventHeader->putInfo<std::string>(Key::generator, "hepmc");
417 eventHeader->putInfo<int>(Key::generatorVersion, HEPMC3_VERSION_CODE);
418
419 auto xSection = mEvent->cross_section();
420 auto pdfInfo = mEvent->pdf_info();
421 auto hiInfo = mEvent->heavy_ion();
422
423 // Set default cross-section
424 if (xSection) {
425 eventHeader->putInfo<float>(Key::xSection, xSection->xsec());
426 eventHeader->putInfo<float>(Key::xSectionError, xSection->xsec_err());
427 eventHeader->putInfo<int>(Key::acceptedEvents,
428 xSection->get_accepted_events());
429 eventHeader->putInfo<int>(Key::attemptedEvents,
430 xSection->get_attempted_events());
431 }
432
433 // Set weights and cross sections
434 size_t iw = 0;
435 for (auto w : mEvent->weights()) {
436 std::string post = (iw > 0 ? "_" + std::to_string(iw) : "");
437 eventHeader->putInfo<float>(Key::weight + post, w);
438 if (xSection) {
439 eventHeader->putInfo<float>(Key::xSection, xSection->xsec(iw));
440 eventHeader->putInfo<float>(Key::xSectionError, xSection->xsec_err(iw));
441 }
442 iw++;
443 }
444
445 // Set the PDF information
446 if (pdfInfo) {
447 eventHeader->putInfo<int>(Key::pdfParton1Id, pdfInfo->parton_id[0]);
448 eventHeader->putInfo<int>(Key::pdfParton2Id, pdfInfo->parton_id[1]);
449 eventHeader->putInfo<float>(Key::pdfX1, pdfInfo->x[0]);
450 eventHeader->putInfo<float>(Key::pdfX2, pdfInfo->x[1]);
451 eventHeader->putInfo<float>(Key::pdfScale, pdfInfo->scale);
452 eventHeader->putInfo<float>(Key::pdfXF1, pdfInfo->xf[0]);
453 eventHeader->putInfo<float>(Key::pdfXF2, pdfInfo->xf[1]);
454 eventHeader->putInfo<int>(Key::pdfCode1, pdfInfo->pdf_id[0]);
455 eventHeader->putInfo<int>(Key::pdfCode2, pdfInfo->pdf_id[1]);
456 }
457
458 // Set heavy-ion information
459 if (hiInfo) {
460 eventHeader->putInfo<int>(Key::impactParameter,
461 hiInfo->impact_parameter);
462 eventHeader->putInfo<int>(Key::nPart,
463 hiInfo->Npart_proj + hiInfo->Npart_targ);
464 eventHeader->putInfo<int>(Key::nPartProjectile, hiInfo->Npart_proj);
465 eventHeader->putInfo<int>(Key::nPartTarget, hiInfo->Npart_targ);
466 eventHeader->putInfo<int>(Key::nColl, hiInfo->Ncoll);
467 eventHeader->putInfo<int>(Key::nCollHard, hiInfo->Ncoll_hard);
468 eventHeader->putInfo<int>(Key::nCollNNWounded,
469 hiInfo->N_Nwounded_collisions);
470 eventHeader->putInfo<int>(Key::nCollNWoundedN,
471 hiInfo->Nwounded_N_collisions);
472 eventHeader->putInfo<int>(Key::nCollNWoundedNwounded,
473 hiInfo->Nwounded_Nwounded_collisions);
474 eventHeader->putInfo<int>(Key::planeAngle,
475 hiInfo->event_plane_angle);
476 eventHeader->putInfo<int>(Key::sigmaInelNN,
477 hiInfo->sigma_inel_NN);
478 eventHeader->putInfo<int>(Key::centrality, hiInfo->centrality);
479 eventHeader->putInfo<int>(Key::nSpecProjectileProton, hiInfo->Nspec_proj_p);
480 eventHeader->putInfo<int>(Key::nSpecProjectileNeutron, hiInfo->Nspec_proj_n);
481 eventHeader->putInfo<int>(Key::nSpecTargetProton, hiInfo->Nspec_targ_p);
482 eventHeader->putInfo<int>(Key::nSpecTargetNeutron, hiInfo->Nspec_targ_n);
483 }
484
485 for (auto na : mEvent->attributes()) {
486 std::string name = na.first;
487 if (name == "GenPdfInfo" ||
488 name == "GenCrossSection" ||
489 name == "GenHeavyIon") {
490 continue;
491 }
492
493 for (auto ia : na.second) {
494 int no = ia.first;
495 auto at = ia.second;
496 std::string post = (no == 0 ? "" : std::to_string(no));
497
498 putAttributeInfo(eventHeader, name + post, at);
499 }
500 }
501}
502
503/*****************************************************************/
504
506{
507 // Reset the reader smart pointer
508 LOG(debug) << "Reseting the reader";
509 mReader.reset();
510
511 // Check that we have any file names left
512 if (mFileNames.size() < 1) {
513 LOG(debug) << "No more files to read, return false";
514 return false;
515 }
516
517 // If we have file names left, pop the top of the list (LIFO)
518 auto filename = mFileNames.front();
519 mFileNames.pop_front();
520
521 LOG(debug) << "Next file to read: \"" << filename << "\" "
522 << mFileNames.size() << " left";
523
524 if (not mCmd.empty()) {
525 // For FIFO reading, we assume straight ASCII output always.
526 // Unfortunately, the HepMC3::deduce_reader `stat`s the filename
527 // which isn't supported on a FIFO, so we have to use the reader
528 // directly. Here, we allow for version 2 formats if the user
529 // specifies that
530 LOG(info) << "Creating ASCII reader of " << filename;
531 if (mVersion == 2) {
532 mReader = std::make_shared<HepMC3::ReaderAsciiHepMC2>(filename);
533 } else {
534 mReader = std::make_shared<HepMC3::ReaderAscii>(filename);
535 }
536 } else {
537 LOG(info) << "Deduce a reader of " << filename;
538 mReader = HepMC3::deduce_reader(filename);
539 }
540
541 bool ret = bool(mReader) and not mReader->failed();
542 LOG(info) << "Reader is " << mReader.get() << " " << ret;
543 return ret;
544}
545
546/*****************************************************************/
547
549{
554
555 // If a EG command line is given, then we make a fifo on a temporary
556 // file, and directs the EG to write to that fifo. We will then set
557 // up the HepMC3 reader to read from that fifo.
558 //
559 // o2-sim -g hepmc --configKeyValues "HepMC.progCmd=<cmd>" ...
560 //
561 // where <cmd> is the command line to run an event generator. The
562 // event generator should output HepMC event records to standard
563 // output. Nothing else, but the HepMC event record may be output
564 // to standard output. If the EG has other output to standard
565 // output, then a filter can be set-up. For example
566 //
567 // crmc -n 3 -o hepmc3 -c /optsw/inst/etc/crmc.param -f /dev/stdout \
568 // | sed -n 's/^\‍(HepMC::\|[EAUWVP] \‍)/\1/p'
569 //
570 // What's more, the event generator program _must_ accept the
571 // following command line argument
572 //
573 // `-n NEVENTS` to set the number of events to produce.
574 //
575 // Optionally, the command line should also accept
576 //
577 // `-s SEED` to set the random number seed
578 // `-b FM` to set the maximum impact parameter to sample
579 // `-o OUTPUT` to set the output file name
580 //
581 // All of this can conviniently be achieved via a wrapper script
582 // around the actual EG program.
583 if (not mCmd.empty()) {
584 if (mFileNames.empty()) {
585 // Set filename to be a temporary name
586 if (not makeTemp(false)) {
587 return false;
588 }
589 } else {
590 // Use the first filename as output for cmd line
591 if (not makeTemp(true)) {
592 return false;
593 }
594 }
595
596 // Make a fifo
597 if (not makeFifo()) {
598 return false;
599 }
600
601 // Build command line, rediret stdout to our fifo and put
602 std::string cmd = makeCmdLine();
603 LOG(debug) << "EG command line is \"" << cmd << "\"";
604
605 // Execute the command line
606 if (not executeCmdLine(cmd)) {
607 LOG(fatal) << "Failed to spawn \"" << cmd << "\"";
608 return false;
609 }
610 } else {
611 // If no command line was given, ensure that all files are present
612 // on the system. Note, in principle, HepMC3 can read from remote
613 // files
614 //
615 // root:// XRootD served
616 // http[s]:// Web served
617 // gsidcap:// DCap served
618 //
619 // These will all be handled in HepMC3 via ROOT's TFile protocol
620 // and the files are assumed to contain a TTree named
621 // `hepmc3_tree` and that tree has the branches
622 //
623 // `hepmc3_event` with object of type `HepMC3::GenEventData`
624 // `GenRunInfo` with object of type `HepMC3::GenRunInfoData`
625 //
626 // where the last branch is optional.
627 //
628 // However, here we will assume system local files. If _any_ of
629 // the listed files do not exist, then we fail.
630 if (not ensureFiles()) {
631 return false;
632 }
633 }
634
635 // Create reader for current (first) file
636 return true;
637}
638
639/*****************************************************************/
640/*****************************************************************/
641
642} /* namespace eventgen */
643} /* namespace o2 */
o2::monitoring::tags::Key Key
uint64_t vertex
Definition RawEventData.h:9
int32_t i
Utility functions for MC particles.
std::ostringstream debug
void putInfo(std::string const &key, T const &value)
void updateHeader(o2::dataformats::MCEventHeader *eventHeader) override
void setEventsToSkip(uint64_t val)
std::shared_ptr< HepMC3::Reader > mReader
void setup(const GeneratorFileOrCmdParam &param0, const GeneratorHepMCParam &param, const conf::SimConfig &config)
std::string mInterfaceName
Definition Generator.h:120
std::vector< TParticle > mParticles
Definition Generator.h:140
Bool_t Init() override
Definition Generator.cxx:57
static void encodeParticleStatusAndTracking(TParticle &particle, bool wanttracking=true)
Definition MCUtils.cxx:211
GLuint const GLchar * name
Definition glcorearb.h:781
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
std::vector< InputSpec > select(char const *matcher="")
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::string filename()
void setFileNames(const std::string &filenames)
void setup(const GeneratorFileOrCmdParam &param, const conf::SimConfig &config)
std::list< std::string > mFileNames
virtual std::string makeCmdLine() const
virtual bool executeCmdLine(const std::string &cmd)
virtual bool makeTemp(const bool &)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"