ATLAS Offline Software
Loading...
Searching...
No Matches
Pythia8::PowhegHooksST Class Reference

POWHEG resonance-veto hooks for single-top t- and s-channel events. More...

Inheritance diagram for Pythia8::PowhegHooksST:
Collaboration diagram for Pythia8::PowhegHooksST:

Classes

struct  EmissionScale

Public Member Functions

 PowhegHooksST ()
 Constructor and destructor for Athena UserHooksFactory.
 ~PowhegHooksST () override
bool initAfterBeams () override
 Initialize settings for the POWHEG resonance-veto strategy.
double pTpowhegFromRes (const Event &event, int iEmt, int iRad, int iRes)
 Compute the POWHEG transverse scale of a resonance splitting.
bool canSetResonanceScale () override
 Disable Pythia's ordinary resonance-scale assignment.
double scaleResonance (int iRes, const Event &event) override
 Reconstruct a resonance scale from the Pythia event record.
bool canVetoProcessLevel () override
 Advertise support for process-level processing.
bool doVetoProcessLevel (Event &event) override
 Build resonance veto scales before showering starts.
bool doVetoFSREmission (int sizeOld, const Event &e, int iSys, bool inResonance) override
 Veto too-hard QCD radiation from a decayed resonance.

Private Member Functions

std::vector< int > resonanceKey (int iRes, const Event &event) const
 Construct the stable signed-ID ancestry key for a resonance.
void storeResonanceScale (const std::vector< int > &key, double scale)
 Store a scale for a resonance ancestry and reject ambiguity.
int getEventType () const
 Extract rad_type / eventtype from LHE event comments.
void fillReadScales ()
 Populate POWHEG emission scales for the current event.
double readScale (int ires, double fallback) const
 Look up a POWHEG scale by original LHA resonance index.

Private Attributes

Pythia8_UserHooks::UserSetting< double > m_pTcutoffSetting
Pythia8_UserHooks::UserSetting< int > m_emscalesSetting
Pythia8_UserHooks::UserSetting< int > m_emscalesAltSetting
Pythia8_UserHooks::UserSetting< bool > m_debugSetting
int m_eventtype
double m_pTcutoff
int m_emscalesMode
int m_vetoMode
int m_QEDvetoMode
int m_vetoCount
std::map< std::vector< int >, double > m_vetoResScale
std::vector< EmissionScale > m_readScales

Detailed Description

POWHEG resonance-veto hooks for single-top t- and s-channel events.

Production radiation is delegated to PowhegHooks. This class handles QCD radiation from decayed resonances and vetoes emissions harder than the corresponding POWHEG resonance scale.

Resonance vetoes are enabled only for eventtype == 1 (the btilde contribution). Remnant and regular events (eventtype == 2 and 3) are not subject to this resonance veto, even if they contain a top.

emscales == 0 reconstructs scales from Pythia decay kinematics. emscales == 1 reads POWHEG's recorded scales using the original LHA resonance index. In mode 1, a resonance with no coloured daughters is unrestricted (1e30), while an unrecorded coloured decay uses pTcutoff.

Resonances are identified by signed-ID ancestry rather than Pythia's system number, which supports nested s-channel histories and event reordering.

In Athena, UserHooks are loaded dynamically via UserHooksFactory without direct access to LHAupPtr, so eventtype and #emscales information are retrieved directly from the LHE event comments via infoPtr->getEventComments().

Definition at line 70 of file PowhegHooksST.cxx.

Constructor & Destructor Documentation

◆ PowhegHooksST()

Pythia8::PowhegHooksST::PowhegHooksST ( )
inline

Constructor and destructor for Athena UserHooksFactory.

Initializes Pythia8_UserHooks::UserSetting handles for configuration via Athena JobOptions (e.g. POWHEG:single-top:emscales, POWHEG:pTcutoff).

Definition at line 80 of file PowhegHooksST.cxx.

