9#include <generators/modules/herwigfragmentation/HerwigLHEWriterModule.h>
11#include <framework/logging/Logger.h>
12#include <framework/datastore/StoreArray.h>
13#include <framework/datastore/StoreObjPtr.h>
14#include <framework/dataobjects/EventMetaData.h>
32HerwigLHEWriterModule::HerwigLHEWriterModule() :
Module()
34 setDescription(
"Stage 1 of the Herwig multistep pipeline. "
35 "Collects KKMC MCParticles (e+, e-, virtual photon/Z0, q, qbar) into a single "
36 "multi-event LHE file and writes per-event KKMC sidecar files. ");
39 addParam(
"WorkDir", m_workDir,
"Working directory for LHE and sidecar files; auto-created if empty.",
41 addParam(
"ShowerScale", m_showerScale,
"Parton shower scale ceiling in GeV (Herwig's SCALUP upper bound)", 11.0);
44HerwigLHEWriterModule::~HerwigLHEWriterModule() {}
51 char tmpl[] =
"/tmp/herwig_batch_XXXXXX";
52 char* dir = mkdtemp(tmpl);
53 if (!dir) B2FATAL(
"HerwigLHEWriter: could not create temp directory");
59 B2INFO(
"HerwigLHEWriter: working directory = " <<
m_workingDir);
63 B2INFO(
"HerwigLHEWriter: batch seed = " <<
m_batchSeed);
71 B2FATAL(
"HerwigLHEWriter: could not open " <<
m_workingDir <<
"/all_events.lhe");
73 m_lheStream <<
"<LesHouchesEvents version=\"1.0\">\n<header></header>\n";
74 m_lheStream <<
"<init>\n 11 -11 " << std::scientific << std::setprecision(8)
75 << beamE <<
" " << beamE
77 <<
" 1.0000000000e+00 0.0000000000e+00 1.0000000000e+00 1\n</init>\n";
94 const std::string manifestPath =
m_workingDir +
"/manifest.txt";
95 std::ofstream mf(manifestPath);
97 B2ERROR(
"HerwigLHEWriter: could not write manifest to " << manifestPath);
100 mf <<
"# HerwigLHEWriter manifest\n";
105 mf << kv.first <<
" " << kv.second.sidecarFile <<
"\n";
107 B2INFO(
"HerwigLHEWriter: wrote manifest to " << manifestPath);
108 B2RESULT(
"HerwigLHEWriter: " <<
m_eventCounter <<
" events written to "
118 const int globalEvtNum =
static_cast<int>(eventMetaData->getEvent());
123 std::vector<MCParticle*> quarks;
124 for (
int i = 0; i < mcParticles.
getEntries(); ++i) {
126 int absPdg = std::abs(mc->getPDG());
127 if (absPdg >= 1 && absPdg <= 5 && mc->getDaughters().empty())
128 quarks.push_back(mc);
131 if (quarks.size() != 2) {
132 B2WARNING(
"HerwigLHEWriter: event " << globalEvtNum
133 <<
": expected 2 quarks, got " << quarks.size() <<
" -- skipping LHE write");
138 B2ERROR(
"HerwigLHEWriter: failed to write LHE event block for event " << globalEvtNum);
143 B2ERROR(
"HerwigLHEWriter: failed to write KKMC sidecar for event " << globalEvtNum);
148 std::ostringstream sidecarName;
149 sidecarName <<
"kkmc_evt" << std::setw(6) << std::setfill(
'0') << globalEvtNum <<
".sidecar";
150 m_manifest[globalEvtNum].sidecarFile = sidecarName.str();
156 if (quarks.size() != 2)
return false;
161 for (
auto* q : quarks) {
162 if (q->getPDG() > 0) quark = q;
165 if (!quark || !antiquark)
return false;
171 const double M2 = sE * sE - sPx * sPx - sPy * sPy - sPz * sPz;
172 const double scalup = (M2 > 0.0) ?
174 const double beamEnergy = sE / 2.0;
180 << std::scientific << std::setprecision(8)
181 <<
"1.00000000e+00 " << scalup <<
" 7.81653700e-03 1.18000000e-01\n";
183 m_lheStream <<
" 11 -1 0 0 0 0 " << std::showpos << 0.0
184 <<
" " << 0.0 <<
" " << beamEnergy <<
" "
185 << std::noshowpos << beamEnergy <<
" 0.0 0.0 -1.0\n";
186 m_lheStream <<
" -11 -1 0 0 0 0 " << std::showpos << 0.0
187 <<
" " << 0.0 <<
" " << -beamEnergy <<
" "
188 << std::noshowpos << beamEnergy <<
" 0.0 0.0 1.0\n";
193 << std::showpos << px <<
" " << py <<
" " << pz <<
" "
194 << std::noshowpos << e <<
" " << m <<
" 0.0 9.0\n";
200 << std::showpos << px <<
" " << py <<
" " << pz <<
" "
201 << std::noshowpos << e <<
" " << m <<
" 0.0 9.0\n";
210 std::ostringstream fname;
211 fname <<
m_workingDir <<
"/kkmc_evt" << std::setw(6) << std::setfill(
'0') << globalEvtNum <<
".sidecar";
212 std::ofstream sf(fname.str());
213 if (!sf.is_open())
return false;
218 sf <<
"# KKMC sidecar event " << globalEvtNum <<
"\n";
220 sf << std::scientific << std::setprecision(10);
221 for (
int i = 0; i < n; ++i) {
227 const ROOT::Math::XYZVector& mom = mc->getMomentum();
228 const ROOT::Math::XYZVector& vtx = mc->getProductionVertex();
229 sf << mc->getPDG() <<
" "
230 << mc->getEnergy() <<
" "
237 << mc->getProductionTime() <<
" "
238 << mc->getMass() <<
" "
239 << mc->getStatus() <<
" "
240 << motherIdx <<
"\n";
unsigned int m_batchSeed
Batch seed drawn from gRandom in initialize().
std::map< int, EventRecord > m_manifest
global_event_number -> EventRecord
std::string m_workingDir
Resolved working directory path.
virtual void initialize() override
Register required MCParticle StoreArray.
virtual void event() override
Accumulate one event into an LHE file and write its KKMC sidecar.
virtual void terminate() override
Close LHE file and write manifest.txt.
std::ofstream m_lheStream
Output stream to all_events.lhe (open from initialize to terminate).
std::string m_workDir
User-specified working dir; auto-created via mkdtemp if empty.
int m_eventCounter
Counts event() calls.
bool writeLHEEventBlock(const std::vector< MCParticle * > &quarks)
Write one <event>...</event> block to m_lheStream.
bool writeKKMCSidecar(int globalEvtNum)
Write per-event KKMC sidecar file: all MCParticles with momenta + parent links.
double m_showerScale
Maximum shower scale ceiling in GeV (default 11.0).
A Class to store the Monte Carlo particle information.
float getEnergy() const
Return particle energy in GeV.
float getMass() const
Return the particle mass in GeV.
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
int getPDG() const
Return PDG code of particle.
ROOT::Math::XYZVector getMomentum() const
Return momentum.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Accessor to arrays stored in the data store.
int getEntries() const
Get the number of objects in the array.
Type-safe access to single objects in the data store.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.