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/ReaderAscii.h"
21#include "HepMC3/ReaderAsciiHepMC2.h"
22#include "HepMC3/GenEvent.h"
23#include "HepMC3/GenParticle.h"
24#include "HepMC3/GenVertex.h"
25#include "HepMC3/FourVector.h"
26#include "HepMC3/Version.h"
27#include "TParticle.h"
28#include "TRandom.h"
29
30#include <fairlogger/Logger.h>
32#include <algorithm>
33#include <cmath>
34#include <fstream>
35#include <numeric>
36#include <sstream>
37
38namespace o2
39{
40namespace eventgen
41{
42
43/*****************************************************************/
44/*****************************************************************/
45
47 : GeneratorHepMC("ALICEo2", "ALICEo2 HepMC Generator")
48{
49}
50
51/*****************************************************************/
52
53GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title)
54 : Generator(name, title)
55{
58 mEvent = new HepMC3::GenEvent();
59 mInterface = reinterpret_cast<void*>(mEvent);
60 mInterfaceName = "hepmc";
61}
62
63/*****************************************************************/
64
66{
68 LOG(info) << "Destructing GeneratorHepMC";
69 if (mReader) {
70 mReader->close();
71 }
72 if (mEvent) {
73 delete mEvent;
74 }
75 stop();
76 removeTemp();
77}
78
79/*****************************************************************/
80
82{
83 if (mCmd.empty()) {
84 return;
85 }
86 // Close our end of the pipe first: a generator still blocked writing to it
87 // then sees EPIPE and exits promptly, instead of sitting out the whole grace
88 // period and being killed - which would lose its CPU time (see terminateCmd).
89 if (mReader) {
90 mReader->close();
91 }
92 // Must be executed before removing the temporary file
93 // otherwise the current child process might still be writing on it
94 // causing unwanted stdout messages which could slow down the system
96}
97
98/*****************************************************************/
100 const HepMCGenConfig& param,
101 const conf::SimConfig& config)
102{
103 GeneratorFileOrCmd::setup(param0, config);
105}
106
107/*****************************************************************/
109 const HepMCGenConfig& param,
110 const conf::SimConfig& config)
111{
112 GeneratorFileOrCmd::setup(param0, config);
114}
115
116/*****************************************************************/
117
119{
120 if (not param.fileName.empty()) {
121 LOG(warn) << "The use of the key \"HepMC.fileName\" is "
122 << "deprecated, use \"GeneratorFileOrCmd.fileNames\" instead";
123 setFileNames(param.fileName);
124 }
125
126 mVersion = param.version;
127 mPrune = param.prune;
128 mRandomize = param.randomize;
129 mRoundRobin = param.roundRobin;
130 mReshuffleOnRepeat = param.reshuffleOnRepeat;
131 mRngSeed = param.rngseed;
132 setEventsToSkip(param.eventsToSkip);
133
134 // we are skipping ahead with this method only in sequential mode
135 // check establishEventOrder for the random mode
136 if (not(mRandomize or mRoundRobin)) {
137 for (uint64_t i = 0; i < mEventsToSkip; ++i) {
139 }
140 }
141
142 if (param.version != 0 and mCmd.empty()) {
143 LOG(warn) << "The key \"HepMC.version\" is no longer needed when "
144 << "reading from files. The format version of the input files "
145 << "are automatically deduced. However, it is mandatory when reading "
146 << "from a pipe containing HepMC2 data.";
147 }
148}
149
150/*****************************************************************/
152{
153 // when the events are not simply served in the order they appear in the file,
154 // the entry to read is taken from the order established in Init
155 if (mRandomize or mRoundRobin) {
156 return generateEventOrdered();
157 }
158
159 LOG(debug) << "Generating an event";
161 int tries = 0;
162 constexpr int max_tries = 3;
163 do {
164 LOG(debug) << " try # " << tries;
165 if (not mReader and not makeReader()) {
166 return false;
167 }
168
170 mEvent->clear();
171 mReader->read_event(*mEvent);
172 if (not mReader->failed()) {
174 mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM);
175 LOG(debug) << "Read one event " << mEvent->event_number();
176 return true;
177 } else {
178 LOG(error) << "Event reading from HepMC failed ...";
179 }
180 tries++;
181 } while (tries < max_tries);
182
183 LOG(error) << "HepMC event gen failed (Does the file/stream have enough events)?";
184
186 return false;
187}
188
189/*****************************************************************/
191{
192 HepMC3::GenEvent& event = *mEvent;
193
194 auto particles = event.particles();
195 auto vertices = event.vertices();
196 std::list<HepMC3::GenParticlePtr> toRemove;
197
198 LOG(debug) << "HepMC events has " << particles.size()
199 << " particles and " << vertices.size()
200 << " vertices" << std::endl;
201
202 size_t nSelect = 0;
203 for (size_t i = 0; i < particles.size(); ++i) {
204 auto particle = particles[i];
205 if (select(particle)) {
206 nSelect++;
207 continue;
208 }
209
210 // Remove particle from the event
211 toRemove.push_back(particle);
212 LOG(debug) << " Remove " << std::setw(3) << particle->id();
213
214 auto endVtx = particle->end_vertex();
215 auto prdVtx = particle->production_vertex();
216 if (endVtx) {
217 // Disconnect this particle from its out going vertex
218 endVtx->remove_particle_in(particle);
219 LOG(debug) << " end " << std::setw(3) << endVtx->id();
220
221 if (prdVtx and prdVtx->id() != endVtx->id()) {
222 auto outbound = endVtx->particles_out();
223 auto inbound = endVtx->particles_in();
224 LOG(debug) << " prd " << std::setw(3) << prdVtx->id() << " "
225 << std::setw(3) << outbound.size() << " out "
226 << " "
227 << std::setw(3) << inbound.size() << " in ";
228
229 // Other out-bound particles of the end vertex are attached as
230 // out-going to the production vertex of this particle.
231 for (auto outgoing : outbound) {
232 // This should also detach the particle from its old
233 // end-vertex.
234 if (outgoing) {
235 auto ee = outgoing->end_vertex();
236 if (not ee or ee->id() != prdVtx->id()) {
237 prdVtx->add_particle_out(outgoing);
238 }
239 LOG(debug) << " " << std::setw(3) << outgoing->id();
240 }
241 }
242
243 // Other incoming particles to the end vertex of this
244 // particles are attached incoming particles to the production
245 // vertex of this particle.
246 for (auto incoming : inbound) {
247 if (incoming) {
248 auto pp = incoming->production_vertex();
249 if (not pp or pp->id() != prdVtx->id()) {
250 prdVtx->add_particle_in(incoming);
251 }
252
253 LOG(debug) << " " << std::setw(3) << incoming->id();
254 }
255 }
256 }
257 }
258 if (prdVtx) {
259 prdVtx->remove_particle_out(particle);
260 }
261 }
262
263 LOG(debug) << "Selected " << nSelect << " particles\n"
264 << "Removing " << toRemove.size() << " particles";
265 size_t oldSize = particles.size();
266 for (auto particle : toRemove) {
267 event.remove_particle(particle);
268 }
269
270 std::list<HepMC3::GenVertexPtr> remVtx;
271 for (auto vtx : event.vertices()) {
272 if (not vtx or
273 (vtx->particles_out().empty() and
274 vtx->particles_in().empty())) {
275 remVtx.push_back(vtx);
276 }
277 }
278 LOG(debug) << "Removing " << remVtx.size() << " vertexes";
279 for (auto vtx : remVtx) {
280 event.remove_vertex(vtx);
281 }
282
283 LOG(debug) << "HepMC events was pruned from " << oldSize
284 << " particles to " << event.particles().size()
285 << " particles and " << event.vertices().size()
286 << " vertices";
287}
288
289/*****************************************************************/
290
292{
294 if (mPrune) {
295 auto select = [](HepMC3::ConstGenParticlePtr particle) {
296 switch (particle->status()) {
297 case 1: // Final st
298 case 2: // Decayed
299 case 4: // Beam
300 return true;
301 }
302 // To also keep diffractive particles
303 // if (particle->pid() == 9902210) return true;
304 return false;
305 };
307 }
308
310 mParticles.clear();
311 auto particles = mEvent->particles();
312 for (int i = 0; i < particles.size(); ++i) {
313
315 auto particle = particles.at(i);
316 auto momentum = particle->momentum();
317 auto vertex = particle->production_vertex()->position();
318 auto parents = particle->parents();
319 auto children = particle->children();
320
322 auto m1 = parents.empty() ? -1 : parents.front()->id() - 1;
323 auto m2 = parents.empty() ? -1 : parents.back()->id() - 1;
324
326 auto d1 = children.empty() ? -1 : children.front()->id() - 1;
327 auto d2 = children.empty() ? -1 : children.back()->id() - 1;
328
330 mParticles.push_back(TParticle(particle->pid(), // Particle type
331 particle->status(), // Status code
332 m1, // First mother
333 m2, // Second mother
334 d1, // First daughter
335 d2, // Last daughter
336 momentum.x(), // X-momentum
337 momentum.y(), // Y-momentum
338 momentum.z(), // Z-momentum
339 momentum.t(), // Energy
340 vertex.x(), // Production X
341 vertex.y(), // Production Y
342 vertex.z(), // Production Z
343 vertex.t())); // Production time
345 mParticles.back(), // Add to back
346 particle->status() == 1); // only final state are to be propagated
347
348 }
351 return kTRUE;
352}
353
354namespace
355{
356template <typename AttributeType, typename TargetType>
357bool putAttributeInfoImpl(o2::dataformats::MCEventHeader* eventHeader,
358 const std::string& name,
359 const std::shared_ptr<HepMC3::Attribute>& a)
360{
361 if (auto* p = dynamic_cast<AttributeType*>(a.get())) {
362 eventHeader->putInfo<TargetType>(name, p->value());
363 return true;
364 }
365 return false;
366}
367
368void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader,
369 const std::string& name,
370 const std::shared_ptr<HepMC3::Attribute>& a)
371{
372 using IntAttribute = HepMC3::IntAttribute;
373 using LongAttribute = HepMC3::LongAttribute;
374 using FloatAttribute = HepMC3::FloatAttribute;
375 using DoubleAttribute = HepMC3::DoubleAttribute;
376 using StringAttribute = HepMC3::StringAttribute;
377 using CharAttribute = HepMC3::CharAttribute;
378 using LongLongAttribute = HepMC3::LongLongAttribute;
379 using LongDoubleAttribute = HepMC3::LongDoubleAttribute;
380 using UIntAttribute = HepMC3::UIntAttribute;
381 using ULongAttribute = HepMC3::ULongAttribute;
382 using ULongLongAttribute = HepMC3::ULongLongAttribute;
383 using BoolAttribute = HepMC3::BoolAttribute;
384
385 if (putAttributeInfoImpl<IntAttribute, int>(eventHeader, name, a)) {
386 return;
387 }
388 if (putAttributeInfoImpl<LongAttribute, int>(eventHeader, name, a)) {
389 return;
390 }
391 if (putAttributeInfoImpl<FloatAttribute, float>(eventHeader, name, a)) {
392 return;
393 }
394 if (putAttributeInfoImpl<DoubleAttribute, float>(eventHeader, name, a)) {
395 return;
396 }
397 if (putAttributeInfoImpl<StringAttribute, std::string>(eventHeader, name, a)) {
398 return;
399 }
400 if (putAttributeInfoImpl<CharAttribute, char>(eventHeader, name, a)) {
401 return;
402 }
403 if (putAttributeInfoImpl<LongLongAttribute, int>(eventHeader, name, a)) {
404 return;
405 }
406 if (putAttributeInfoImpl<LongDoubleAttribute, float>(eventHeader, name, a)) {
407 return;
408 }
409 if (putAttributeInfoImpl<UIntAttribute, int>(eventHeader, name, a)) {
410 return;
411 }
412 if (putAttributeInfoImpl<ULongAttribute, int>(eventHeader, name, a)) {
413 return;
414 }
415 if (putAttributeInfoImpl<ULongLongAttribute, int>(eventHeader, name, a)) {
416 return;
417 }
418 if (putAttributeInfoImpl<BoolAttribute, bool>(eventHeader, name, a)) {
419 return;
420 }
421}
422} // namespace
423
424/*****************************************************************/
425
427{
430
431 eventHeader->putInfo<std::string>(Key::generator, "hepmc");
432 eventHeader->putInfo<int>(Key::generatorVersion, HEPMC3_VERSION_CODE);
433
434 auto xSection = mEvent->cross_section();
435 auto pdfInfo = mEvent->pdf_info();
436 auto hiInfo = mEvent->heavy_ion();
437
438 // Workaround for a bug in HepMC3 (3.3.1 on 23/02/2026): GenHeavyIon::from_string() for the "v0"
439 // format skips reading user_cent_estimate, but to_string() always writes it.
440 // This shifts all subsequent fields by one, causing a istringstream failure and and heavy_ion()
441 // to return null even when the attribute is present and well-formed.
442 // For now we use this manual parser in case the infos are available
443 if (!hiInfo) {
444 auto attStr = mEvent->attribute_as_string("GenHeavyIon");
445 if (!attStr.empty() && attStr[0] == 'v') {
446 std::istringstream is(attStr);
447 std::string version;
448 is >> version;
449 if (version == "v0") {
450 auto hi = std::make_shared<HepMC3::GenHeavyIon>();
451 double spectNeutrons, spectProtons, eccentricity, userCentEst;
452 is >> hi->Ncoll_hard >> hi->Npart_proj >> hi->Npart_targ >> hi->Ncoll >> spectNeutrons >> spectProtons // deprecated v0 fields
453 >> hi->N_Nwounded_collisions >> hi->Nwounded_N_collisions >> hi->Nwounded_Nwounded_collisions >> hi->impact_parameter >> hi->event_plane_angle >> eccentricity // deprecated v0 field
454 >> hi->sigma_inel_NN >> hi->centrality >> userCentEst // GenHeavyIon::to_string always writes this, but GenHeavyIon::from_string skips it for v0 (HepMC3 bug to fix)
455 >> hi->Nspec_proj_n >> hi->Nspec_targ_n >> hi->Nspec_proj_p >> hi->Nspec_targ_p;
456 if (!is.fail()) {
457 LOG(debug) << "GenHeavyIon: using manual v0 parser (workaround for HepMC3 from_string bug)";
458 hiInfo = hi;
459 } else {
460 LOG(warn) << "GenHeavyIon: manual v0 parser also failed on: [" << attStr << "]";
461 }
462 }
463 }
464 }
465
466 // Set default cross-section
467 if (xSection) {
468 eventHeader->putInfo<float>(Key::xSection, xSection->xsec());
469 eventHeader->putInfo<float>(Key::xSectionError, xSection->xsec_err());
470 eventHeader->putInfo<int>(Key::acceptedEvents,
471 xSection->get_accepted_events());
472 eventHeader->putInfo<int>(Key::attemptedEvents,
473 xSection->get_attempted_events());
474 }
475
476 // Set weights and cross sections
477 size_t iw = 0;
478 for (auto w : mEvent->weights()) {
479 std::string post = (iw > 0 ? "_" + std::to_string(iw) : "");
480 eventHeader->putInfo<float>(Key::weight + post, w);
481 if (xSection) {
482 eventHeader->putInfo<float>(Key::xSection, xSection->xsec(iw));
483 eventHeader->putInfo<float>(Key::xSectionError, xSection->xsec_err(iw));
484 }
485 iw++;
486 }
487
488 // Set the PDF information
489 if (pdfInfo) {
490 eventHeader->putInfo<int>(Key::pdfParton1Id, pdfInfo->parton_id[0]);
491 eventHeader->putInfo<int>(Key::pdfParton2Id, pdfInfo->parton_id[1]);
492 eventHeader->putInfo<float>(Key::pdfX1, pdfInfo->x[0]);
493 eventHeader->putInfo<float>(Key::pdfX2, pdfInfo->x[1]);
494 eventHeader->putInfo<float>(Key::pdfScale, pdfInfo->scale);
495 eventHeader->putInfo<float>(Key::pdfXF1, pdfInfo->xf[0]);
496 eventHeader->putInfo<float>(Key::pdfXF2, pdfInfo->xf[1]);
497 eventHeader->putInfo<int>(Key::pdfCode1, pdfInfo->pdf_id[0]);
498 eventHeader->putInfo<int>(Key::pdfCode2, pdfInfo->pdf_id[1]);
499 }
500
501 // Set heavy-ion information
502 if (hiInfo) {
503 eventHeader->SetB(hiInfo->impact_parameter); // sets the impact parameter to the FairMCEventHeader field for quick access in the AO2D
504 eventHeader->putInfo<float>(Key::impactParameter,
505 hiInfo->impact_parameter);
506 eventHeader->putInfo<int>(Key::nPart,
507 hiInfo->Npart_proj + hiInfo->Npart_targ);
508 eventHeader->putInfo<int>(Key::nPartProjectile, hiInfo->Npart_proj);
509 eventHeader->putInfo<int>(Key::nPartTarget, hiInfo->Npart_targ);
510 eventHeader->putInfo<int>(Key::nColl, hiInfo->Ncoll);
511 eventHeader->putInfo<int>(Key::nCollHard, hiInfo->Ncoll_hard);
512 eventHeader->putInfo<int>(Key::nCollNNWounded,
513 hiInfo->N_Nwounded_collisions);
514 eventHeader->putInfo<int>(Key::nCollNWoundedN,
515 hiInfo->Nwounded_N_collisions);
516 eventHeader->putInfo<int>(Key::nCollNWoundedNwounded,
517 hiInfo->Nwounded_Nwounded_collisions);
518 eventHeader->putInfo<double>(Key::planeAngle, hiInfo->event_plane_angle);
519 eventHeader->putInfo<float>(Key::sigmaInelNN, hiInfo->sigma_inel_NN);
520 eventHeader->putInfo<float>(Key::centrality, hiInfo->centrality);
521 eventHeader->putInfo<int>(Key::nSpecProjectileProton, hiInfo->Nspec_proj_p);
522 eventHeader->putInfo<int>(Key::nSpecProjectileNeutron, hiInfo->Nspec_proj_n);
523 eventHeader->putInfo<int>(Key::nSpecTargetProton, hiInfo->Nspec_targ_p);
524 eventHeader->putInfo<int>(Key::nSpecTargetNeutron, hiInfo->Nspec_targ_n);
525 }
526
527 for (auto na : mEvent->attributes()) {
528 std::string name = na.first;
529 if (name == "GenPdfInfo" ||
530 name == "GenCrossSection" ||
531 name == "GenHeavyIon") {
532 continue;
533 }
534
535 for (auto ia : na.second) {
536 int no = ia.first;
537 auto at = ia.second;
538 std::string post = (no == 0 ? "" : std::to_string(no));
539
540 putAttributeInfo(eventHeader, name + post, at);
541 }
542 }
543
544 // When randomised is enabled, the header comes from the last served event
545 if (mRandomize or mRoundRobin) {
546 eventHeader->putInfo<std::string>("forwarding-generator", "generatorHepMC");
547 eventHeader->putInfo<std::string>("forwarding-generator_inputFile", mCurrentFileName);
548 eventHeader->putInfo<int>("forwarding-generator_inputEventNumber", mLastEntryRead);
549 }
550}
551
552/*****************************************************************/
553
555{
556 // Reset the reader smart pointer
557 LOG(debug) << "Reseting the reader";
558 mReader.reset();
559
560 // Check that we have any file names left
561 if (mFileNames.size() < 1) {
562 LOG(debug) << "No more files to read, return false";
563 return false;
564 }
565
566 // If we have file names left, pop the top of the list (LIFO)
567 auto filename = mFileNames.front();
568 mFileNames.pop_front();
569
570 LOG(debug) << "Next file to read: \"" << filename << "\" "
571 << mFileNames.size() << " left";
572
573 if (not mCmd.empty()) {
574 // For FIFO reading, we assume straight ASCII output always.
575 // Unfortunately, the HepMC3::deduce_reader `stat`s the filename
576 // which isn't supported on a FIFO, so we have to use the reader
577 // directly. Here, we allow for version 2 formats if the user
578 // specifies that
579 LOG(info) << "Creating ASCII reader of " << filename;
580 if (mVersion == 2) {
581 mReader = std::make_shared<HepMC3::ReaderAsciiHepMC2>(filename);
582 } else {
583 mReader = std::make_shared<HepMC3::ReaderAscii>(filename);
584 }
585 } else {
586 LOG(info) << "Deduce a reader of " << filename;
587 mReader = HepMC3::deduce_reader(filename);
588 }
589
590 bool ret = bool(mReader) and not mReader->failed();
591 LOG(info) << "Reader is " << mReader.get() << " " << ret;
592 return ret;
593}
594
595/*****************************************************************/
596
597bool GeneratorHepMC::buildIndex(const std::string& filename)
598{
599 // Going through the file once to know how many events it holds and to
600 // record where each of them starts. This way a single
601 // seek is performed instead of a scan from the current position
602 mEventOffsets.clear();
603 mIndexedStream.reset();
604 mIndexedHepMC2 = false;
605
606 HepMC3::InputInfo info(filename);
607 if (info.m_error or info.m_remote or info.m_pipe or
608 not(info.m_asciiv3 or info.m_iogenevent)) {
609 return false;
610 }
611 mIndexedHepMC2 = info.m_iogenevent;
612
613 auto stream = std::make_shared<std::ifstream>(filename);
614 if (not stream->good()) {
615 LOG(error) << "Could not open " << filename << " to index its events";
616 return false;
617 }
618 std::shared_ptr<HepMC3::Reader> reader;
619 if (mIndexedHepMC2) {
620 reader = std::make_shared<HepMC3::ReaderAsciiHepMC2>(stream);
621 } else {
622 reader = std::make_shared<HepMC3::ReaderAscii>(stream);
623 }
624 if (not reader or reader->failed()) {
625 LOG(error) << "Could not open " << filename << " to index its events";
626 return false;
627 }
628
629 // the offsets come from the parser itself rather than from guessing at line prefixes
630 constexpr int max_events = 100000000;
631 HepMC3::GenEvent event;
632 while ((int)mEventOffsets.size() < max_events) {
633 auto here = (std::streamoff)stream->tellg();
634 event.clear();
635 reader->read_event(event);
636 if (reader->failed()) {
637 break;
638 }
639 mEventOffsets.push_back(here);
640 }
641 if ((int)mEventOffsets.size() >= max_events) {
642 LOG(warn) << "Stopped indexing the events of " << filename << " at " << max_events;
643 }
644 if (mEventOffsets.empty()) {
645 LOG(error) << "No event found in HepMC file " << filename;
646 return false;
647 }
648
649 // keep the reader and its stream: serving an entry is now a seek plus a read.
652 mReader = reader;
653 mLastEntryRead = -1;
654 LOG(info) << "Indexed " << mEventOffsets.size() << " events of " << filename;
655 return true;
656}
657
658/*****************************************************************/
659
661{
662 // The entry starts at a byte offset recorded by buildIndex
663 if (entry < 0 or entry >= (int)mEventOffsets.size() or not mIndexedStream or not mReader) {
664 LOG(error) << "No entry " << entry << " in " << mCurrentFileName;
665 return false;
666 }
667 mIndexedStream->clear();
669
671 mEvent->clear();
672 mReader->read_event(*mEvent);
673 if (mReader->failed()) {
674 LOG(error) << "Reading entry " << entry << " of " << mCurrentFileName << " failed";
675 return false;
676 }
678 mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM);
680 LOG(debug) << "Read one event " << mEvent->event_number();
681 return true;
682}
683
684/*****************************************************************/
685
687{
688 // Decide the order in which the entries of the input file are served
689 // The events to skip at the start of the file are left out of the read
690 auto first = (int)std::min<uint64_t>(mEventsToSkip, (uint64_t)std::max(mEventsAvailable, 0));
691 mEventOrder.resize(std::max(mEventsAvailable, 0) - first);
692 std::iota(mEventOrder.begin(), mEventOrder.end(), first);
693 if (mRandomize) {
694 // Shuffle based on the ROOT random generator
695 for (int i = (int)mEventOrder.size() - 1; i > 0; --i) {
696 auto j = (int)gRandom->Integer(i + 1);
697 std::swap(mEventOrder[i], mEventOrder[j]);
698 }
699 }
700}
701
702/*****************************************************************/
703
705{
706 // The entry to be read is fixed by the event order established at file opening
707 if (mEventCounter >= (int)mEventOrder.size()) {
708 if (not mRoundRobin) {
709 auto requested = getTotalNEvents();
710 LOG(fatal) << "GeneratorHepMC: ran out of events after " << mEventsServed
711 << " event(s) from " << mCurrentFileName
712 << (requested > 0 ? " (" + std::to_string(requested) + " were requested)" : "")
713 << ". Provide more events or allow reusing them via roundRobin";
714 return false;
715 }
716 // start over from the beginning of the file, with a fresh order if requested
717 LOG(info) << "GeneratorHepMC - Reached the end of the input; reusing its events";
718 mEventCounter = 0;
719 if (mReshuffleOnRepeat) {
721 }
722 }
723 if (mEventOrder.empty()) {
724 LOG(error) << "GeneratorHepMC: no usable event in " << mCurrentFileName;
725 return false;
726 }
727
729 if (mRandomize) {
730 LOG(info) << "GeneratorHepMC - Picking event " << entry;
731 }
732 if (not readEntry(entry)) {
733 return false;
734 }
737 return true;
738}
739
740/*****************************************************************/
741
743{
748
749 // If a EG command line is given, then we make a fifo on a temporary
750 // file, and directs the EG to write to that fifo. We will then set
751 // up the HepMC3 reader to read from that fifo.
752 //
753 // o2-sim -g hepmc --configKeyValues "HepMC.progCmd=<cmd>" ...
754 //
755 // where <cmd> is the command line to run an event generator. The
756 // event generator should output HepMC event records to standard
757 // output. Nothing else, but the HepMC event record may be output
758 // to standard output. If the EG has other output to standard
759 // output, then a filter can be set-up. For example
760 //
761 // crmc -n 3 -o hepmc3 -c /optsw/inst/etc/crmc.param -f /dev/stdout \
762 // | sed -n 's/^\‍(HepMC::\|[EAUWVP] \‍)/\1/p'
763 //
764 // What's more, the event generator program _must_ accept the
765 // following command line argument
766 //
767 // `-n NEVENTS` to set the number of events to produce.
768 //
769 // Optionally, the command line should also accept
770 //
771 // `-s SEED` to set the random number seed
772 // `-b FM` to set the maximum impact parameter to sample
773 // `-o OUTPUT` to set the output file name
774 //
775 // All of this can conviniently be achieved via a wrapper script
776 // around the actual EG program.
777 if (not mCmd.empty()) {
778 if (mFileNames.empty()) {
779 // Set filename to be a temporary name
780 if (not makeTemp(false)) {
781 return false;
782 }
783 } else {
784 // Use the first filename as output for cmd line
785 if (not makeTemp(true)) {
786 return false;
787 }
788 }
789
790 // Make a fifo
791 if (not makeFifo()) {
792 return false;
793 }
794
795 // Build command line, rediret stdout to our fifo and put
796 std::string cmd = makeCmdLine();
797 LOG(debug) << "EG command line is \"" << cmd << "\"";
798
799 // Execute the command line
800 if (not executeCmdLine(cmd)) {
801 LOG(fatal) << "Failed to spawn \"" << cmd << "\"";
802 return false;
803 }
804 } else {
805 // If no command line was given, ensure that all files are present
806 // on the system. Note, in principle, HepMC3 can read from remote
807 // files
808 //
809 // root:// XRootD served
810 // http[s]:// Web served
811 // gsidcap:// DCap served
812 //
813 // These will all be handled in HepMC3 via ROOT's TFile protocol
814 // and the files are assumed to contain a TTree named
815 // `hepmc3_tree` and that tree has the branches
816 //
817 // `hepmc3_event` with object of type `HepMC3::GenEventData`
818 // `GenRunInfo` with object of type `HepMC3::GenRunInfoData`
819 //
820 // where the last branch is optional.
821 //
822 // However, here we will assume system local files. If _any_ of
823 // the listed files do not exist, then we fail.
824 if (not ensureFiles()) {
825 return false;
826 }
827 }
828
829 // Serving the events in random order
830 if (mRandomize or mRoundRobin) {
831 if (not mCmd.empty()) {
832 LOG(fatal) << "HepMC.randomize/HepMC.roundRobin cannot be used when the events "
833 << "come from a command, as the pipe can only be read once";
834 return false;
835 }
836 if (mFileNames.size() != 1) {
837 LOG(fatal) << "HepMC.randomize/HepMC.roundRobin need exactly one input file, but "
838 << mFileNames.size() << " were given";
839 return false;
840 }
841 if (mRngSeed > 0) {
842 // with a zero the seed given to the driver (o2-sim --seed) stays in control
843 gRandom->SetSeed(mRngSeed);
844 }
845 LOG(info) << "GeneratorHepMC: the event order is drawn with gRandom (" << gRandom->ClassName()
846 << ") seeded with " << gRandom->GetSeed();
847
848 auto const& filename = mFileNames.front();
849 // Indexing the file gives us both the number of events and constant-time access
850 // to any of them, and creates the reader we then serve the events from
851 if (not buildIndex(filename)) {
852 LOG(fatal) << "HepMC.randomize/HepMC.roundRobin need an input the events can be "
853 << "picked from in any order, which means a plain HepMC3 or HepMC2 "
854 << "ASCII file; " << filename << " is not one. Convert it, or convert "
855 << "it to O2 kinematics and read it back with -g extkinO2, which "
856 << "randomizes over a TTree";
857 return false;
858 }
859 mEventsAvailable = (int)mEventOffsets.size();
861 LOG(fatal) << "HepMC.eventsToSkip (" << mEventsToSkip << ") leaves no event of the "
862 << mEventsAvailable << " contained in " << filename;
863 return false;
864 }
866 auto requested = getTotalNEvents();
867 if (requested > 0 and not mRoundRobin and mEventOrder.size() < requested) {
868 LOG(warn) << "This job will request " << requested << " events, but the input holds "
869 << "only " << mEventOrder.size() << " usable event(s). The job will stop "
870 << "with 'ran out of events' - provide more events or enable roundRobin";
871 }
872 LOG(info) << "Reading events from HepMC file " << filename << " (" << mEventsAvailable
873 << " events, " << (mRandomize ? "randomized" : "sequential") << " order)";
874 }
875
876 // Create reader for current (first) file
877 return true;
878}
879
880/*****************************************************************/
881/*****************************************************************/
882
883} /* namespace eventgen */
884} /* namespace o2 */
o2::monitoring::tags::Key Key
std::ostringstream debug
uint64_t vertex
Definition RawEventData.h:9
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char pp
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc bool
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs and
char error[CURL_ERROR_SIZE]
Utility functions for MC particles.
uint32_t j
Definition RawData.h:0
uint32_t version
Definition RawData.h:8
void SetB(Double_t b)
void putInfo(std::string const &key, T const &value)
void updateHeader(o2::dataformats::MCEventHeader *eventHeader) override
void setEventsToSkip(uint64_t val)
std::vector< int > mEventOrder
std::vector< std::streamoff > mEventOffsets
void setupHepMC(const HepMCGenConfig &param)
std::shared_ptr< std::istream > mIndexedStream
void setup(const GeneratorFileOrCmdParam &param0, const HepMCGenConfig &param, const conf::SimConfig &config)
std::shared_ptr< HepMC3::Reader > mReader
bool buildIndex(const std::string &filename)
std::string mInterfaceName
Definition Generator.h:141
static unsigned int getTotalNEvents()
Definition Generator.h:102
std::vector< TParticle > mParticles
Definition Generator.h:161
Bool_t Init() override
static void encodeParticleStatusAndTracking(TParticle &particle, bool wanttracking=true)
Definition MCUtils.cxx:211
struct _cl_event * event
Definition glcorearb.h:2982
GLuint entry
Definition glcorearb.h:5735
GLuint const GLchar * name
Definition glcorearb.h:781
GLint first
Definition glcorearb.h:399
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint GLuint stream
Definition glcorearb.h:1806
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
static constexpr unsigned int sStopGraceMillis
virtual bool terminateCmd(unsigned int graceMillis=0)
virtual std::string makeCmdLine() const
virtual bool executeCmdLine(const std::string &cmd)
virtual bool makeTemp(const bool &)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"