81 : m_pTcutoffSetting("POWHEG:pTcutoff", 0.8),
82 m_emscalesSetting("POWHEG:single-top:emscales", 0),
83 m_emscalesAltSetting("POWHEG:emscales", 0),
84 m_debugSetting("POWHEG:single-top:DEBUG", false),
85 m_eventtype(1),
86 m_pTcutoff(0.8),
88 m_vetoMode(0),
91 {
92 std::cout << "**********************************************************" << std::endl;
93 std::cout << "* *" << std::endl;
94 std::cout << "* Applying PowhegHooksST UserHook (Single-Top)! *" << std::endl;
95 std::cout << "* Resonance-aware matching for single-top-dec-pwhg *" << std::endl;
96 std::cout << "* *" << std::endl;
97 std::cout << "**********************************************************" << std::endl;
98 }
Pythia8_UserHooks::UserSetting< bool > m_debugSetting
Pythia8_UserHooks::UserSetting< int > m_emscalesSetting
Pythia8_UserHooks::UserSetting< int > m_emscalesAltSetting
Pythia8_UserHooks::UserSetting< double > m_pTcutoffSetting

◆ ~PowhegHooksST()

Pythia8::PowhegHooksST::~PowhegHooksST ( )
inlineoverride

Definition at line 100 of file PowhegHooksST.cxx.

100{}

Member Function Documentation

◆ canSetResonanceScale()

bool Pythia8::PowhegHooksST::canSetResonanceScale ( )
inlineoverride

Disable Pythia's ordinary resonance-scale assignment.

Scales are assigned in doVetoProcessLevel(), before resonance showers are interleaved, so the result is independent of Pythia's system order.

Returns
Always false.

Definition at line 191 of file PowhegHooksST.cxx.

191{ return false; }

◆ canVetoProcessLevel()

bool Pythia8::PowhegHooksST::canVetoProcessLevel ( )
inlineoverride

Advertise support for process-level processing.

Returns
Always true.

Definition at line 272 of file PowhegHooksST.cxx.

272{ return true; }

◆ doVetoFSREmission()

bool Pythia8::PowhegHooksST::doVetoFSREmission ( int sizeOld,
const Event & e,
int iSys,
bool inResonance )
inlineoverride

Veto too-hard QCD radiation from a decayed resonance.

Production radiation and radiation outside a resonance are delegated to PowhegHooks. For eventtype == 1, resonance radiation is compared with the scale prepared by doVetoProcessLevel(). A scale of 1e30 is unrestricted. The colour test uses colType(), so top radiation such as t -> t g is kept.

Parameters
sizeOldEvent-record size before the emission.
eEvent record after the emission.
iSysPythia parton-system index.
inResonanceWhether the emission is inside a resonance.
Returns
true if the emission is vetoed, false otherwise.

Definition at line 332 of file PowhegHooksST.cxx.

332 {
333 // Radiation from the hard system: delegate to PowhegHooks
334 if (iSys == 0 || !inResonance) return PowhegHooks::doVetoFSREmission(sizeOld, e, iSys, inResonance);
335
336 if (m_eventtype != 1) return false;
337
338 // Get the participants of the splitting: the radiation and the emitter
339 const int iRad = e.size() - 2;
340 const int iEmtAft = e.size() - 3;
341 const int iEmtBef = e[iRad].mother1();
342
343 // Test colour rather than isParton(), which excludes the top in t -> t g
344 // radiation inside the s-channel W* decay.
345 // Do not veto QED radiation (i.e. if (pre or post) emitter or emission are not coloured;
346 // can be f -> f gamma, gamma -> f fb, with f quark or lepton)
347 if (m_QEDvetoMode == 0 && !(
348 e[iEmtAft].colType() != 0 && e[iEmtBef].colType() != 0
349 && e[iRad].colType() != 0)) {
350 return false;
351 }
352
353 // Get the resonance ID from the partonSystem pointer
354 const int iRes = partonSystemsPtr->getInRes(iSys);
355 // Systems are created as resonances decay, possibly interleaved with the
356 // shower. Resolve the actual incoming resonance instead of guessing iSys.
357 auto scale = m_vetoResScale.find(resonanceKey(iRes, e));
358 if (scale == m_vetoResScale.end()) {
359 if (loggerPtr) loggerPtr->ABORT_MSG("Cannot find the resonance the showering is coming from");
360 exit(1);
361 }
362 const double pTmax = scale->second;
363 if (pTmax == 1e30) return false;
364
365 const double pTcurr = pTpowhegFromRes(e, iEmtAft, iRad, iRes);
366 // Veto emissions harder than the powheg one
367 return (pTcurr > pTmax);
368 }
std::vector< int > resonanceKey(int iRes, const Event &event) const
Construct the stable signed-ID ancestry key for a resonance.
std::map< std::vector< int >, double > m_vetoResScale
double pTpowhegFromRes(const Event &event, int iEmt, int iRad, int iRes)
Compute the POWHEG transverse scale of a resonance splitting.

