cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
LPAIR.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2013-2024 Laurent Forthomme
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
20#include "CepGen/Event/Event.h"
25#include "CepGen/Physics/PDG.h"
30#include "CepGen/Utils/Math.h"
31
32using namespace cepgen;
33
35class LPAIR final : public cepgen::proc::Process {
36public:
37 explicit LPAIR(const ParametersList& params)
38 : proc::Process(params),
39 pair_(steer<ParticleProperties>("pair")),
40 symmetrise_(steer<bool>("symmetrise")),
41 randomise_charge_(steer<bool>("randomiseCharge")) {}
42 LPAIR(const LPAIR& oth)
43 : proc::Process(oth), pair_(oth.pair_), symmetrise_(oth.symmetrise_), randomise_charge_(oth.randomise_charge_) {}
44
45 proc::ProcessPtr clone() const override { return proc::ProcessPtr(new LPAIR(*this)); }
46
47 void addEventContent() override {
49 {Particle::IncomingBeam2, {PDG::proton}},
50 {Particle::Parton1, {PDG::photon}},
51 {Particle::Parton2, {PDG::photon}},
52 {Particle::OutgoingBeam1, {PDG::proton}},
53 {Particle::OutgoingBeam2, {PDG::proton}},
54 {Particle::CentralSystem, {+(spdgid_t)pair_.pdgid, -(spdgid_t)pair_.pdgid}}});
55 }
56
57 double computeWeight() override;
58
59 void prepareKinematics() override {
60 ml_ = pair_.mass;
61 ml2_ = ml_ * ml_;
62 charge_factor_ = std::pow(pair_.integerCharge() / 3., 2);
63 beams_mode_ = kinematics().incomingBeams().mode();
66 if (re_ = 0.5 * inverseSqrtS(); !utils::positive(re_))
67 throw CG_FATAL("LPAIR:prepareKinematics") << "Invalid centre of mass energy: sqrt(s)=" << sqrtS() << ".";
68 w12_ = mA2() - mB2(); // mass difference between the two incoming particles
69 ep1_ = re_ * (s() + w12_); // in centre of mass system (pp != ep)
70 ep2_ = re_ * (s() - w12_);
71 ss_ = s() + w12_;
72 if (const auto rl1 = ss_ * ss_ - 4. * mA2() * s(); rl1 >= 0.)
73 sl1_ = std::sqrt(rl1);
74 else
75 throw CG_FATAL("LPAIR:prepareKinematics") << "Invalid rl1 = " << rl1 << ".";
76 p_cm_ = 0.5 * sl1_ * inverseSqrtS();
77 mom_prefactor_ = 2. / sl1_;
78 p12_ = 0.5 * (s() - mA2() - mB2());
79 e1mp1_ = mA2() / (ep1_ + p_cm_);
80 { // definition of boost-to-lab boost variables
81 const Momentum cm = pA() + pB();
82 gamma_cm_ = cm.energy() * inverseSqrtS();
83 beta_gamma_cm_ = cm.pz() * inverseSqrtS();
84 CG_DEBUG_LOOP("LPAIR:prepareKinematics")
85 << "sqrt(s)=" << sqrtS() << " GeV, initial two-proton system: " << cm << "\n\t"
86 << "gamma=" << gamma_cm_ << ", beta*gamma=" << beta_gamma_cm_;
87 }
88
89 formfac1_ = FormFactorsFactory::get().build(kinematics().incomingBeams().positive().formFactors());
90 formfac2_ = FormFactorsFactory::get().build(kinematics().incomingBeams().negative().formFactors());
91 strfun_ = StructureFunctionsFactory::get().build(kinematics().incomingBeams().structureFunctions());
92 is_strfun_sy_ = strfun_->name() == "SuriYennie";
93
94 //--- first define the squared mass range for the diphoton/dilepton system
95 const auto w_limits = kinematics()
96 .cuts()
97 .central.mass_sum.compute([](double ext) { return std::pow(ext, 2); })
98 .truncate(Limits{4. * ml2_, s()});
99 CG_DEBUG_LOOP("LPAIR:prepareKinematics") << "w limits = " << w_limits << "\n\t"
100 << "wmax/wmin = " << w_limits.max() / w_limits.min();
101
102 //--- variables mapping
103 defineVariable(m_u_t1_, Mapping::linear, {0., 1.}, "u_t1");
104 defineVariable(m_u_t2_, Mapping::linear, {0., 1.}, "u_t2");
105 defineVariable(m_u_s2_, Mapping::linear, {0., 1.}, "u_s2");
106 defineVariable(m_w4_, Mapping::power_law, w_limits, "w4");
107 defineVariable(m_theta4_, Mapping::linear, {0., M_PI}, "theta4");
108 defineVariable(m_phi6_cm_, Mapping::linear, {0., 2. * M_PI}, "phi6cm");
109 defineVariable(m_x6_, Mapping::linear, {-1., 1.}, "x6");
110
111 mX2() = mA2();
112 mY2() = mB2();
113 const auto mx_range = [&](double m_in) {
114 return kinematics()
115 .cuts()
116 .remnants.mx.truncate(Limits{mp_ + PDG::get().mass(PDG::piPlus), sqrtS() - m_in - 2. * pair_.mass})
117 .compute([](double m) { return m * m; });
118 };
119 if (beams_mode_ != mode::Kinematics::ElasticElastic) // first outgoing beam particle or remnant mass
120 defineVariable(mX2(), Mapping::power_law, mx_range(mA()), "MX2");
121 if (beams_mode_ == mode::Kinematics::InelasticInelastic) // second outgoing beam particle or remnant mass
122 defineVariable(mY2(), Mapping::power_law, mx_range(mB()), "MY2");
123 if (symmetrise_ &&
124 (beams_mode_ == mode::Kinematics::InelasticElastic || beams_mode_ == mode::Kinematics::ElasticInelastic))
125 CG_INFO("LPAIR:prepareKinematics")
126 << "Single dissociation kinematics mode was enabled with symmetrisation of the outgoing system.\n\t"
127 "The generator-level cross section will be doubled, and beam particles, incoming partons, and central "
128 "system will be mirrored in z.";
129 }
130
131 void fillKinematics() override {
132 // boost of the incoming beams
133 pA() = Momentum(0., 0., +p_cm_, ep1_).betaGammaBoost(gamma_cm_, beta_gamma_cm_);
134 pB() = Momentum(0., 0., -p_cm_, ep2_).betaGammaBoost(gamma_cm_, beta_gamma_cm_);
135 // boost of the outgoing beams
136 pX().setMass(mX()).betaGammaBoost(gamma_cm_, beta_gamma_cm_);
137 pY().setMass(mY()).betaGammaBoost(gamma_cm_, beta_gamma_cm_);
138 // incoming partons
139 q1() = pA() - pX();
140 q2() = pB() - pY();
141
142 // randomly rotate all particles
143 const short rany = rnd_gen_->uniformInt(0, 1) == 1 ? 1 : -1;
144 const double ranphi = rnd_gen_->uniform(0., 2. * M_PI);
145 for (auto* mom : {&q1(), &q2(), &pX(), &pY(), &pc(0), &pc(1)})
146 mom->rotatePhi(ranphi, rany);
147 if ((symmetrise_ && rnd_gen_->uniformInt(0, 1) == 1) ||
148 beams_mode_ == mode::Kinematics::ElasticInelastic) { // mirror X/Y and dilepton systems if needed
149 std::swap(pX(), pY());
150 std::swap(q1(), q2());
151 std::swap(pc(0), pc(1));
152 for (auto* mom : {&q1(), &q2(), &pX(), &pY(), &pc(0), &pc(1)})
153 mom->mirrorZ();
154 }
155 // first outgoing beam
156 event()
158 .setStatus(kinematics().incomingBeams().positive().elastic() ? Particle::Status::FinalState
159 : Particle::Status::Unfragmented);
160 // second outgoing beam
161 event()
163 .setStatus(kinematics().incomingBeams().negative().elastic() ? Particle::Status::FinalState
164 : Particle::Status::Unfragmented);
165
166 // central system
167 const auto ransign = rnd_gen_->uniformInt(0, 1) == 1;
168 if (randomise_charge_) { // randomise the charge of outgoing system
169 event()[Particle::CentralSystem][0].get().setAntiparticle(ransign);
170 event()[Particle::CentralSystem][1].get().setAntiparticle(!ransign);
171 }
172 event()[Particle::CentralSystem][0].get().setStatus(Particle::Status::FinalState);
173 event()[Particle::CentralSystem][1].get().setStatus(Particle::Status::FinalState);
174 }
175
177 auto desc = proc::Process::description();
178 desc.setDescription("γγ → l⁺l¯ (LPAIR)");
179 desc.addAs<int, pdgid_t>("pair", PDG::muon).setDescription("Lepton pair considered");
180 desc.add<bool>("symmetrise", false).setDescription("Symmetrise along z the central system?");
181 desc.add<bool>("randomiseCharge", true).setDescription("randomise the charges of the two central fermions?");
182 return desc;
183 }
184
185private:
186 static constexpr double constb_ = 0.5 * M_1_PI * M_1_PI * M_1_PI;
188 bool orient();
195 double periPP() const {
196 const auto qdq = 4. * ml2_ - m_w4_;
197 const auto m_em =
198 Matrix{{(bb_ * (q2dq_ - gamma4_ - qdq * (t1() + t2() + 2. * ml2_)) -
199 2. * (t1() + 2. * ml2_) * (t2() + 2. * ml2_) * q2dq_) *
200 t1() * t2(),
201 2. * (-bb_ * (deltas1_[1] + gamma6_) - 2. * (t1() + 2. * ml2_) * (sa2_ * q2dq_ + alpha6_ * alpha6_)) *
202 t1()},
203 {2. * (-bb_ * (deltas2_[1] + gamma5_) - 2. * (t2() + 2. * ml2_) * (sa1_ * q2dq_ + alpha5_ * alpha5_)) *
204 t2(),
205 8. * (bb_ * (delta_ * delta_ - gram_) -
206 std::pow(epsilon_ - delta_ * (qdq + 0.5 * (m_w4_ - t1() - t2())), 2) - sa1_ * alpha6_ * alpha6_ -
207 sa2_ * alpha5_ * alpha5_ - sa1_ * sa2_ * q2dq_)}} *
208 std::pow(4. / t1() / t2() / bb_, 2);
209
210 // compute the electric/magnetic form factors for the two considered parton momenta transfers
211 const auto compute_form_factors =
212 [this](formfac::Parameterisation& formfac, bool elastic, double q2, double mi2, double mx2) -> Vector {
213 if (elastic) { // trivial case for elastic photon emission
214 const auto ff = formfac(q2);
215 return Vector{ff.FM, ff.FE};
216 }
217 if (!strfun_)
218 throw CG_FATAL("LPAIR:peripp")
219 << "Inelastic proton form factors computation requires a structure functions definition!";
220 const double xbj = utils::xBj(q2, mi2, mx2);
221 if (is_strfun_sy_) // this one requires its own object to deal with FM
222 return Vector{strfun_->FM(xbj, q2), strfun_->F2(xbj, q2) * xbj * mp_ / q2};
223 return Vector{-2. * strfun_->F1(xbj, q2) / q2, strfun_->F2(xbj, q2) * xbj / q2};
224 };
225 const auto u1 = beams_mode_ == mode::Kinematics::ElasticInelastic
226 ? compute_form_factors(*formfac2_, false, -t1(), mA2(), mX2())
227 : compute_form_factors(
228 *formfac1_, kinematics().incomingBeams().positive().elastic(), -t1(), mA2(), mX2()),
229 u2 = beams_mode_ == mode::Kinematics::ElasticInelastic
230 ? compute_form_factors(*formfac1_, true, -t2(), mB2(), mY2())
231 : compute_form_factors(
232 *formfac2_, kinematics().incomingBeams().negative().elastic(), -t2(), mB2(), mY2());
233 const auto peripp = (u1.transposed() * m_em * u2)(0);
234 CG_DEBUG_LOOP("LPAIR:peripp") << "bb = " << bb_ << ", qqq = " << q2dq_ << ", qdq = " << qdq << "\n\t"
235 << "e-m matrix=\n"
236 << m_em << "\n\t"
237 << "u1-2: " << u1 << ", " << u2 << " -> PeriPP = " << peripp << ".";
238 return peripp;
239 }
243 double pickin();
244
245 const ParticleProperties pair_;
246 const bool symmetrise_;
247 const bool randomise_charge_;
248
250 // variables computed at phase space definition
251 double ml_{0.};
252 double ml2_{0.};
253 double charge_factor_{0.};
254 mode::Kinematics beams_mode_{mode::Kinematics::invalid};
255 double re_{0.};
256 double ep1_{0.};
257 double ep2_{0.};
258 double w12_{0.};
259 double ss_{0.};
260 double p12_{0.};
261 double sl1_{0.};
262 double e1mp1_{0.};
263 double p_cm_{0.}, mom_prefactor_{0.};
264 double gamma_cm_{0.}, beta_gamma_cm_{0.};
265
266 std::unique_ptr<formfac::Parameterisation> formfac1_, formfac2_;
267 std::unique_ptr<strfun::Parameterisation> strfun_;
268 bool is_strfun_sy_{false};
269
270 // mapped variables
271 double m_u_t1_{0.};
272 double m_u_t2_{0.};
273 double m_u_s2_{0.};
274 // yy4 = \f$\cos\left(\pi x_3\right)\f$
275 double m_w4_{0.};
276 double m_theta4_{0.};
277 double m_phi6_cm_{0.};
286 double m_x6_{0.};
287
289 // variables computed for each phase space point computation
290 double s1_{0.}, s2_{0.};
291 double sa1_{0.}, sa2_{0.};
292 double p1k2_{0.}, p2k1_{0.};
293 double ec4_{0.};
294 double pc4_{0.};
295 double pt4_{0.};
296 double mc4_{0.};
297 double cos_theta4_{0.};
298 double sin_theta4_{0.};
299 double q2dq_{0.};
300 double epsilon_{0.};
301 double alpha4_{0.}, beta4_{0.}, gamma4_{0.};
302 double alpha5_{0.}, gamma5_{0.}, alpha6_{0.}, gamma6_{0.};
303 double bb_{0.};
304 double gram_{0.};
305 double dd5_{0.};
306 std::array<double, 2> deltas1_, deltas2_;
310 double delta_{0.};
311 double eph1_{0.}, eph2_{0.};
312};
313
314//---------------------------------------------------------------------------------------------
315
316double LPAIR::pickin() {
324 const auto map_expo = [](double expo, const Limits& lim) {
325 const double y = lim.max() / lim.min(), out = lim.min() * std::pow(y, expo);
326 return std::make_pair(out, out * std::log(y));
327 };
328 const auto [s2_val, s2_width] =
329 map_expo(m_u_s2_, Limits{mc4_ + mY(), sqrtS() - mX()}.compute([](double lim) { return lim * lim; }));
330 s2_ = s2_val;
331 if (s2_width <= 0.)
332 return 0.;
333
334 const double sp = s() + mX2() - s2_, d3 = s2_ - mB2();
335 const double rl2 = sp * sp - 4. * s() * mX2(); // lambda(s, m3**2, sigma)
336 if (!utils::positive(rl2)) {
337 CG_WARNING("LPAIR:pickin") << "Invalid rl2 = " << rl2 << ".";
338 return 0.;
339 }
340 const auto w31 = mX2() - mA2();
341 // definition from eq. (A.4) and (A.5) in [1]
342 auto t1_max = mA2() + mX2() - 0.5 * (ss_ * sp + sl1_ * std::sqrt(rl2)) / s(),
343 t1_min = (w31 * d3 + (d3 - w31) * (d3 * mA2() - w31 * mB2()) / s()) / t1_max;
344 t1_max = std::max(t1_max, -kinematics().cuts().initial.q2.at(0).max());
345 t1_min = std::min(t1_min, -kinematics().cuts().initial.q2.at(0).min());
346 const auto t1_limits = Limits{t1_min, t1_max};
347 CG_DEBUG_LOOP("LPAIR:pickin") << "t1 in range: " << t1_limits << ".";
348 const auto [t1_val, t1_width] = map_expo(m_u_t1_, t1_limits); // definition of the first photon propagator (t1 < 0)
349 t1() = t1_val;
350 if (t1_width >= 0.)
351 return 0.;
352
353 const auto r1 = s2_ - t1() + mB2(), r2 = s2_ - m_w4_ + mY2(),
354 rl4 = (r1 * r1 - 4. * s2_ * mB2()) * (r2 * r2 - 4. * s2_ * mY2());
355 if (!utils::positive(rl4)) {
356 CG_WARNING("LPAIR:pickin") << "Invalid rl4 = " << rl4 << ".";
357 return 0.;
358 }
359
360 const auto d4 = m_w4_ - t1();
361 const auto w52 = mY2() - mB2();
362 // t2max, t2min definitions from eq. (A.12) and (A.13) in [1]
363 auto t2_max = mB2() + mY2() - 0.5 * (r1 * r2 + std::sqrt(rl4)) / s2_,
364 t2_min = (w52 * d4 + (d4 - w52) * (d4 * mB2() - w52 * t1()) / s2_) / t2_max;
365 t2_max = std::max(t2_max, -kinematics().cuts().initial.q2.at(1).max());
366 t2_min = std::min(t2_min, -kinematics().cuts().initial.q2.at(1).min());
367 const auto t2_limits = Limits{t2_min, t2_max};
368 CG_DEBUG_LOOP("LPAIR:pickin") << "t2 in range: " << t2_limits << ".";
369 const auto [t2_val, t2_width] = map_expo(m_u_t2_, t2_limits); // definition of the second photon propagator (t2 < 0)
370 t2() = t2_val;
371 if (t2_width >= 0.)
372 return 0.;
373
374 const auto r3 = m_w4_ - t1() - t2();
375 if (gamma4_ = t1() * t2() - 0.25 * r3 * r3; gamma4_ >= 0.) {
376 CG_WARNING("LPAIR:pickin") << "gamma4 = " << gamma4_ << " >= 0";
377 return 0.;
378 }
379
380 const auto compute_deltas = [this](double var,
381 short sign,
382 double t_1,
383 double mi2_1,
384 double mf2_1,
385 double t_2,
386 double mi2_2,
387 double mf2_2,
388 std::array<double, 2>& deltas) -> std::tuple<double, double> {
389 const auto del1 = t_1 - mi2_2, del2 = t_1 - mi2_1 - mf2_1, del3 = m_w4_ - mf2_2;
390 const auto m2diff = mf2_1 - mi2_1;
391 const auto compute_sa = [](double t, double mi2, double mf2) {
392 return mi2 * t - 0.25 * std::pow(mf2 - mi2 - t, 2);
393 };
394 const auto sa_1 = compute_sa(t_1, mi2_1, mf2_1), sa_2 = compute_sa(t_2, mi2_2, mf2_2);
395 const auto compute_boundaries = [](double sb, double sd, double se) {
396 std::pair<double, double> out;
397 if (std::fabs((sb - sd) / sd) >= 1.) {
398 out.first = sb - sd;
399 out.second = se / out.first;
400 } else {
401 out.second = sb + sd;
402 out.first = se / out.second;
403 }
404 return out;
405 };
406 double var_pm = 0., var_mp = 0., var_min = 0., var_max = 0.;
407 if (mi2_1 == 0.) {
408 var_max =
409 (s() * (t_1 * (s() + del1 - mf2_1) - mi2_2 * mf2_1) + mi2_2 * mf2_1 * (mf2_1 - del1)) / ((s() + w12_) * del2);
410 deltas[0] = -0.25 * (var_max - var) * ss_ * del2;
411 } else {
412 const auto inv_w1 = 1. / mi2_1;
413 const auto sb = mf2_1 + 0.5 * (s() * (t_1 - m2diff) + w12_ * del2) * inv_w1,
414 sd = sl1_ * std::sqrt(-sa_1) * inv_w1,
415 se = (s() * (t_1 * (s() + del2 - mi2_2) - mi2_2 * m2diff) + mf2_1 * (mi2_2 * mf2_1 + w12_ * del1)) *
416 inv_w1;
417 std::tie(var_pm, var_max) = compute_boundaries(sb, sd, se);
418 deltas[0] = -0.25 * (var_max - var) * (var_pm - var) * mi2_1;
419 }
420 {
421 const auto inv_t = 1. / t_2;
422 const auto sb = mi2_2 + t_1 - 0.5 * (m_w4_ - t_1 - t_2) * (mf2_2 - mi2_2 - t_2) * inv_t,
423 sd = 2. * sign * std::sqrt(sa_2 * gamma4_) * inv_t,
424 se = del3 * del1 + (del3 - del1) * (del3 * mi2_2 - del1 * mf2_2) * inv_t;
425 std::tie(var_mp, var_min) = compute_boundaries(sb, sd, se);
426 deltas[1] = -0.25 * (var_min - var) * (var_mp - var) * t_2;
427 }
428 return std::make_tuple(sa_1, 0.5 * (var - t_1 - mi2_2));
429 };
430
431 if (std::tie(sa1_, p2k1_) = compute_deltas(s2_, -1, t1(), mA2(), mX2(), t2(), mB2(), mY2(), deltas1_); sa1_ >= 0.) {
432 CG_WARNING("LPAIR:pickin") << "sa1_ = " << sa1_ << " >= 0";
433 return 0.;
434 }
435
436 const auto dd = deltas1_[0] * deltas1_[1];
437 if (!utils::positive(dd)) {
438 CG_WARNING("LPAIR:pickin") << "Invalid dd = " << dd << ".";
439 return 0.;
440 }
441
442 const auto ap = s2_ * t1() - 0.25 * std::pow(s2_ + t1() - mB2(), 2);
443 if (utils::positive(ap)) {
444 CG_WARNING("LPAIR:pickin") << "ap = " << ap << " should be strictly negative.";
445 return 0.;
446 }
447 const auto inv_ap = 1. / ap;
448 const auto st = s2_ - t1() - mB2();
449 delta_ = 0.5 *
450 ((mB2() * r3 + 0.5 * (w52 - t2()) * st) * (p12_ * t1() - 0.25 * (t1() - w31) * st) -
451 std::cos(m_theta4_) * st * std::sqrt(dd)) *
452 inv_ap;
453
454 s1_ = t2() + mA2() + 2. * (p12_ * r3 - 2. * delta_) / st;
455
456 const auto jacobian = s2_width * t1_width * t2_width * 0.125 * 0.5 / (sl1_ * std::sqrt(-ap));
457 if (!utils::positive(jacobian)) {
458 CG_WARNING("LPAIR:pickin") << "Null Jacobian.\n\t"
459 << "ds2=" << s2_width << ", dt1=" << t1_width << ", dt2=" << t2_width << ".";
460 return 0.;
461 }
462 CG_DEBUG_LOOP("LPAIR:pickin") << "s1=" << s1_ << ", s2=" << s2_ << ", ds2=" << s2_width << ", t1=" << t1()
463 << ", dt1=" << t1_width << ", t2=" << t2() << ", dt2=" << t2_width << "\n\t"
464 << "Jacobian=" << std::scientific << jacobian
465 << ", LPAIR original dj=" << (jacobian * M_PI * M_PI * 2.) << std::fixed;
466
467 gram_ = std::pow(std::sin(m_theta4_), 2) * dd * inv_ap;
468
469 if (std::tie(sa2_, p1k2_) = compute_deltas(s1_, +1, t2(), mB2(), mY2(), t1(), mA2(), mX2(), deltas2_); sa2_ >= 0.) {
470 CG_WARNING("LPAIR:pickin") << "sa2_ = " << sa2_ << " >= 0";
471 return 0.;
472 }
473 CG_DEBUG_LOOP("LPAIR:pickin") << std::scientific << "deltas = " << deltas1_ << ", " << deltas2_ << std::fixed;
474
475 if (dd5_ = deltas1_[0] + deltas2_[0] +
476 ((p12_ * (t1() - w31) * 0.5 - mA2() * p2k1_) * (p2k1_ * (t2() - w52) - mB2() * r3) -
477 delta_ * (2. * p12_ * p2k1_ - mB2() * (t1() - w31))) /
478 p2k1_;
479 !utils::positive(dd5_)) {
480 CG_WARNING("LPAIR:pickin") << "Invalid dd5=" << dd5_ << ", with all deltas=" << deltas1_ << ", " << deltas2_ << ".";
481 return 0.;
482 }
483
484 return jacobian;
485}
486
487//---------------------------------------------------------------------------------------------
488
489bool LPAIR::orient() {
490 eph1_ = re_ * (s2_ - mX2() + w12_); // de3 in original LPAIR
491 eph2_ = re_ * (s1_ - mY2() - w12_); // de5 un original LPAIR
492
493 //----- central two-photon/lepton system
494 if (ec4_ = eph1_ + eph2_; ec4_ < mc4_) {
495 CG_WARNING("LPAIR:orient") << "ec4_ = " << ec4_ << " < mc4_ = " << mc4_ << "==> photon energies: " << eph1_ << ", "
496 << eph2_ << ".";
497 return false;
498 }
499 if (pc4_ = utils::fastSqrtSqDiff(ec4_, mc4_); pc4_ == 0.) { // protons' momenta are not along the z-axis
500 CG_WARNING("LPAIR:orient") << "pzc4 is null and should not be...";
501 return false;
502 }
503
504 CG_DEBUG_LOOP("LPAIR:orient") << "Central system's energy: E4 = " << ec4_ << "\n\t"
505 << " momentum: p4 = " << pc4_ << "\n\t"
506 << " invariant mass: m4 = " << mc4_ << ".";
507
508 pt4_ = mom_prefactor_ * std::sqrt(dd5_);
509 if (sin_theta4_ = pt4_ / pc4_; !Limits{-1., 1.}.contains(sin_theta4_)) {
510 CG_WARNING("LPAIR:orient") << "Invalid sin(theta4): " << sin_theta4_ << ".";
511 return false;
512 }
513 const auto p14 = +0.5 * (s1_ + t1() - t2() - mX2());
514 cos_theta4_ = std::sqrt(1. - sin_theta4_ * sin_theta4_) * (ep1_ * ec4_ < p14 ? -1. : 1.);
515 const auto sin2_theta4 = sin_theta4_ * sin_theta4_;
516 alpha4_ = 1. - cos_theta4_;
517 beta4_ = 1. + cos_theta4_;
518 if (cos_theta4_ < 0.)
519 beta4_ = sin2_theta4 / alpha4_;
520 else
521 alpha4_ = sin2_theta4 / beta4_;
522
523 CG_DEBUG_LOOP("LPAIR:orient") << "cos(theta4) = " << cos_theta4_ << "\t"
524 << "sin(theta4) = " << sin_theta4_ << "\n\t"
525 << "alpha4 = " << alpha4_ << ", beta4 = " << beta4_;
526
527 //----- outgoing beam states
528 const auto rr = mom_prefactor_ * std::sqrt(-gram_) / pt4_;
529
530 //--- beam 1 -> 3
531 const auto ep3 = ep1_ - eph1_, pp3 = utils::fastSqrtSqDiff(ep3, mX()), pt3 = mom_prefactor_ * std::sqrt(deltas1_[0]);
532 if (pt3 > pp3) {
533 CG_DEBUG("LPAIR:orient") << "Invalid momentum for outgoing beam 1: pt=" << pt3 << ", p=" << pp3 << ".";
534 return false;
535 }
536 if (pt3 < rr) {
537 CG_DEBUG("LPAIR:orient") << "Invalid momentum balance for outgoing beam 1.";
538 return false;
539 }
540 pX() = Momentum::fromPThetaPhiE(pp3, -std::asin(pt3 / pp3), std::asin(-rr / pt3), ep3);
541 CG_DEBUG_LOOP("LPAIR:orient") << "Positive-z beam state:\n\t" << std::scientific << "energy: E3 = " << ep3
542 << ", pt3 = " << pt3 << "\n\t"
543 << "momentum = " << pX() << ".";
544
545 //--- beam 2 -> 5
546 const auto ep5 = ep2_ - eph2_, pp5 = utils::fastSqrtSqDiff(ep5, mY()), pt5 = mom_prefactor_ * std::sqrt(deltas2_[0]);
547 if (pt5 > pp5) {
548 CG_DEBUG("LPAIR:orient") << "Invalid momentum for outgoing beam 2: pt=" << pt5 << ", p=" << pp5 << ".";
549 return false;
550 }
551 if (pt5 < rr) {
552 CG_DEBUG("LPAIR:orient") << "Invalid momentum balance for outgoing beam 2.";
553 return false;
554 }
555 pY() = Momentum::fromPThetaPhiE(pp5, M_PI + std::asin(pt5 / pp5), std::asin(+rr / pt5), ep5);
556 CG_DEBUG_LOOP("LPAIR:orient") << "Negative-z beam state:\n\t" << std::scientific << "energy: E5 = " << ep5
557 << ", pt5 = " << pt5 << "\n\t"
558 << "momentum = " << pY() << ".";
559
560 // x-axis mirroring
561 if (const double a1 = pX().px() - pY().px();
562 std::fabs(pt4_ + pX().px() + pY().px()) >= std::fabs(std::fabs(a1) - pt4_)) {
563 CG_DEBUG_LOOP("LPAIR:orient") << "|pt4+pt3*cos(phi3)+pt5*cos(phi5)| < | |a1|-pt4 | ; pt4 = " << pt4_ << ".";
564 if (a1 < 0.)
565 pY().mirrorX();
566 else
567 pX().mirrorX();
568 }
569 return true;
570}
571
572//---------------------------------------------------------------------------------------------
573
575 if (mc4_ = std::sqrt(m_w4_); !utils::positive(mc4_)) // compute the two-photon energy for this point
576 return 0.;
577
578 CG_DEBUG_LOOP("LPAIR:weight") << "Masses dump:\n\t"
579 << "m1 = " << mA() << ", m2 = " << mB() << ", m3 = " << mX() << ", m4 = " << mc4_
580 << ", m5 = " << mY() << ".\n\t"
581 << "w1 = " << mA2() << ", w2 = " << mB2() << ", w3 = " << mX2() << ", w4 = " << m_w4_
582 << ", w5 = " << mY2() << ".";
583
584 auto jacobian = pickin();
585 if (!utils::positive(jacobian)) {
586 CG_DEBUG_LOOP("LPAIR:weight") << "Pickin failed.";
587 return 0.;
588 }
589 if (!orient()) {
590 CG_DEBUG_LOOP("LPAIR:weight") << "Orient failed.";
591 return 0.;
592 }
593
594 const double ecm6 = m_w4_ / (2. * mc4_), pp6cm = utils::fastSqrtSqDiff(ecm6, ml_);
595
596 jacobian *= pp6cm / mc4_;
597
598 // Let the most obscure part of this code begin...
599
600 const double e3mp3 = mX2() / (pX().energy() + pX().p());
601 const double theta_x = pX().theta(), al3 = std::pow(std::sin(theta_x), 2) / (1. + theta_x);
602
603 // 2-photon system kinematics ?!
604 const double eg = (m_w4_ + t1() - t2()) / (2. * mc4_);
605
606 const double gamma4 = ec4_ / mc4_;
607 const Momentum pg(-pX().px() * cos_theta4_ - (pX().p() * al3 + e3mp3 - e1mp1_ + eph1_) * sin_theta4_,
608 -pX().py(),
609 -gamma4 * pX().px() * sin_theta4_ + (pX().p() * al3 + e3mp3 - e1mp1_) * gamma4 * cos_theta4_ +
610 mc4_ * eph1_ / (ec4_ + pc4_) - gamma4 * eph1_ * alpha4_);
611
612 const auto pt_gam = pg.pt(), p_gam = std::max(std::sqrt(eg * eg - t1()), pg.p() > 0.9 * pt_gam ? pg.p() : -999.);
613 const auto cos_phi_gam = pg.px() / pt_gam, sin_phi_gam = pg.py() / pt_gam, sin_theta_gam = pt_gam / p_gam;
614 const short theta_sign = pg.pz() > 0. ? 1 : -1;
615 const auto cos_theta_gam = theta_sign * std::sqrt(1. - sin_theta_gam * sin_theta_gam);
616
617 const double amap = 0.5 * (m_w4_ - t1() - t2()),
618 bmap = 0.5 * std::sqrt((std::pow(m_w4_ - t1() - t2(), 2) - 4. * t1() * t2()) * (1. - 4. * ml2_ / m_w4_)),
619 ymap = (amap + bmap) / (amap - bmap), beta = std::pow(ymap, m_x6_);
620
621 // 3D rotation of the first outgoing lepton wrt the CM system
622 const auto cos_theta6cm = Limits{-1., 1.}.trim(amap / bmap * (beta - 1.) / (beta + 1.)),
623 cos2_theta6cm = cos_theta6cm * cos_theta6cm, sin2_theta6cm = 1. - cos2_theta6cm,
624 theta6cm = M_PI - std::acos(cos_theta6cm);
625
626 // match the Jacobian
627 jacobian *= (amap + bmap * cos_theta6cm);
628 jacobian *= (amap - bmap * cos_theta6cm);
629 jacobian *= 0.5 * std::log(ymap) / amap / bmap;
630 if (symmetrise_ &&
631 (beams_mode_ == mode::Kinematics::ElasticInelastic || beams_mode_ == mode::Kinematics::InelasticElastic))
632 jacobian *= 1.;
633 else
634 jacobian *= 0.5;
635
636 const auto p6cm = Momentum::fromPThetaPhiE(pp6cm, theta6cm, m_phi6_cm_); // 1st outgoing lepton 3-mom. in CoM system
637
638 const double h1 = p6cm.pz() * sin_theta_gam + p6cm.px() * cos_theta_gam;
639 const double pc6z = p6cm.pz() * cos_theta_gam - p6cm.px() * sin_theta_gam;
640 const double pc6x = h1 * cos_phi_gam - p6cm.py() * sin_phi_gam;
641 const double qcx = 2. * pc6x, qcz = 2. * pc6z;
642
643 const double el6 = (ec4_ * ecm6 + pc4_ * pc6z) / mc4_;
644 const double h2 = (ec4_ * pc6z + pc4_ * ecm6) / mc4_;
645
646 // outgoing leptons' kinematics (in the two-photon CM frame)
647 const auto pc4 = Momentum::fromPThetaPhiE(pc4_, std::acos(cos_theta4_), 0., ec4_);
648 pc(0) = Momentum(+pc6x * cos_theta4_ + h2 * sin_theta4_,
649 p6cm.py() * cos_phi_gam + h1 * sin_phi_gam,
650 -pc6x * sin_theta4_ + h2 * cos_theta4_,
651 el6);
652 pc(1) = pc4 - pc(0);
653 CG_DEBUG_LOOP("LPAIR") << "Outgoing kinematics\n\t"
654 << " first outgoing lepton: p = " << pc(0) << "\n\t"
655 << "second outgoing lepton: p = " << pc(1) << ".";
656
657 bb_ = t1() * t2() + (m_w4_ * sin2_theta6cm + 4. * ml2_ * cos2_theta6cm) * p_gam * p_gam;
658 q2dq_ = std::pow(eg * (2. * ecm6 - mc4_) - 2. * p_gam * p6cm.pz(), 2);
659
660 const auto hq = ec4_ * qcz / mc4_;
661 const auto qve = Momentum::fromPxPyPzE(+qcx * cos_theta4_ + hq * sin_theta4_,
662 2. * pc(0).py(),
663 -qcx * sin_theta4_ + hq * cos_theta4_,
664 +qcz * pc4_ / mc4_);
665
666 for (size_t i = 0; i < 2; ++i) // boost outgoing leptons' kinematics into lab frame
667 pc(i).betaGammaBoost(gamma_cm_, beta_gamma_cm_);
668 if (!kinematics().cuts().central.contain(event()(Particle::CentralSystem))) // cuts on outgoing leptons
669 return 0.;
670
671 { // preparation for the periPP call
672 const auto compute_coeffs =
673 [&qve](double e_in, double m_in, const Momentum& pout, double ene_pho, double pcm, double& gamma)
674 -> std::tuple<double, double, double, double, double, double, double> {
675 const auto phi_out = pout.phi(), cos_phi_out = std::cos(phi_out), sin_phi_out = std::sin(phi_out);
676 const auto e2_in = e_in * e_in, m2_in = m_in * m_in, pt_out = pout.pt();
677 const auto c1 = pt_out * (qve.px() * sin_phi_out - qve.py() * cos_phi_out),
678 c2 = pt_out * (qve.pz() * e_in - qve.energy() * pcm),
679 c3 = ((pout.mass2() - m2_in) * e2_in + 2. * m2_in * ene_pho * e_in - m2_in * ene_pho * ene_pho +
680 pt_out * pt_out * e2_in) /
681 (pout.pz() * e2_in + pout.energy() * pcm);
682 const auto r2 = c2 * sin_phi_out + c3 * qve.py(), r3 = -c2 * cos_phi_out - c3 * qve.px();
683 gamma = m2_in * c1 * c1 + r2 * r2 + r3 * r3;
684 return std::make_tuple(cos_phi_out, sin_phi_out, c1, c2, c3, r2, r3);
685 };
686 const auto [cos_phi3, sin_phi3, c1, c2, c3, r12, r13] = compute_coeffs(ep1_, mA(), pX(), eph1_, +p_cm_, gamma5_);
687 const auto [cos_phi5, sin_phi5, b1, b2, b3, r22, r23] = compute_coeffs(ep2_, mB(), pY(), eph2_, -p_cm_, gamma6_);
688 const auto pt3 = pX().pt(), pt5 = pY().pt();
689 alpha5_ = -(qve.px() * cos_phi3 + qve.py() * sin_phi3) * pt3 * p1k2_ -
690 (ep1_ * qve.energy() - p_cm_ * qve.pz()) * (cos_phi3 * cos_phi5 + sin_phi3 * sin_phi5) * pt3 * pt5 +
691 (eph2_ * qve.pz() + qve.energy() * (p_cm_ + pY().pz())) * c3;
692 alpha6_ = -(qve.px() * cos_phi5 + qve.py() * sin_phi5) * pt5 * p2k1_ -
693 (ep2_ * qve.energy() + p_cm_ * qve.pz()) * (cos_phi3 * cos_phi5 + sin_phi3 * sin_phi5) * pt3 * pt5 +
694 (eph1_ * qve.pz() - qve.energy() * (p_cm_ - pY().pz())) * b3;
695 epsilon_ = p12_ * c1 * b1 + r12 * r22 + r13 * r23;
696 }
697 const auto peripp = periPP(); // compute the structure functions factors
698 if (!utils::positive(peripp))
699 return 0.;
700
701 const auto alpha_prod = alphaEM(std::sqrt(-t1())) * alphaEM(std::sqrt(-t2()));
702 jacobian *= constb_ * charge_factor_ * alpha_prod * alpha_prod / s();
703
704 CG_DEBUG_LOOP("LPAIR:f") << "Jacobian: " << jacobian << ", str.fun. factor: " << peripp << ".";
705 return jacobian * peripp; // compute the event weight using the Jacobian
706}
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_WARNING(mod)
Definition Message.h:228
#define CG_DEBUG_LOOP(mod)
Definition Message.h:224
#define CG_DEBUG(mod)
Definition Message.h:220
#define CG_INFO(mod)
Definition Message.h:216
#define REGISTER_PROCESS(name, obj)
Add a generic process definition to the list of handled processes.
Matrix element for the process as defined in .
Definition LPAIR.cpp:35
proc::ProcessPtr clone() const override
Copy all process attributes into a new object.
Definition LPAIR.cpp:45
LPAIR(const LPAIR &oth)
Definition LPAIR.cpp:42
void prepareKinematics() override
Compute the incoming state kinematics.
Definition LPAIR.cpp:59
LPAIR(const ParametersList &params)
Definition LPAIR.cpp:37
void fillKinematics() override
Fill the Event object with the particles' kinematics.
Definition LPAIR.cpp:131
static ParametersDescription description()
Definition LPAIR.cpp:176
void addEventContent() override
Set the incoming and outgoing state to be expected in the process.
Definition LPAIR.cpp:47
double computeWeight() override
Compute the phase space point weight.
Definition LPAIR.cpp:574
const Momentum & momentum() const
Beam particle 4-momentum Set the beam particle 4-momentum.
Definition Beam.h:54
Particle & oneWithRole(Particle::Role role)
First Particle object with a given role in the event.
Definition Event.cpp:190
const Beam & positive() const
Reference to the positive-z beam information.
const Beam & negative() const
Reference to the negative-z beam information.
mode::Kinematics mode() const
Type of kinematics to consider for the phase space.
List of kinematic constraints to apply on the process phase space.
Definition Kinematics.h:27
CutsList & cuts()
Phase space cuts.
Definition Kinematics.h:41
IncomingBeams & incomingBeams()
Beam/primary particle kinematics.
Definition Kinematics.h:36
Validity interval for a variable.
Definition Limits.h:28
Limits compute(double(*)(double)) const
Compute a copy of limits with an operator applied on boundaries Compute a copy of limits with an oper...
Definition Limits.cpp:152
double trim(double) const
Limit a value to boundaries.
Definition Limits.cpp:139
Limits truncate(const Limits &) const
Truncate limits to minimal/maximal values.
Definition Limits.cpp:130
bool contains(double val, bool exclude_boundaries=false) const
Check if value is inside limits' boundaries.
Definition Limits.cpp:77
A matrix object.
Definition Algebra.h:31
Container for a particle's 4-momentum, along with useful methods to ease the development of any matri...
Definition Momentum.h:33
double pz() const
Longitudinal momentum (in GeV)
Definition Momentum.h:120
Momentum & betaGammaBoost(double gamma, double betagamma)
Forward boost.
Definition Momentum.cpp:297
double px() const
Momentum along the -axis (in GeV)
Definition Momentum.h:112
Momentum & mirrorX()
Apply a transformation.
Definition Momentum.h:196
double py() const
Momentum along the -axis (in GeV)
Definition Momentum.h:116
static Momentum fromPxPyPzE(double px, double py, double pz, double e)
Build a 4-momentum from its four momentum and energy coordinates.
Definition Momentum.cpp:82
double pt() const
Transverse momentum (in GeV)
Definition Momentum.cpp:232
Momentum & setMass(double)
Compute the energy from the mass.
Definition Momentum.cpp:176
double phi() const
Azimuthal angle (angle in the transverse plane)
Definition Momentum.cpp:230
double p() const
3-momentum norm (in GeV)
Definition Momentum.h:130
double energy() const
Energy (in GeV)
Definition Momentum.h:136
double theta() const
Polar angle (angle with respect to the longitudinal direction)
Definition Momentum.cpp:228
static Momentum fromPThetaPhiE(double p, double theta, double phi, double e=-1.)
Build a 4-momentum from its scalar momentum, and its polar and azimuthal angles.
Definition Momentum.cpp:77
A description object for parameters collection.
@ IncomingBeam2
incoming beam particle
Definition Particle.h:53
@ Parton2
beam incoming parton
Definition Particle.h:59
@ OutgoingBeam1
outgoing beam state/particle
Definition Particle.h:54
@ IncomingBeam1
incoming beam particle
Definition Particle.h:52
@ OutgoingBeam2
outgoing beam state/particle
Definition Particle.h:55
@ Parton1
beam incoming parton
Definition Particle.h:58
@ CentralSystem
Central particles system.
Definition Particle.h:56
Particle & setStatus(Status status)
Definition Particle.h:96
T steer(const std::string &key) const
Retrieve a parameters as previously steered.
Definition Steerable.h:39
Specialisation of a matrix.
Definition Algebra.h:139
Nucleon electromagnetic form factors parameterisation.
Class template to define any process to compute using this MC integrator/events generator.
Definition Process.h:34
double mB2() const
Negative-z incoming beam particle's squared mass.
Definition Process.h:71
const Kinematics & kinematics() const
Constant reference to the process kinematics.
Definition Process.h:50
const Momentum & pA() const
Positive-z incoming beam particle's 4-momentum.
Definition Process.cpp:91
const Momentum & pX() const
Positive-z outgoing beam particle's 4-momentum.
Definition Process.cpp:99
double t1() const
Positive-z incoming parton's squared mass.
Definition Process.h:81
double mp_
Proton mass, in GeV/c .
Definition Process.h:121
double mX() const
Positive-z outgoing beam particle's mass.
Definition Process.h:75
const Momentum & q2() const
Negative-z incoming parton's 4-momentum.
Definition Process.cpp:111
double inverseSqrtS() const
Inverse two-beam centre of mass energy.
Definition Process.h:109
Process & defineVariable(double &out, const Mapping &type, const Limits &lim, const std::string &name, const std::string &description="")
Register a variable to be handled and populated whenever a new phase space point weight is to be calc...
Definition Process.cpp:149
@ power_law
a power-law mapping inherited from LPAIR
double s() const
Two-beam squared centre of mass energy.
Definition Process.h:107
double mA() const
Positive-z incoming beam particle's mass.
Definition Process.h:69
double mA2() const
Positive-z incoming beam particle's squared mass.
Definition Process.h:68
double mY2() const
Negative-z outgoing beam particle's squared mass.
Definition Process.h:77
Process(const ParametersList &)
Definition Process.cpp:47
double sqrtS() const
Two-beam centre of mass energy.
Definition Process.h:108
double alphaEM(double q) const
Compute the electromagnetic running coupling algorithm at a given scale.
Definition Process.cpp:346
const Momentum & pB() const
Negative-z incoming beam particle's 4-momentum.
Definition Process.cpp:95
void setEventContent(const std::unordered_map< Particle::Role, spdgids_t > &)
Set the incoming and outgoing states to be defined in this process (and prepare the Event object acco...
Definition Process.cpp:370
double mY() const
Negative-z outgoing beam particle's mass.
Definition Process.h:78
double mB() const
Negative-z incoming beam particle's mass.
Definition Process.h:72
Momentum & pc(size_t)
Central particle's 4-momentum.
Definition Process.cpp:113
const Momentum & pY() const
Negative-z outgoing beam particle's 4-momentum.
Definition Process.cpp:103
std::unique_ptr< utils::RandomGenerator > rnd_gen_
Process-local random number generator engine.
Definition Process.h:161
static ParametersDescription description()
Definition Process.cpp:403
double mX2() const
Positive-z outgoing beam particle's squared mass.
Definition Process.h:74
const Event & event() const
Handled particles objects and their relationships.
Definition Process.cpp:267
double t2() const
Negative-z incoming parton's squared mass.
Definition Process.h:84
const Momentum & q1() const
Positive-z incoming parton's 4-momentum.
Definition Process.cpp:107
Kinematics
Type of scattering.
Definition Modes.h:28
@ ElasticInelastic
proton-proton single-dissociative (or inelastic-elastic) case
std::unique_ptr< Process > ProcessPtr
Helper typedef for a Process unique pointer.
Definition Process.h:199
double xBj(double q2, double mp2, double mx2)
Compute Bjorken x from virtuality/diffractive mass.
Definition Utils.cpp:41
bool positive(const T &val)
Check if a number is positive and finite.
Definition Math.cpp:26
double fastSqrtSqDiff(double x, double y)
Compute the square root of the squared difference (sqrt(a^2-b^2))
Definition Math.cpp:43
Common namespace for this Monte Carlo generator.
unsigned long long pdgid_t
Alias for the integer-like particle PDG id.
long long spdgid_t
cuts::Remnants remnants
Cuts on the beam remnants system.
Definition Cuts.h:97
cuts::Central central
Cuts on the central system produced.
Definition Cuts.h:95
A collection of physics constants associated to a single particle.
double mass
Mass, in GeV/c .
pdgid_t pdgid
PDG identifier.
short integerCharge() const
Integer charge, in /3.
Limits mass_sum
multiparticle system invariant mass
Definition Cuts.h:46
Limits mx
diffractive mass
Definition Cuts.h:75