24#define BOOST_TEST_MODULE Test GeneratorHepMC indexed access
25#define BOOST_TEST_MAIN
26#define BOOST_TEST_DYN_LINK
27#include <boost/test/unit_test.hpp>
34#include <HepMC3/GenEvent.h>
35#include <HepMC3/GenParticle.h>
36#include <HepMC3/GenRunInfo.h>
37#include <HepMC3/ReaderAscii.h>
38#include <HepMC3/ReaderAsciiHepMC2.h>
39#include <HepMC3/WriterAsciiHepMC2.h>
54double expectedPx(
int i) {
return 10. +
i; }
58std::string writeInput(
const std::string&
name,
int nEvents)
60 std::ofstream out(
name);
61 out <<
"HepMC::Version 3.02.05\n"
62 <<
"HepMC::Asciiv3-START_EVENT_LISTING\n"
64 <<
"T unit-test|indexed-access|\n";
66 const double px = expectedPx(
i);
67 out <<
"E " <<
i + 1 <<
" 1 4\n"
70 <<
"P 1 0 2212 0.000000e+00 0.000000e+00 +6.500000e+03 6.500000e+03 9.383000e-01 4\n"
71 <<
"P 2 0 2212 0.000000e+00 0.000000e+00 -6.500000e+03 6.500000e+03 9.383000e-01 4\n"
72 <<
"V -1 0.000000e+00 0.000000e+00 0.000000e+00 [1,2]\n"
73 <<
"P 3 -1 211 " << px <<
" 1.000000e+00 1.000000e+00 " << px + 5. <<
" 1.395700e-01 1\n"
74 <<
"P 4 -1 -211 " << -px <<
" -1.000000e+00 -1.000000e+00 " << px + 5. <<
" 1.395700e-01 1\n";
76 out <<
"HepMC::Asciiv3-END_EVENT_LISTING\n";
82std::string writeInputHepMC2(
const std::string& asciiv3,
const std::string&
name)
84 HepMC3::ReaderAscii in(asciiv3);
85 HepMC3::WriterAsciiHepMC2 out(
name);
87 HepMC3::GenEvent
event;
92 out.write_event(
event);
100std::string fingerprint(
const HepMC3::GenEvent&
event)
107 for (
const auto& p :
event.particles()) {
108 snprintf(
buf,
sizeof buf,
" [%d,%d,%.9e,%.9e,%.9e,%.9e]", p->pid(), p->status(),
109 p->momentum().x(), p->momentum().y(), p->momentum().z(), p->momentum().t());
117 const std::string
key =
"forwarding-generator_inputEventNumber";
127int servedEntry(
const std::vector<o2::MCTrack>& tracks)
129 auto outgoing = std::find_if(tracks.begin(), tracks.end(),
130 [](
const o2::MCTrack& t) { return t.GetPdgCode() == 211; });
131 if (outgoing == tracks.end()) {
134 return (
int)std::lround(outgoing->Px() - expectedPx(0));
138void configure(
const std::string& file,
int eventsToSkip = 0)
141 "GeneratorFileOrCmd.fileNames=" + file +
142 ";HepMC.randomize=true;HepMC.roundRobin=true;HepMC.reshuffleOnRepeat=false"
143 ";HepMC.rngseed=12345;HepMC.eventsToSkip=" +
153void checkSeekEquivalence(
const std::string& file,
bool hepmc2)
155 auto makeReader = [hepmc2](std::shared_ptr<std::istream>
stream) -> std::shared_ptr<HepMC3::Reader> {
157 return std::make_shared<HepMC3::ReaderAsciiHepMC2>(
stream);
159 return std::make_shared<HepMC3::ReaderAscii>(
stream);
163 std::vector<std::streamoff>
offsets;
164 std::vector<std::string> sequential;
166 auto stream = std::make_shared<std::ifstream>(file);
167 BOOST_REQUIRE(
stream->good());
168 auto reader = makeReader(
stream);
170 auto here = (std::streamoff)
stream->tellg();
171 HepMC3::GenEvent
event;
172 reader->read_event(
event);
173 if (reader->failed()) {
177 sequential.push_back(fingerprint(
event));
180 BOOST_REQUIRE_MESSAGE(!
offsets.empty(),
"no event indexed in " << file);
183 auto stream = std::make_shared<std::ifstream>(file);
184 BOOST_REQUIRE(
stream->good());
185 auto reader = makeReader(
stream);
187 HepMC3::GenEvent header;
188 reader->read_event(header);
192 HepMC3::GenEvent
event;
193 reader->read_event(
event);
194 BOOST_REQUIRE_MESSAGE(!reader->failed(),
195 file <<
": could not read entry " <<
entry <<
" by seeking");
196 BOOST_CHECK_MESSAGE(fingerprint(
event) == sequential[
entry],
197 file <<
": entry " <<
entry <<
" read by seeking differs from the "
198 <<
"sequential read; the HepMC3 reader can no longer be "
199 <<
"repositioned and GeneratorHepMC's indexed access is unsafe");
200 BOOST_CHECK_MESSAGE(
event.run_info() !=
nullptr,
201 file <<
": entry " <<
entry <<
" lost its GenRunInfo");
212 auto asciiv3 = writeInput(
"test_GeneratorHepMCIndexed_seek.hepmc",
nEvents);
213 auto hepmc2 = writeInputHepMC2(asciiv3,
"test_GeneratorHepMCIndexed_seek2.hepmc");
215 checkSeekEquivalence(asciiv3,
false);
216 checkSeekEquivalence(hepmc2,
true);
218 std::remove(asciiv3.c_str());
219 std::remove(hepmc2.c_str());
230 auto name = writeInput(
"test_GeneratorHepMCIndexed_gen.hepmc",
nEvents);
237 std::vector<int> served;
242 "event " <<
i <<
" belongs to no entry of the input");
245 BOOST_CHECK_MESSAGE(announcedEntry(
event.second) ==
entry,
246 "event " <<
i <<
": the generator reports entry "
247 << announcedEntry(
event.second)
248 <<
" but handed out the event stored at entry " <<
entry);
249 served.push_back(
entry);
254 std::iota(all.begin(), all.end(), 0);
255 std::vector<int> pass1(served.begin(), served.begin() +
nEvents);
256 std::vector<int> pass2(served.begin() +
nEvents, served.begin() + 2 *
nEvents);
257 std::vector<int> sorted1 = pass1;
258 std::vector<int> sorted2 = pass2;
259 std::sort(sorted1.begin(), sorted1.end());
260 std::sort(sorted2.begin(), sorted2.end());
270 std::remove(
name.c_str());
279 constexpr int toSkip = 18;
280 auto name = writeInput(
"test_GeneratorHepMCIndexed_skip.hepmc",
nEvents);
281 configure(
name, toSkip);
286 std::vector<int> served;
287 for (
int i = 0;
i < 2 * (
nEvents - toSkip); ++
i) {
291 "event " <<
i <<
" came from entry " <<
entry
292 <<
", outside the requested range [" << toSkip <<
", "
294 BOOST_CHECK_MESSAGE(announcedEntry(
event.second) ==
entry,
295 "event " <<
i <<
": the generator reports entry "
296 << announcedEntry(
event.second)
297 <<
" but handed out the event stored at entry " <<
entry);
298 served.push_back(
entry);
301 std::vector<int> usable(
nEvents - toSkip);
302 std::iota(usable.begin(), usable.end(), toSkip);
303 std::vector<int> pass1(served.begin(), served.begin() + (
nEvents - toSkip));
305 std::sort(sorted.begin(), sorted.end());
308 std::remove(
name.c_str());
316 auto asciiv3 = writeInput(
"test_GeneratorHepMCIndexed_h2src.hepmc",
nEvents);
317 auto name = writeInputHepMC2(asciiv3,
"test_GeneratorHepMCIndexed_h2.hepmc");
318 std::remove(asciiv3.c_str());
324 std::vector<int> served;
329 "event " <<
i <<
" belongs to no entry of the HepMC2 input");
330 BOOST_CHECK_MESSAGE(announcedEntry(
event.second) ==
entry,
331 "event " <<
i <<
": the generator reports entry "
332 << announcedEntry(
event.second)
333 <<
" but handed out the event stored at entry " <<
entry);
334 served.push_back(
entry);
337 std::iota(all.begin(), all.end(), 0);
338 auto sorted = served;
339 std::sort(sorted.begin(), sorted.end());
343 std::remove(
name.c_str());
Definition of the MCTrack class.
static void updateFromString(std::string const &)
A class offering convenient generator configuration and encapsulation of lower level classes....
std::pair< std::vector< MCTrack >, o2::dataformats::MCEventHeader > generateEvent()
void initService(std::string const &generatorName, std::string const &triggerName, VertexOption const &vtxOption)
GLuint GLsizei const GLuint const GLintptr * offsets
GLuint const GLchar * name
GLenum GLuint GLenum GLsizei const GLchar * buf
std::string to_string(gsl::span< T, Size > span)
BOOST_AUTO_TEST_CASE(hepmc3_reader_can_be_seeked)