◆ doVetoProcessLevel()

bool Pythia8::PowhegHooksST::doVetoProcessLevel ( Event & event)
inlineoverride

Build resonance veto scales before showering starts.

No resonance scales are built for eventtype != 1. Otherwise scales are reconstructed from the event record or read using original LHA ires values.

Parameters
eventPythia event record for the current LHE event.
Returns
Always false; this prepares scales but does not reject the event.

Definition at line 283 of file PowhegHooksST.cxx.

283 {
284 m_vetoResScale.clear();
286
287 // Regular or remnant events have no POWHEG radiation in their decays. In particular,
288 // an empty emission-scale list must not turn into a cutoff veto for them.
289 if (m_eventtype != 1) return false;
290
291 if (m_emscalesMode == 1) {
293 // ires refers to the ORIGINAL LHA record, before Pythia reorders it.
294 // In Pythia's event record, LHE particles are offset by 2 beam entries (indices 1 and 2),
295 // so the original LHE index is i - 2.
296 // Identify a resonance by its signed IDs from the resonance to the root.
297 // This distinguishes e.g. W* -> t bbar -> W b bbar and W* -> W Z.
298 for (int i = 0; i < event.size(); ++i) {
299 if (event[i].statusAbs() == 22 && !event[i].daughterList().empty()) {
300 bool hasQCDDecay = false;
301 for (int d : event[i].daughterList()) {
302 if (particleDataPtr->colType(event[d].id()) != 0) hasQCDDecay = true;
303 }
304 double scale = readScale(i - 2, hasQCDDecay ? m_pTcutoff : 1e30);
305 storeResonanceScale(resonanceKey(i, event), scale);
306 }
307 }
308 } else {
309 for (int i = 0; i < event.size(); ++i) {
310 if (event[i].status() == -22 && !event[i].daughterList().empty()) {
311 storeResonanceScale(resonanceKey(i, event), scaleResonance(i, event));
312 }
313 }
314 }
315 return false;
316 }
static const Attributes_t empty
double readScale(int ires, double fallback) const
Look up a POWHEG scale by original LHA resonance index.
int getEventType() const
Extract rad_type / eventtype from LHE event comments.
void storeResonanceScale(const std::vector< int > &key, double scale)
Store a scale for a resonance ancestry and reject ambiguity.
double scaleResonance(int iRes, const Event &event) override
Reconstruct a resonance scale from the Pythia event record.
void fillReadScales()
Populate POWHEG emission scales for the current event.
status
Definition merge.py:16

◆ fillReadScales()

void Pythia8::PowhegHooksST::fillReadScales ( )
inlineprivate

Populate POWHEG emission scales for the current event.

In Athena, event comments recorded in the LHE event record are parsed for #emscales lines without needing the Fortran common block c_emscales_.

Definition at line 472 of file PowhegHooksST.cxx.

472 {
473 m_readScales.clear();
474 if (!infoPtr) return;
475 std::string comments = infoPtr->getEventComments();
476 if (comments.empty()) return;
477
478 std::istringstream iss(comments);
479 std::string line;
480 while (std::getline(iss, line)) {
481 if (line.compare(0, 9, "#emscales") != 0) continue;
482 if (line.find("nemissions=") != std::string::npos) continue;
483
484 EmissionScale es{};
485 int idx = 0;
486 if (std::sscanf(line.c_str(),
487 "#emscales i=%d scalup=%lf id_emitter=%d id_radiated=%d ires=%d",
488 &idx, &es.scalup, &es.id_emitter, &es.id_radiated, &es.ires) == 5) {
489 es.idx = idx;
490 m_readScales.push_back(es);
491 }
492 }
493 }
std::vector< EmissionScale > m_readScales

◆ getEventType()

int Pythia8::PowhegHooksST::getEventType ( ) const
inlineprivate

Extract rad_type / eventtype from LHE event comments.

In Athena, UserHooks run without the Fortran common block powhegeventssettings_. The event type (1 = btilde, 2 = remnant, 3 = regular) is parsed from the per-event comments (#rwgt <type> ... or # <type> rad_type).

Returns
The event type (1, 2, or 3). Defaults to 1 if comments cannot be found.

Definition at line 444 of file PowhegHooksST.cxx.

444 {
445 int eventtype = 1;
446 if (!infoPtr) return eventtype;
447 std::string comments = infoPtr->getEventComments();
448 if (comments.empty()) return eventtype;
449
450 std::istringstream iss(comments);
451 std::string line;
452 while (std::getline(iss, line)) {
453 if (line.compare(0, 5, "#rwgt") == 0) {
454 std::istringstream lss(line.substr(5));
455 int type = 0;
456 if (lss >> type) return type;
457 }
458 if (line.find("rad_type") != std::string::npos) {
459 int type = 0;
460 if (std::sscanf(line.c_str(), "# %d rad_type", &type) == 1) return type;
461 }
462 }
463 return eventtype;
464 }

◆ initAfterBeams()

bool Pythia8::PowhegHooksST::initAfterBeams ( )
inlineoverride

Initialize settings for the POWHEG resonance-veto strategy.

Reads the Pythia veto settings and prepares the selected scale source. In emscales mode 1, scales will be parsed from the LHE event comments.

Returns
true if initialization is successful, false otherwise.

Definition at line 110 of file PowhegHooksST.cxx.

110 {
111 // Initialize base PowhegHooks settings
112 PowhegHooks::initAfterBeams();
113
114 if (settingsPtr->isParm("POWHEG:pTcutoff")) {
115 m_pTcutoff = settingsPtr->parm("POWHEG:pTcutoff");
116 } else {
117 m_pTcutoff = m_pTcutoffSetting(settingsPtr);
118 }
119
120 m_vetoMode = settingsPtr->mode("POWHEG:veto");
121 m_vetoCount = settingsPtr->mode("POWHEG:vetoCount");
122 m_QEDvetoMode = settingsPtr->mode("POWHEG:QEDveto");
123
124 if (settingsPtr->isMode("POWHEG:single-top:emscales")) {
125 m_emscalesMode = settingsPtr->mode("POWHEG:single-top:emscales");
126 } else if (settingsPtr->isMode("POWHEG:emscales")) {
127 m_emscalesMode = settingsPtr->mode("POWHEG:emscales");
128 } else {
129 m_emscalesMode = m_emscalesSetting(settingsPtr);
130 }
131
132 if (m_emscalesMode == 1) {
133 std::cout << "PowhegHooksST: resonance veto scales taken from the POWHEG emission scales [emscales 1]\n";
134 m_readScales.clear();
135 } else {
136 std::cout << "PowhegHooksST: resonance veto scales reconstructed from the event record [emscales 0]\n";
137 m_vetoResScale.clear();
138 }
139 return true;
140 }

◆ pTpowhegFromRes()

double Pythia8::PowhegHooksST::pTpowhegFromRes ( const Event & event,
int iEmt,
int iRad,
int iRes )
inline

Compute the POWHEG transverse scale of a resonance splitting.

Parameters
eventEvent record containing the branching and resonance.
iEmtIndex of the post-branching emitter.
iRadIndex of the radiated parton.
iResIndex of the parent resonance.
Returns
The POWHEG transverse scale of the branching.

Definition at line 151 of file PowhegHooksST.cxx.

151 {
152 // Rad should be the radiated gluon for q->qg.
153 // For g->gg or g->qq it does not matter.
154 if (event[iEmt].id() == 21 || event[iRad].id() != 21)
155 std::swap(iEmt, iRad);
156
157 // Resonance, post branching emitter, and radiated parton
158 Vec4 pres(event[iRes].p());
159 Vec4 pemt(event[iEmt].p());
160 Vec4 prad(event[iRad].p());
161
162 // Energies in the resonance rest frame
163 double mRes = std::sqrt(pres * pres);
164 double Erad = prad * pres / mRes;
165 double Eemt = pemt * pres / mRes;
166 double scale;
167 if ((event[iEmt].id() != 21 && std::abs(event[iEmt].id()) > 6)
168 || (event[iRad].id() != 21 && std::abs(event[iRad].id()) > 6)) {
169 if (loggerPtr) loggerPtr->ABORT_MSG("pTpowheg should be called only over QCD splittings");
170 exit(1);
171 }
172
173 // Gluon (rad) emission from quark (emt) line: 2*(1 - cos theta)*E_g^2
174 if (std::abs(event[iEmt].id()) != std::abs(event[iRad].id())) {
175 scale = 2.0 * pemt * prad * Erad / Eemt;
176 } else {
177 // Gluon splitting: use a symmetrised scale
178 scale = 2.0 * pemt * prad * Eemt * Erad / (std::pow(Eemt, 2) + std::pow(Erad, 2));
179 }
180 return std::sqrt(scale);
181 }
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)

◆ readScale()

double Pythia8::PowhegHooksST::readScale ( int ires,
double fallback ) const
inlineprivate

Look up a POWHEG scale by original LHA resonance index.

Parameters
iresOriginal LHA resonance index.
fallbackValue returned when no scale was recorded for ires.
Returns
The recorded scale or fallback.

Definition at line 502 of file PowhegHooksST.cxx.

502 {
503 for (const auto &es : m_readScales) {
504 if (es.ires == ires) return es.scalup;
505 }
506 return fallback;
507 }

◆ resonanceKey()

std::vector< int > Pythia8::PowhegHooksST::resonanceKey ( int iRes,
const Event & event ) const
inlineprivate

Construct the stable signed-ID ancestry key for a resonance.

Only status-22 entries are included, so shower/recoil copies do not create a second identity for the same physical resonance history.

Parameters
iResIndex of the resonance or its shower copy.
eventPythia event record.
Returns
Signed-ID path from the resonance towards the hard-process root.

Definition at line 410 of file PowhegHooksST.cxx.

410 {
411 std::vector<int> key;
412 // Original resonance entries retain |status| = 22. Shower/recoil copies
413 // have other statuses; follow their mothers without counting them again.
414 for (int i = iRes; i > 0; i = event[i].mother1()) {
415 if (event[i].statusAbs() == 22) key.push_back(event[i].id());
416 }
417 return key;
418 }

◆ scaleResonance()

double Pythia8::PowhegHooksST::scaleResonance ( int iRes,
const Event & event )
inlineoverride

Reconstruct a resonance scale from the Pythia event record.

Used for emscales == 0. Top scales are computed from the b/gluon decay system; leptonic W/Z decays are unrestricted; coloured W/Z decays without a resolved gluon use pTcutoff. Other resonance types are unrestricted.

Parameters
iResIndex of the resonance particle.
eventEvent record containing the resonance decay.
Returns
The resonance veto scale, or 1e30 for an unrestricted resonance.

Definition at line 204 of file PowhegHooksST.cxx.

204 {
205 double veto_res_scale;
206 if (event[iRes].daughterList().size() > 3) {
207 if (loggerPtr) loggerPtr->ABORT_MSG("A resonance can have at most 3 children");
208 exit(1);
209 }
210
211 // For the time being, only from btilde events with tops
212 if (m_eventtype != 1) {
213 veto_res_scale = 1e30;
214 } else {
215 // Determine if W or Z boson is decaying leptonically or hadronically
216 if (std::abs(event[iRes].id()) == 23 || std::abs(event[iRes].id()) == 24) {
217 int iq = -1, iqb = -1, ig = -1;
218 for (int i = 0; i < int(event[iRes].daughterList().size()); i++) {
219 int iDau = event[iRes].daughterList()[i];
220 if (event[iDau].id() == 21) ig = iDau;
221 if (event[iDau].id() > 0 && event[iDau].id() < 6) iq = iDau;
222 if (event[iDau].id() > -6 && event[iDau].id() < 0) iqb = iDau;
223 }
224
225 // Leptonic decay
226 if (iq == -1 && iqb == -1) {
227 veto_res_scale = 1e30;
228 } else {
229 // Hadronic decay without gluon emission
230 if (ig == -1) {
231 veto_res_scale = m_pTcutoff;
232 } else {
233 double pTqg = (iq > 0) ? pTpowhegFromRes(event, iq, ig, iRes) : 1e30;
234 double pTqbg = (iqb > 0) ? pTpowhegFromRes(event, iqb, ig, iRes) : 1e30;
235 veto_res_scale = std::min(pTqg, pTqbg);
236 }
237 }
238 }
239 // Top decay
240 else if (std::abs(event[iRes].id()) == 6) {
241 // Now handle tops
242 if (event[iRes].daughterList().size() < 3) {
243 veto_res_scale = m_pTcutoff;
244 } else {
245 // Find top daughters
246 int iw = -1, ib = -1, ig = -1;
247 for (int i = 0; i < int(event[iRes].daughterList().size()); i++) {
248 int iDau = event[iRes].daughterList()[i];
249 if (std::abs(event[iDau].id()) == 24) iw = iDau;
250 if (std::abs(event[iDau].id()) == 5) ib = iDau;
251 if (std::abs(event[iDau].id()) == 21) ig = iDau;
252 }
253 if (iw < 0 || ib < 0 || ig < 0) {
254 if (loggerPtr) loggerPtr->ABORT_MSG("Top decay products not found");
255 exit(1);
256 }
257 veto_res_scale = pTpowhegFromRes(event, ib, ig, iRes);
258 }
259 } else {
260 // Other resonance: no veto
261 veto_res_scale = 1e30;
262 }
263 }
264 return veto_res_scale;
265 }
size_t size() const
Number of registered mappings.

◆ storeResonanceScale()

void Pythia8::PowhegHooksST::storeResonanceScale ( const std::vector< int > & key,
double scale )
inlineprivate

Store a scale for a resonance ancestry and reject ambiguity.

Parameters
keyStable resonance ancestry key.
scaleResonance veto scale.

Definition at line 426 of file PowhegHooksST.cxx.

426 {
427 // The s- and t-channel histories have unique resonance paths. Do not
428 // silently assign one scale to two indistinguishable sibling resonances.
429 if (!m_vetoResScale.emplace(key, scale).second) {
430 if (loggerPtr) loggerPtr->ABORT_MSG("Ambiguous resonance ancestry in POWHEG event");
431 exit(1);
432 }
433 }

Member Data Documentation

◆ m_debugSetting

Pythia8_UserHooks::UserSetting<bool> Pythia8::PowhegHooksST::m_debugSetting
private

Definition at line 375 of file PowhegHooksST.cxx.

◆ m_emscalesAltSetting

Pythia8_UserHooks::UserSetting<int> Pythia8::PowhegHooksST::m_emscalesAltSetting
private

Definition at line 374 of file PowhegHooksST.cxx.

◆ m_emscalesMode

int Pythia8::PowhegHooksST::m_emscalesMode
private

Definition at line 379 of file PowhegHooksST.cxx.

◆ m_emscalesSetting

Pythia8_UserHooks::UserSetting<int> Pythia8::PowhegHooksST::m_emscalesSetting
private

Definition at line 373 of file PowhegHooksST.cxx.

◆ m_eventtype

int Pythia8::PowhegHooksST::m_eventtype
private

Definition at line 377 of file PowhegHooksST.cxx.

◆ m_pTcutoff

double Pythia8::PowhegHooksST::m_pTcutoff
private

Definition at line 378 of file PowhegHooksST.cxx.

◆ m_pTcutoffSetting

Pythia8_UserHooks::UserSetting<double> Pythia8::PowhegHooksST::m_pTcutoffSetting
private

Definition at line 372 of file PowhegHooksST.cxx.

◆ m_QEDvetoMode

int Pythia8::PowhegHooksST::m_QEDvetoMode
private

Definition at line 381 of file PowhegHooksST.cxx.

◆ m_readScales

std::vector<EmissionScale> Pythia8::PowhegHooksST::m_readScales
private

Definition at line 398 of file PowhegHooksST.cxx.

◆ m_vetoCount

int Pythia8::PowhegHooksST::m_vetoCount
private

Definition at line 382 of file PowhegHooksST.cxx.

◆ m_vetoMode

int Pythia8::PowhegHooksST::m_vetoMode
private

Definition at line 380 of file PowhegHooksST.cxx.

◆ m_vetoResScale

std::map<std::vector<int>, double> Pythia8::PowhegHooksST::m_vetoResScale
private

Definition at line 385 of file PowhegHooksST.cxx.


The documentation for this class was generated from the following file: