Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F19244225
MatrixElement.cc
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
91 KB
Referenced Files
None
Subscribers
None
MatrixElement.cc
View Options
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019-2023
* \copyright GPLv2 or later
*/
#include
"HEJ/MatrixElement.hh"
#include
<algorithm>
#include
<cassert>
#include
<cmath>
#include
<cstddef>
#include
<cstdlib>
#include
<iterator>
#include
<limits>
#include
<unordered_map>
#include
<utility>
#include
"fastjet/PseudoJet.hh"
#include
"HEJ/ConfigFlags.hh"
#include
"HEJ/Constants.hh"
#include
"HEJ/EWConstants.hh"
#include
"HEJ/Event.hh"
#include
"HEJ/HiggsCouplingSettings.hh"
#include
"HEJ/Hjets.hh"
#include
"HEJ/LorentzVector.hh"
#include
"HEJ/PDG_codes.hh"
#include
"HEJ/Particle.hh"
#include
"HEJ/WWjets.hh"
#include
"HEJ/Wjets.hh"
#include
"HEJ/Zjets.hh"
#include
"HEJ/event_types.hh"
#include
"HEJ/exceptions.hh"
#include
"HEJ/jets.hh"
#include
"HEJ/utility.hh"
namespace
HEJ
{
namespace
{
// Colour acceleration multiplier for gluons
// see eq:K_g in developer manual
double
K_g
(
double
p1minus
,
double
paminus
)
{
return
1.
/
2.
*
(
p1minus
/
paminus
+
paminus
/
p1minus
)
*
(
C_A
-
1.
/
C_A
)
+
1.
/
C_A
;
}
double
K_g
(
CLHEP
::
HepLorentzVector
const
&
pout
,
CLHEP
::
HepLorentzVector
const
&
pin
)
{
if
(
pin
.
z
()
>
0
)
return
K_g
(
pout
.
plus
(),
pin
.
plus
());
return
K_g
(
pout
.
minus
(),
pin
.
minus
());
}
// Colour acceleration multiplier for quarks
// see eq:K_q in developer manual
constexpr
double
K_q
=
C_F
;
// Colour acceleration multipliers
double
K
(
ParticleID
type
,
CLHEP
::
HepLorentzVector
const
&
pout
,
CLHEP
::
HepLorentzVector
const
&
pin
){
if
(
type
==
pid
::
gluon
)
return
K_g
(
pout
,
pin
);
return
K_q
;
}
}
// namespace
double
MatrixElement
::
omega0
(
double
alpha_s
,
double
mur
,
fastjet
::
PseudoJet
const
&
q_j
)
const
{
const
double
lambda
=
param_
.
regulator_lambda
;
const
double
result
=
-
alpha_s
*
N_C
/
M_PI
*
std
::
log
(
q_j
.
perp2
()
/
(
lambda
*
lambda
));
if
(
!
param_
.
log_correction
)
return
result
;
return
(
1.
+
alpha_s
/
(
4.
*
M_PI
)
*
BETA0
*
std
::
log
(
mur
*
mur
/
(
q_j
.
perp
()
*
lambda
))
)
*
result
;
}
Weights
MatrixElement
::
operator
()(
Event
const
&
event
)
const
{
std
::
vector
<
double
>
tree_kin_part
=
tree_kin
(
event
);
std
::
vector
<
Weights
>
virtual_part
=
virtual_corrections
(
event
);
if
(
tree_kin_part
.
size
()
!=
virtual_part
.
size
())
{
throw
std
::
logic_error
(
"tree and virtuals have different sizes"
);
}
Weights
sum
=
Weights
{
0.
,
std
::
vector
<
double
>
(
event
.
variations
().
size
(),
0.
)};
for
(
size_t
i
=
0
;
i
<
tree_kin_part
.
size
();
++
i
)
{
sum
+=
tree_kin_part
.
at
(
i
)
*
virtual_part
.
at
(
i
);
}
return
tree_param
(
event
)
*
sum
;
}
Weights
MatrixElement
::
tree
(
Event
const
&
event
)
const
{
std
::
vector
<
double
>
tree_kin_part
=
tree_kin
(
event
);
double
sum
=
0.
;
for
(
double
i
:
tree_kin_part
)
{
sum
+=
i
;
}
return
tree_param
(
event
)
*
sum
;
}
Weights
MatrixElement
::
tree_param
(
Event
const
&
event
)
const
{
if
(
!
is_resummable
(
event
.
type
()))
{
return
Weights
{
0.
,
std
::
vector
<
double
>
(
event
.
variations
().
size
(),
0.
)};
}
Weights
result
;
// only compute once for each renormalisation scale
std
::
unordered_map
<
double
,
double
>
known
;
result
.
central
=
tree_param
(
event
,
event
.
central
().
mur
);
known
.
emplace
(
event
.
central
().
mur
,
result
.
central
);
for
(
auto
const
&
var
:
event
.
variations
())
{
const
auto
ME_it
=
known
.
find
(
var
.
mur
);
if
(
ME_it
==
end
(
known
))
{
const
double
wt
=
tree_param
(
event
,
var
.
mur
);
result
.
variations
.
emplace_back
(
wt
);
known
.
emplace
(
var
.
mur
,
wt
);
}
else
{
result
.
variations
.
emplace_back
(
ME_it
->
second
);
}
}
return
result
;
}
std
::
vector
<
Weights
>
MatrixElement
::
virtual_corrections
(
Event
const
&
event
)
const
{
if
(
!
event
.
valid_hej_state
(
param_
.
soft_pt_regulator
))
{
return
{
Weights
{
0.
,
std
::
vector
<
double
>
(
event
.
variations
().
size
(),
0.
)}};
}
// only compute once for each renormalisation scale
std
::
unordered_map
<
double
,
std
::
vector
<
double
>
>
known_vec
;
std
::
vector
<
double
>
central_vec
=
virtual_corrections
(
event
,
event
.
central
().
mur
);
known_vec
.
emplace
(
event
.
central
().
mur
,
central_vec
);
for
(
auto
const
&
var
:
event
.
variations
())
{
const
auto
ME_it
=
known_vec
.
find
(
var
.
mur
);
if
(
ME_it
==
end
(
known_vec
))
{
known_vec
.
emplace
(
var
.
mur
,
virtual_corrections
(
event
,
var
.
mur
));
}
}
// At this stage known_vec contains one vector of virtual corrections for each mur value
// Now put this into a vector of Weights
std
::
vector
<
Weights
>
result_vec
;
for
(
size_t
i
=
0
;
i
<
central_vec
.
size
();
++
i
)
{
Weights
result
;
result
.
central
=
central_vec
.
at
(
i
);
for
(
auto
const
&
var
:
event
.
variations
())
{
const
auto
ME_it
=
known_vec
.
find
(
var
.
mur
);
result
.
variations
.
emplace_back
(
ME_it
->
second
.
at
(
i
));
}
result_vec
.
emplace_back
(
result
);
}
return
result_vec
;
}
template
<
class
InputIterator
>
std
::
vector
<
double
>
MatrixElement
::
virtual_corrections_interference
(
InputIterator
begin_parton
,
InputIterator
end_parton
,
fastjet
::
PseudoJet
const
&
q0_t
,
fastjet
::
PseudoJet
const
&
q0_b
,
const
double
mur
)
const
{
const
double
alpha_s
=
alpha_s_
(
mur
);
auto
qi_t
=
q0_t
;
auto
qi_b
=
q0_b
;
double
sum_top
=
0.
;
double
sum_bot
=
0.
;
double
sum_mix
=
0.
;
for
(
auto
parton_it
=
begin_parton
;
parton_it
!=
end_parton
;
++
parton_it
){
Particle
parton
=
*
parton_it
;
Particle
parton_next
=
*
(
parton_it
+
1
);
const
double
dy
=
parton_next
.
rapidity
()
-
parton
.
rapidity
();
const
double
tmp_top
=
omega0
(
alpha_s
,
mur
,
qi_t
)
*
dy
;
const
double
tmp_bot
=
omega0
(
alpha_s
,
mur
,
qi_b
)
*
dy
;
sum_top
+=
tmp_top
;
sum_bot
+=
tmp_bot
;
sum_mix
+=
(
tmp_top
+
tmp_bot
)
/
2.
;
qi_t
-=
parton_next
.
p
;
qi_b
-=
parton_next
.
p
;
}
if
(
param_
.
nlo
.
enabled
){
return
{(
sum_top
),
(
sum_bot
),
(
sum_mix
)};
}
return
{
exp
(
sum_top
),
exp
(
sum_bot
),
exp
(
sum_mix
)};
}
double
MatrixElement
::
virtual_corrections_W
(
Event
const
&
event
,
const
double
mur
,
Particle
const
&
WBoson
)
const
{
auto
const
&
in
=
event
.
incoming
();
const
auto
partons
=
filter_partons
(
event
.
outgoing
());
fastjet
::
PseudoJet
const
&
pa
=
in
.
front
().
p
;
#ifndef NDEBUG
fastjet
::
PseudoJet
const
&
pb
=
in
.
back
().
p
;
double
const
norm
=
(
in
.
front
().
p
+
in
.
back
().
p
).
E
();
#endif
assert
(
std
::
is_sorted
(
partons
.
begin
(),
partons
.
end
(),
rapidity_less
{}));
assert
(
partons
.
size
()
>=
2
);
assert
(
pa
.
pz
()
<
pb
.
pz
());
fastjet
::
PseudoJet
q
=
pa
-
partons
[
0
].
p
;
auto
first_idx
=
cbegin
(
partons
);
auto
last_idx
=
cend
(
partons
)
-
1
;
#ifndef NDEBUG
bool
wc
=
true
;
#endif
// With extremal qqbar or unordered gluon outside the extremal
// partons then it is not part of the FKL ladder and does not
// contribute to the virtual corrections. W emitted from the
// most backward leg must be taken into account in t-channel
if
(
event
.
type
()
==
event_type
::
unob
)
{
q
-=
partons
[
1
].
p
;
++
first_idx
;
if
(
in
[
0
].
type
!=
partons
[
1
].
type
){
q
-=
WBoson
.
p
;
#ifndef NDEBUG
wc
=
false
;
#endif
}
}
else
if
(
event
.
type
()
==
event_type
::
qqbar_exb
)
{
q
-=
partons
[
1
].
p
;
++
first_idx
;
if
(
std
::
abs
(
partons
[
0
].
type
)
!=
std
::
abs
(
partons
[
1
].
type
)){
q
-=
WBoson
.
p
;
#ifndef NDEBUG
wc
=
false
;
#endif
}
}
else
{
if
(
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
){
--
last_idx
;
}
if
(
in
[
0
].
type
!=
partons
[
0
].
type
){
q
-=
WBoson
.
p
;
#ifndef NDEBUG
wc
=
false
;
#endif
}
}
auto
first_idx_qqbar
=
last_idx
;
auto
last_idx_qqbar
=
last_idx
;
bool
wqq
=
false
;
//if qqbarMid event, virtual correction do not occur between qqbar pair.
if
(
event
.
type
()
==
event_type
::
qqbar_mid
){
const
auto
backquark
=
std
::
find_if
(
begin
(
partons
)
+
1
,
end
(
partons
)
-
1
,
[](
Particle
const
&
s
){
return
(
s
.
type
!=
pid
::
gluon
);
}
);
assert
(
backquark
!=
end
(
partons
)
-
1
&&
(
backquark
+
1
)
->
type
!=
pid
::
gluon
);
if
(
std
::
abs
(
backquark
->
type
)
!=
std
::
abs
((
backquark
+
1
)
->
type
))
{
wqq
=
true
;
#ifndef NDEBUG
wc
=
false
;
#endif
}
last_idx
=
backquark
;
first_idx_qqbar
=
last_idx
+
1
;
}
double
exponent
=
0
;
const
double
alpha_s
=
alpha_s_
(
mur
);
for
(
auto
parton_it
=
first_idx
;
parton_it
!=
last_idx
;
++
parton_it
)
{
exponent
+=
omega0
(
alpha_s
,
mur
,
q
)
*
(
(
parton_it
+
1
)
->
rapidity
()
-
parton_it
->
rapidity
()
);
q
-=
(
parton_it
+
1
)
->
p
;
}
// End Loop one
if
(
last_idx
!=
first_idx_qqbar
)
{
q
-=
(
*
(
last_idx
+
1
)).
p
;
if
(
wqq
)
q
-=
WBoson
.
p
;
for
(
auto
parton_it
=
first_idx_qqbar
;
parton_it
!=
last_idx_qqbar
;
++
parton_it
)
{
exponent
+=
omega0
(
alpha_s
,
mur
,
q
)
*
(
(
parton_it
+
1
)
->
rapidity
()
-
parton_it
->
rapidity
()
);
q
-=
(
parton_it
+
1
)
->
p
;
}
}
#ifndef NDEBUG
if
(
wc
)
q
-=
WBoson
.
p
;
assert
(
nearby
(
q
,
-
1
*
pb
,
norm
)
||
is_AWZH_boson
(
partons
.
back
().
type
)
||
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
);
#endif
if
(
param_
.
nlo
.
enabled
)
{
double
nlo_virtual
=
1.
;
// Only apply virtual corrections to a nlo order event.
if
(
partons
.
size
()
==
param_
.
nlo
.
nj
)
nlo_virtual
+=
exponent
;
return
nlo_virtual
;
}
return
std
::
exp
(
exponent
);
}
std
::
vector
<
double
>
MatrixElement
::
virtual_corrections_WW
(
Event
const
&
event
,
const
double
mur
)
const
{
auto
const
&
in
=
event
.
incoming
();
const
auto
partons
=
filter_partons
(
event
.
outgoing
());
fastjet
::
PseudoJet
const
&
pa
=
in
.
front
().
p
;
#ifndef NDEBUG
fastjet
::
PseudoJet
const
&
pb
=
in
.
back
().
p
;
#endif
assert
(
std
::
is_sorted
(
partons
.
begin
(),
partons
.
end
(),
rapidity_less
{}));
assert
(
partons
.
size
()
>=
2
);
assert
(
pa
.
pz
()
<
pb
.
pz
());
assert
(
event
.
decays
().
size
()
==
2
);
std
::
vector
<
fastjet
::
PseudoJet
>
plbar
;
std
::
vector
<
fastjet
::
PseudoJet
>
pl
;
for
(
auto
const
&
decay_pair
:
event
.
decays
())
{
auto
const
decay
=
decay_pair
.
second
;
if
(
decay
.
at
(
0
).
type
<
0
)
{
plbar
.
emplace_back
(
decay
.
at
(
0
).
p
);
pl
.
emplace_back
(
decay
.
at
(
1
).
p
);
}
else
{
pl
.
emplace_back
(
decay
.
at
(
0
).
p
);
plbar
.
emplace_back
(
decay
.
at
(
1
).
p
);
}
}
fastjet
::
PseudoJet
q_t
=
pa
-
partons
[
0
].
p
-
pl
[
0
]
-
plbar
[
0
];
fastjet
::
PseudoJet
q_b
=
pa
-
partons
[
0
].
p
-
pl
[
1
]
-
plbar
[
1
];
auto
const
begin_parton
=
cbegin
(
partons
);
auto
const
end_parton
=
cend
(
partons
)
-
1
;
if
(
param_
.
nlo
.
enabled
){
std
::
vector
<
double
>
virt_corrections_nlo
{
1.0
,
1.0
,
1.0
};
//set virtual corrections to 1.
// Only apply virtual corrections to a nlo order event.
if
(
partons
.
size
()
==
param_
.
nlo
.
nj
)
{
std
::
vector
<
double
>
virt_corrections_nlo_interference
=
virtual_corrections_interference
(
begin_parton
,
end_parton
,
q_t
,
q_b
,
mur
);
assert
(
virt_corrections_nlo_interference
.
size
()
==
virt_corrections_nlo
.
size
()
);
for
(
std
::
size_t
i
=
0
;
i
<
virt_corrections_nlo
.
size
();
++
i
){
virt_corrections_nlo
[
i
]
+=
virt_corrections_nlo_interference
[
i
];
}
}
return
virt_corrections_nlo
;
}
return
virtual_corrections_interference
(
begin_parton
,
end_parton
,
q_t
,
q_b
,
mur
);
}
std
::
vector
<
double
>
MatrixElement
::
virtual_corrections_Z_interference
(
Event
const
&
event
,
const
double
mur
,
Particle
const
&
ZBoson
)
const
{
auto
const
&
in
=
event
.
incoming
();
const
auto
partons
=
filter_partons
(
event
.
outgoing
());
fastjet
::
PseudoJet
const
&
pa
=
in
.
front
().
p
;
#ifndef NDEBUG
fastjet
::
PseudoJet
const
&
pb
=
in
.
back
().
p
;
#endif
assert
(
std
::
is_sorted
(
partons
.
begin
(),
partons
.
end
(),
rapidity_less
{}));
assert
(
partons
.
size
()
>=
2
);
assert
(
pa
.
pz
()
<
pb
.
pz
());
fastjet
::
PseudoJet
q_t
=
pa
-
partons
[
0
].
p
-
ZBoson
.
p
;
fastjet
::
PseudoJet
q_b
=
pa
-
partons
[
0
].
p
;
auto
begin_parton
=
cbegin
(
partons
);
auto
end_parton
=
cend
(
partons
)
-
1
;
// for uno/exqqbar the two extremal partons do not contribute to the virtual corrections
if
(
event
.
type
()
==
event_type
::
unob
||
event
.
type
()
==
event_type
::
qqbar_exb
)
{
// unordered gluon or first quark is partons[0] and is already subtracted
// partons[1] is the backward quark (uno case) or the second quark (exqqbar case)
q_t
-=
partons
[
1
].
p
;
q_b
-=
partons
[
1
].
p
;
++
begin_parton
;
}
else
if
(
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
)
{
// end sum at next to last parton
--
end_parton
;
}
if
(
param_
.
nlo
.
enabled
){
//set virtual corrections to 1.
std
::
vector
<
double
>
virt_corrections_nlo
{
1.0
,
1.0
,
1.0
};
// Only apply virtual corrections to a nlo order event.
if
(
partons
.
size
()
==
param_
.
nlo
.
nj
)
{
std
::
vector
<
double
>
virt_corrections_nlo_interference
=
virtual_corrections_interference
(
begin_parton
,
end_parton
,
q_t
,
q_b
,
mur
);
assert
(
virt_corrections_nlo
.
size
()
==
virt_corrections_nlo_interference
.
size
()
);
for
(
std
::
size_t
i
=
0
;
i
<
virt_corrections_nlo
.
size
();
++
i
){
virt_corrections_nlo
[
i
]
+=
virt_corrections_nlo_interference
[
i
];
}
}
return
virt_corrections_nlo
;
}
return
virtual_corrections_interference
(
begin_parton
,
end_parton
,
q_t
,
q_b
,
mur
);
}
double
MatrixElement
::
virtual_corrections_Z_no_interference
(
Event
const
&
event
,
const
double
mur
,
Particle
const
&
ZBoson
,
const
bool
emit_fwd
)
const
{
auto
const
&
in
=
event
.
incoming
();
const
auto
partons
=
filter_partons
(
event
.
outgoing
());
fastjet
::
PseudoJet
const
&
pa
=
in
.
front
().
p
;
#ifndef NDEBUG
fastjet
::
PseudoJet
const
&
pb
=
in
.
back
().
p
;
#endif
assert
(
std
::
is_sorted
(
partons
.
begin
(),
partons
.
end
(),
rapidity_less
{}));
assert
(
partons
.
size
()
>=
2
);
assert
(
pa
.
pz
()
<
pb
.
pz
());
// If the Z is emitted from forward leg, don't subtract the Z momentum from first q
fastjet
::
PseudoJet
q
=
(
emit_fwd
?
pa
-
partons
[
0
].
p
:
pa
-
partons
[
0
].
p
-
ZBoson
.
p
);
size_t
first_idx
=
0
;
size_t
last_idx
=
partons
.
size
()
-
1
;
// for uno/exqqbar the two extremal partons do not contribute to the virtual corrections
if
(
event
.
type
()
==
event_type
::
unob
||
event
.
type
()
==
event_type
::
qqbar_exb
)
{
// unordered gluon or first quark is partons[0] and is already subtracted
// partons[1] is the backward quark (uno case) or the second quark (exqqbar case)
q
-=
partons
[
1
].
p
;
++
first_idx
;
}
else
if
(
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
)
{
// end sum at next to last parton
--
last_idx
;
}
double
sum
=
0.
;
const
double
alpha_s
=
alpha_s_
(
mur
);
for
(
size_t
j
=
first_idx
;
j
<
last_idx
;
++
j
){
sum
+=
omega0
(
alpha_s
,
mur
,
q
)
*
(
partons
[
j
+
1
].
rapidity
()
-
partons
[
j
].
rapidity
());
q
-=
partons
[
j
+
1
].
p
;
}
if
(
param_
.
nlo
.
enabled
){
double
nlo_virtual
=
1.
;
//Only apply virtual corrections to a nlo order event.
if
(
partons
.
size
()
==
param_
.
nlo
.
nj
)
nlo_virtual
+=
sum
;
return
nlo_virtual
;
}
return
exp
(
sum
);
}
std
::
vector
<
double
>
MatrixElement
::
virtual_corrections
(
Event
const
&
event
,
const
double
mur
)
const
{
auto
const
&
in
=
event
.
incoming
();
auto
const
&
out
=
event
.
outgoing
();
fastjet
::
PseudoJet
const
&
pa
=
in
.
front
().
p
;
#ifndef NDEBUG
fastjet
::
PseudoJet
const
&
pb
=
in
.
back
().
p
;
double
const
norm
=
(
in
.
front
().
p
+
in
.
back
().
p
).
E
();
#endif
std
::
vector
<
Particle
>
bosons
=
filter_AWZH_bosons
(
out
);
if
(
event
.
jets
().
size
()
!=
param_
.
nlo
.
nj
&&
param_
.
nlo
.
enabled
)
{
throw
std
::
logic_error
{
"Input event has number of jets different to stated NLO "
"input in config file: "
+
std
::
to_string
(
event
.
jets
().
size
())
+
" vs "
+
std
::
to_string
(
param_
.
nlo
.
nj
)
+
"
\n
"
};
}
if
(
bosons
.
size
()
>
2
)
{
throw
not_implemented
(
"Emission of >2 bosons is unsupported"
);
}
if
(
bosons
.
size
()
==
2
)
{
if
(
bosons
[
0
].
type
==
pid
::
Wp
&&
bosons
[
1
].
type
==
pid
::
Wp
)
{
return
virtual_corrections_WW
(
event
,
mur
);
}
else
if
(
bosons
[
0
].
type
==
pid
::
Wm
&&
bosons
[
1
].
type
==
pid
::
Wm
)
{
return
virtual_corrections_WW
(
event
,
mur
);
}
throw
not_implemented
(
"Emission of bosons of unsupported type"
);
}
if
(
bosons
.
size
()
==
1
)
{
const
auto
AWZH_boson
=
bosons
[
0
];
if
(
std
::
abs
(
AWZH_boson
.
type
)
==
pid
::
Wp
){
return
{
virtual_corrections_W
(
event
,
mur
,
AWZH_boson
)};
}
if
(
AWZH_boson
.
type
==
pid
::
Z_photon_mix
){
if
(
event
.
type
()
==
event_type
::
FKL
||
event
.
type
()
==
event_type
::
unob
||
event
.
type
()
==
event_type
::
unof
){
if
(
is_gluon
(
in
.
back
().
type
)){
// qg event, emission from backward leg
return
{
virtual_corrections_Z_no_interference
(
event
,
mur
,
AWZH_boson
,
false
)};
}
if
(
is_gluon
(
in
.
front
().
type
)){
// gq event, emission from forward leg
return
{
virtual_corrections_Z_no_interference
(
event
,
mur
,
AWZH_boson
,
true
)};
}
}
if
(
event
.
type
()
==
event_type
::
qqbar_exb
&&
is_gluon
(
in
.
back
().
type
)){
// gg event, emission from backward leg
return
{
virtual_corrections_Z_no_interference
(
event
,
mur
,
AWZH_boson
,
false
)};
}
if
(
event
.
type
()
==
event_type
::
qqbar_exf
&&
is_gluon
(
in
.
front
().
type
)){
// gg event, emission from forward leg
return
{
virtual_corrections_Z_no_interference
(
event
,
mur
,
AWZH_boson
,
true
)};
}
// qq initiated FKL/uno or qg/gq initiated exqqbar
return
virtual_corrections_Z_interference
(
event
,
mur
,
AWZH_boson
);
}
}
assert
(
std
::
is_sorted
(
out
.
begin
(),
out
.
end
(),
rapidity_less
{}));
assert
(
out
.
size
()
>=
2
);
assert
(
pa
.
pz
()
<
pb
.
pz
());
fastjet
::
PseudoJet
q
=
pa
-
out
[
0
].
p
;
auto
first_idx
=
cbegin
(
out
);
auto
last_idx
=
cend
(
out
)
-
1
;
// if there is a Higgs boson _not_ emitted off an incoming gluon,
// extremal qqbar or unordered gluon outside the extremal partons
// then it is not part of the FKL ladder
// and does not contribute to the virtual corrections
if
((
out
.
front
().
type
==
pid
::
Higgs
&&
in
.
front
().
type
!=
pid
::
gluon
)
||
event
.
type
()
==
event_type
::
unob
||
event
.
type
()
==
event_type
::
qqbar_exb
){
q
-=
out
[
1
].
p
;
++
first_idx
;
}
if
((
out
.
back
().
type
==
pid
::
Higgs
&&
in
.
back
().
type
!=
pid
::
gluon
)
||
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
){
--
last_idx
;
}
auto
first_idx_qqbar
=
last_idx
;
auto
last_idx_qqbar
=
last_idx
;
//if central qqbar event, virtual correction do not occur between q-qbar.
if
(
event
.
type
()
==
event_type
::
qqbar_mid
){
const
auto
backquark
=
std
::
find_if
(
begin
(
out
)
+
1
,
end
(
out
)
-
1
,
[](
Particle
const
&
s
){
return
(
s
.
type
!=
pid
::
gluon
&&
is_parton
(
s
.
type
));
}
);
assert
(
backquark
!=
end
(
out
)
-
1
&&
(
backquark
+
1
)
->
type
!=
pid
::
gluon
);
last_idx
=
backquark
;
first_idx_qqbar
=
last_idx
+
1
;
}
double
exponent
=
0
;
const
double
alpha_s
=
alpha_s_
(
mur
);
for
(
auto
parton_it
=
first_idx
;
parton_it
!=
last_idx
;
++
parton_it
)
{
exponent
+=
omega0
(
alpha_s
,
mur
,
q
)
*
(
(
parton_it
+
1
)
->
rapidity
()
-
parton_it
->
rapidity
()
);
q
-=
(
parton_it
+
1
)
->
p
;
}
if
(
last_idx
!=
first_idx_qqbar
)
{
q
-=
(
*
(
last_idx
+
1
)).
p
;
for
(
auto
parton_it
=
first_idx_qqbar
;
parton_it
!=
last_idx_qqbar
;
++
parton_it
)
{
exponent
+=
omega0
(
alpha_s
,
mur
,
q
)
*
(
(
parton_it
+
1
)
->
rapidity
()
-
parton_it
->
rapidity
()
);
q
-=
(
parton_it
+
1
)
->
p
;
}
}
assert
(
nearby
(
q
,
-
1
*
pb
,
norm
)
||
(
out
.
back
().
type
==
pid
::
Higgs
&&
in
.
back
().
type
!=
pid
::
gluon
)
||
event
.
type
()
==
event_type
::
unof
||
event
.
type
()
==
event_type
::
qqbar_exf
);
if
(
param_
.
nlo
.
enabled
){
const
auto
partons
=
filter_partons
(
event
.
outgoing
());
double
nlo_virtual
=
1.
;
// Only apply virtual corrections to a nlo order event.
if
(
partons
.
size
()
==
param_
.
nlo
.
nj
)
nlo_virtual
+=
exponent
;
return
{
nlo_virtual
};
}
return
{
std
::
exp
(
exponent
)};
}
namespace
{
//! Lipatov vertex for partons emitted into extremal jets
CLHEP
::
HepLorentzVector
CLipatov
(
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
)
{
const
CLHEP
::
HepLorentzVector
p5
=
qav
-
qbv
;
const
CLHEP
::
HepLorentzVector
CL
=
-
(
qav
+
qbv
)
+
p1
*
(
qav
.
m2
()
/
p5
.
dot
(
p1
)
+
2.
*
p5
.
dot
(
p2
)
/
p1
.
dot
(
p2
))
-
p2
*
(
qbv
.
m2
()
/
p5
.
dot
(
p2
)
+
2.
*
p5
.
dot
(
p1
)
/
p1
.
dot
(
p2
));
return
CL
;
}
double
C2Lipatov
(
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
){
const
CLHEP
::
HepLorentzVector
CL
=
CLipatov
(
qav
,
qbv
,
p1
,
p2
);
return
-
CL
.
dot
(
CL
);
}
//! Lipatov vertex with soft subtraction for partons emitted into extremal jets
double
C2Lipatovots
(
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
,
const
double
lambda
)
{
const
double
Cls
=
(
C2Lipatov
(
qav
,
qbv
,
p1
,
p2
)
/
(
qav
.
m2
()
*
qbv
.
m2
()));
const
double
kperp
=
(
qav
-
qbv
).
perp
();
if
(
kperp
>
lambda
)
return
Cls
;
return
Cls
-
4.
/
(
kperp
*
kperp
);
}
double
C2Lipatov_Mix
(
CLHEP
::
HepLorentzVector
const
&
qav_t
,
CLHEP
::
HepLorentzVector
const
&
qbv_t
,
CLHEP
::
HepLorentzVector
const
&
qav_b
,
CLHEP
::
HepLorentzVector
const
&
qbv_b
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
)
{
const
CLHEP
::
HepLorentzVector
CL_t
=
CLipatov
(
qav_t
,
qbv_t
,
p1
,
p2
);
const
CLHEP
::
HepLorentzVector
CL_b
=
CLipatov
(
qav_b
,
qbv_b
,
p1
,
p2
);
return
-
CL_t
.
dot
(
CL_b
);
}
double
C2Lipatovots_Mix
(
CLHEP
::
HepLorentzVector
const
&
qav_t
,
CLHEP
::
HepLorentzVector
const
&
qbv_t
,
CLHEP
::
HepLorentzVector
const
&
qav_b
,
CLHEP
::
HepLorentzVector
const
&
qbv_b
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
,
const
double
lambda
)
{
const
double
Cls
=
C2Lipatov_Mix
(
qav_t
,
qbv_t
,
qav_b
,
qbv_b
,
p1
,
p2
)
/
sqrt
(
qav_t
.
m2
()
*
qbv_t
.
m2
()
*
qav_b
.
m2
()
*
qbv_b
.
m2
());
const
double
kperp
=
(
qav_t
-
qbv_t
).
perp
();
if
(
kperp
>
lambda
){
return
Cls
;
}
return
Cls
-
4.0
/
(
kperp
*
kperp
);
}
CLHEP
::
HepLorentzVector
CLipatov
(
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
pim
,
CLHEP
::
HepLorentzVector
const
&
pip
,
CLHEP
::
HepLorentzVector
const
&
pom
,
CLHEP
::
HepLorentzVector
const
&
pop
){
const
CLHEP
::
HepLorentzVector
p5
=
qav
-
qbv
;
const
CLHEP
::
HepLorentzVector
CL
=
-
(
qav
+
qbv
)
+
qav
.
m2
()
*
(
1.
/
p5
.
dot
(
pip
)
*
pip
+
1.
/
p5
.
dot
(
pop
)
*
pop
)
/
2.
-
qbv
.
m2
()
*
(
1.
/
p5
.
dot
(
pim
)
*
pim
+
1.
/
p5
.
dot
(
pom
)
*
pom
)
/
2.
+
(
pip
*
(
p5
.
dot
(
pim
)
/
pip
.
dot
(
pim
)
+
p5
.
dot
(
pom
)
/
pip
.
dot
(
pom
))
+
pop
*
(
p5
.
dot
(
pim
)
/
pop
.
dot
(
pim
)
+
p5
.
dot
(
pom
)
/
pop
.
dot
(
pom
))
-
pim
*
(
p5
.
dot
(
pip
)
/
pip
.
dot
(
pim
)
+
p5
.
dot
(
pop
)
/
pop
.
dot
(
pim
))
-
pom
*
(
p5
.
dot
(
pip
)
/
pip
.
dot
(
pom
)
+
p5
.
dot
(
pop
)
/
pop
.
dot
(
pom
))
)
/
2.
;
return
CL
;
}
//! Lipatov vertex
double
C2Lipatov
(
// B
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
pim
,
CLHEP
::
HepLorentzVector
const
&
pip
,
CLHEP
::
HepLorentzVector
const
&
pom
,
CLHEP
::
HepLorentzVector
const
&
pop
){
const
CLHEP
::
HepLorentzVector
CL
=
CLipatov
(
qav
,
qbv
,
pim
,
pip
,
pom
,
pop
);
return
-
CL
.
dot
(
CL
);
}
//! Lipatov vertex with soft subtraction
double
C2Lipatovots
(
CLHEP
::
HepLorentzVector
const
&
qav
,
CLHEP
::
HepLorentzVector
const
&
qbv
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
,
const
double
lambda
)
{
const
double
Cls
=
(
C2Lipatov
(
qav
,
qbv
,
pa
,
pb
,
p1
,
p2
)
/
(
qav
.
m2
()
*
qbv
.
m2
()));
const
double
kperp
=
(
qav
-
qbv
).
perp
();
if
(
kperp
>
lambda
)
return
Cls
;
return
Cls
-
4.
/
(
kperp
*
kperp
);
}
double
C2Lipatov_Mix
(
CLHEP
::
HepLorentzVector
const
&
qav_t
,
CLHEP
::
HepLorentzVector
const
&
qbv_t
,
CLHEP
::
HepLorentzVector
const
&
qav_b
,
CLHEP
::
HepLorentzVector
const
&
qbv_b
,
CLHEP
::
HepLorentzVector
const
&
pim
,
CLHEP
::
HepLorentzVector
const
&
pip
,
CLHEP
::
HepLorentzVector
const
&
pom
,
CLHEP
::
HepLorentzVector
const
&
pop
)
{
const
CLHEP
::
HepLorentzVector
CL_t
=
CLipatov
(
qav_t
,
qbv_t
,
pim
,
pip
,
pom
,
pop
);
const
CLHEP
::
HepLorentzVector
CL_b
=
CLipatov
(
qav_b
,
qbv_b
,
pim
,
pip
,
pom
,
pop
);
return
-
CL_t
.
dot
(
CL_b
);
}
double
C2Lipatovots_Mix
(
CLHEP
::
HepLorentzVector
const
&
qav_t
,
CLHEP
::
HepLorentzVector
const
&
qbv_t
,
CLHEP
::
HepLorentzVector
const
&
qav_b
,
CLHEP
::
HepLorentzVector
const
&
qbv_b
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
,
const
double
lambda
)
{
const
double
Cls
=
C2Lipatov_Mix
(
qav_t
,
qbv_t
,
qav_b
,
qbv_b
,
pa
,
pb
,
p1
,
p2
)
/
sqrt
(
qav_t
.
m2
()
*
qbv_t
.
m2
()
*
qav_b
.
m2
()
*
qbv_b
.
m2
());
const
double
kperp
=
(
qav_t
-
qbv_t
).
perp
();
if
(
kperp
>
lambda
)
{
return
Cls
;
}
return
Cls
-
4.0
/
(
kperp
*
kperp
);
}
/** Matrix element squared for tree-level current-current scattering
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pg Unordered gluon momentum
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @returns ME Squared for Tree-Level Current-Current Scattering
*
* @note The unof contribution can be calculated by reversing the argument ordering.
*/
double
ME_uno_current
(
[[
maybe_unused
]]
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pg
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
){
assert
(
aptype
!=
pid
::
gluon
);
// aptype cannot be gluon
const
double
t1
=
(
pa
-
p1
-
pg
).
m2
();
const
double
t2
=
(
pb
-
pn
).
m2
();
return
K_q
*
K
(
bptype
,
pn
,
pb
)
*
currents
::
ME_unob_qq
(
pg
,
p1
,
pa
,
pn
,
pb
)
/
(
t1
*
t2
);
}
/** Matrix element squared for tree-level current-current scattering
* @param bptype Particle b PDG ID
* @param pgin Incoming gluon momentum
* @param p1 More backward (anti-)quark from splitting Momentum
* @param p2 Less backward (anti-)quark from splitting Momentum
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @returns ME Squared for Tree-Level Current-Current Scattering
*
* @note The forward qqbar contribution can be calculated by reversing the
* argument ordering.
*/
double
ME_qqbar_current
(
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pgin
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
p2
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
){
const
double
t1
=
(
pgin
-
p1
-
p2
).
m2
();
const
double
t2
=
(
pn
-
pb
).
m2
();
return
K_q
*
K
(
bptype
,
pn
,
pb
)
*
currents
::
ME_qqbar_qg
(
pgin
,
pb
,
p1
,
p2
,
pn
)
/
(
t1
*
t2
);
}
/* \brief Matrix element squared for central qqbar tree-level current-current
* scattering
*
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param nabove Number of gluons emitted before central qqbarpair
* @param nbelow Number of gluons emitted after central qqbarpair
* @param pa Initial state a Momentum
* @param pb Initial state b Momentum
* @param partons Vector of all outgoing partons
* @param qbar_first Ordering of the qqbar pair (true: qbar-q, false: q-qbar)
* @returns ME Squared for qqbar_mid Tree-Level Current-Current Scattering
*/
double
ME_qqbar_mid_current
(
ParticleID
aptype
,
ParticleID
bptype
,
int
nabove
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
CLHEP
::
HepLorentzVector
>
const
&
partons
,
bool
const
qbar_first
){
using
namespace
currents
;
CLHEP
::
HepLorentzVector
const
&
p1
=
partons
.
front
();
CLHEP
::
HepLorentzVector
const
&
pn
=
partons
.
back
();
const
double
t1
=
(
p1
-
pa
).
m2
();
const
double
t2
=
(
pb
-
pn
).
m2
();
return
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
*
ME_Cenqqbar_qq
(
pa
,
pb
,
partons
,
qbar_first
,
nabove
)
/
(
t1
*
t2
*
(
4.
*
(
N_C
*
N_C
-
1
)));
}
/** Matrix element squared for tree-level current-current scattering
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @returns ME Squared for Tree-Level Current-Current Scattering
*/
double
ME_current
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
){
const
double
t1
=
(
p1
-
pa
).
m2
();
const
double
t2
=
(
pb
-
pn
).
m2
();
return
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
*
currents
::
ME_qq
(
p1
,
pa
,
pn
,
pb
)
/
(
t1
*
t2
);
}
/** Matrix element squared for tree-level current-current scattering With W+Jets
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param wc Boolean. True->W Emitted from b. Else; emitted from leg a
* @returns ME Squared for Tree-Level Current-Current Scattering
*/
double
ME_W_current
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
bool
const
wc
,
ParticleProperties
const
&
Wprop
){
using
namespace
currents
;
assert
(
!
(
aptype
==
pid
::
gluon
&&
bptype
==
pid
::
gluon
));
if
(
aptype
==
pid
::
gluon
||
wc
)
{
// swap currents to ensure that the W is emitted off the first one
return
ME_W_current
(
bptype
,
aptype
,
p1
,
pa
,
pn
,
pb
,
plbar
,
pl
,
false
,
Wprop
);
}
// we assume that the W is emitted off a quark line
// if this is not the case, we have to apply CP conjugation,
// which is equivalent to swapping lepton and antilepton momenta
const
double
current_contr
=
is_quark
(
aptype
)
?
ME_W_qQ
(
p1
,
plbar
,
pl
,
pa
,
pn
,
pb
,
Wprop
)
:
ME_W_qQ
(
p1
,
pl
,
plbar
,
pa
,
pn
,
pb
,
Wprop
);
const
double
t1
=
(
pa
-
p1
-
pl
-
plbar
).
m2
();
const
double
tn
=
(
pn
-
pb
).
m2
();
return
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
*
current_contr
/
(
4.
*
(
N_C
*
N_C
-
1
)
*
t1
*
tn
);
}
/** Matrix element squared for backwards uno tree-level current-current
* scattering With W+Jets
*
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param pg Unordered gluon momentum
* @param wc Boolean. True->W Emitted from b. Else; emitted from leg a
* @returns ME Squared for unob Tree-Level Current-Current Scattering
*
* @note The unof contribution can be calculated by reversing the argument ordering.
*/
double
ME_W_uno_current
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pg
,
CLHEP
::
HepLorentzVector
plbar
,
CLHEP
::
HepLorentzVector
pl
,
bool
const
wc
,
ParticleProperties
const
&
Wprop
){
using
namespace
currents
;
assert
(
bptype
!=
pid
::
gluon
||
aptype
!=
pid
::
gluon
);
if
(
aptype
==
pid
::
gluon
||
wc
)
{
// emission off pb -- pn line
// we assume that the W is emitted off a quark line
// if this is not the case, we have to apply CP conjugation,
// which is equivalent to swapping lepton and antilepton momenta
if
(
is_antiquark
(
bptype
))
std
::
swap
(
plbar
,
pl
);
const
double
t1
=
(
pa
-
p1
-
pg
).
m2
();
const
double
tn
=
(
pb
-
pn
-
plbar
-
pl
).
m2
();
return
K_q
*
K_q
*
ME_W_unob_qQ
(
p1
,
pa
,
pn
,
pb
,
pg
,
plbar
,
pl
,
Wprop
)
/
(
4.
*
(
N_C
*
N_C
-
1
)
*
t1
*
tn
);
}
// emission off pa -- p1 line
if
(
is_antiquark
(
aptype
))
std
::
swap
(
plbar
,
pl
);
const
double
t1
=
(
pa
-
p1
-
pg
-
plbar
-
pl
).
m2
();
const
double
tn
=
(
pb
-
pn
).
m2
();
return
K
(
bptype
,
pn
,
pb
)
/
C_F
*
ME_Wuno_qQ
(
p1
,
pa
,
pn
,
pb
,
pg
,
plbar
,
pl
,
Wprop
)
/
(
t1
*
tn
);
}
/** \brief Matrix element squared for backward qqbar tree-level current-current
* scattering With W+Jets
*
* @param bptype Particle b PDG ID
* @param pa Initial state a Momentum
* @param pb Initial state b Momentum
* @param pq Final state q Momentum
* @param pqbar Final state qbar Momentum
* @param pn Final state n Momentum
* @param plbar Final state anti-lepton momentum
* @param pl Final state lepton momentum
* @param wc Boolean. True->W Emitted from b. Else; emitted from leg a
* @returns ME Squared for qqbarb Tree-Level Current-Current Scattering
*
* @note calculate forwards qqbar contribution by reversing argument ordering.
*/
double
ME_W_qqbar_current
(
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
pq
,
CLHEP
::
HepLorentzVector
const
&
pqbar
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
bool
const
wc
,
ParticleProperties
const
&
Wprop
){
using
namespace
currents
;
if
(
is_anyquark
(
bptype
)
&&
wc
)
{
// W Must be emitted from forwards leg.
const
double
t1
=
(
pa
-
pq
-
pqbar
).
m2
();
const
double
tn
=
(
pb
-
pn
-
pl
-
plbar
).
m2
();
return
K_q
*
K_q
*
ME_W_Exqqbar_QQq
(
pb
,
pa
,
pn
,
pq
,
pqbar
,
plbar
,
pl
,
is_antiquark
(
bptype
),
Wprop
)
/
(
4.
*
(
N_C
*
N_C
-
1
)
*
t1
*
tn
);
}
const
double
t1
=
(
pa
-
pl
-
plbar
-
pq
-
pqbar
).
m2
();
const
double
tn
=
(
pb
-
pn
).
m2
();
return
K
(
bptype
,
pn
,
pb
)
/
C_F
*
ME_WExqqbar_qqbarQ
(
pa
,
pqbar
,
plbar
,
pl
,
pq
,
pn
,
pb
,
Wprop
)
/
(
t1
*
tn
);
}
/* \brief Matrix element squared for central qqbar tree-level current-current
* scattering With W+Jets
*
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param nabove Number of gluons emitted before central qqbarpair
* @param nbelow Number of gluons emitted after central qqbarpair
* @param pa Initial state a Momentum
* @param pb Initial state b Momentum\
* @param partons Vector of all outgoing partons
* @param plbar Final state anti-lepton momentum
* @param pl Final state lepton momentum
* @param qbar_first Ordering of the qqbar pair (true: qbar-q, false: q-qbar)
* @param wqq Boolean. True siginfies W boson is emitted from Central qqbar
* @param wc Boolean. wc=true signifies w boson emitted from leg b; if wqq=false.
* @returns ME Squared for qqbar_mid Tree-Level Current-Current Scattering
*/
double
ME_W_qqbar_mid_current
(
ParticleID
aptype
,
ParticleID
bptype
,
int
nabove
,
int
nbelow
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
CLHEP
::
HepLorentzVector
>
const
&
partons
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
bool
const
qbar_first
,
bool
const
wqq
,
bool
const
wc
,
ParticleProperties
const
&
Wprop
){
using
namespace
currents
;
const
double
wt
=
K
(
aptype
,
partons
.
front
(),
pa
)
*
K
(
bptype
,
partons
.
back
(),
pb
)
/
(
4.
*
(
N_C
*
N_C
-
1
));
if
(
wqq
)
return
wt
*
ME_WCenqqbar_qq
(
pa
,
pb
,
pl
,
plbar
,
partons
,
is_antiquark
(
aptype
),
is_antiquark
(
bptype
),
qbar_first
,
nabove
,
Wprop
);
return
wt
*
ME_W_Cenqqbar_qq
(
pa
,
pb
,
pl
,
plbar
,
partons
,
is_antiquark
(
aptype
),
is_antiquark
(
bptype
),
qbar_first
,
nabove
,
nbelow
,
wc
,
Wprop
);
}
/** Matrix element squared for tree-level current-current scattering With Z+Jets
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param plbar Final state positron momentum
* @param pl Final state electron momentum
* @param Zprop Z properties
* @param stw2 Value of sin(theta_w)^2
* @param ctw Value of cos(theta_w)
* @returns ME Squared for Tree-Level Current-Current Scattering
*/
std
::
vector
<
double
>
ME_Z_current
(
const
ParticleID
aptype
,
const
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
using
namespace
currents
;
const
auto
pZ
=
pl
+
plbar
;
const
double
pref
=
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
/
(
4.
*
(
N_C
*
N_C
-
1
));
// we know they are not both gluons
assert
(
!
is_gluon
(
aptype
)
||
!
is_gluon
(
bptype
));
if
(
is_anyquark
(
aptype
)
&&
is_gluon
(
bptype
)){
// This is a qg event
const
double
t1
=
(
pa
-
p1
-
pZ
).
m2
();
const
double
tn
=
(
pb
-
pn
).
m2
();
return
{
pref
*
ME_Z_qg
(
pa
,
pb
,
p1
,
pn
,
plbar
,
pl
,
aptype
,
bptype
,
Zprop
,
stw2
,
ctw
)
/
(
t1
*
tn
)
};
}
if
(
is_gluon
(
aptype
)
&&
is_anyquark
(
bptype
)){
// This is a gq event
const
double
t1
=
(
pa
-
p1
).
m2
();
const
double
tn
=
(
pb
-
pn
-
pZ
).
m2
();
return
{
pref
*
ME_Z_qg
(
pb
,
pa
,
pn
,
p1
,
plbar
,
pl
,
bptype
,
aptype
,
Zprop
,
stw2
,
ctw
)
/
(
t1
*
tn
)
};
}
// This is a qq event
assert
(
is_anyquark
(
aptype
)
&&
is_anyquark
(
bptype
));
const
double
t1_top
=
(
pa
-
p1
-
pZ
).
m2
();
const
double
t2_top
=
(
pb
-
pn
).
m2
();
const
double
t1_bot
=
(
pa
-
p1
).
m2
();
const
double
t2_bot
=
(
pb
-
pn
-
pZ
).
m2
();
std
::
vector
<
double
>
res
=
ME_Z_qQ
(
pa
,
pb
,
p1
,
pn
,
plbar
,
pl
,
aptype
,
bptype
,
Zprop
,
stw2
,
ctw
);
assert
(
res
.
size
()
==
3
);
res
[
0
]
*=
pref
/
(
t1_top
*
t2_top
);
res
[
1
]
*=
pref
/
(
t1_bot
*
t2_bot
);
res
[
2
]
*=
pref
/
sqrt
(
t1_top
*
t2_top
*
t1_bot
*
t2_bot
);
return
res
;
}
/** Matrix element squared for backwards uno tree-level current-current
* scattering With Z+Jets
*
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param pg Unordered gluon momentum
* @param plbar Final state positron momentum
* @param pl Final state electron momentum
* @param Zprop Z properties
* @param stw2 Value of sin(theta_w)^2
* @param ctw Value of cos(theta_w)
* @returns ME Squared for unob Tree-Level Current-Current Scattering
*
* @note The unof contribution can be calculated by reversing the argument ordering.
*/
std
::
vector
<
double
>
ME_Z_uno_current
(
const
ParticleID
aptype
,
const
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pg
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
using
namespace
currents
;
const
auto
pZ
=
pl
+
plbar
;
const
double
pref
=
K
(
aptype
,
p1
,
pa
)
/
C_F
*
K
(
bptype
,
pn
,
pb
)
/
C_F
;
// we only evaluate unordered backward -> first incoming particle must be a quark
assert
(
is_anyquark
(
aptype
));
const
double
t1_top
=
(
pa
-
pg
-
p1
-
pZ
).
m2
();
const
double
t2_top
=
(
pb
-
pn
).
m2
();
if
(
is_gluon
(
bptype
))
{
// This is a qg event -> Z emission from top leg
return
{
pref
*
ME_Zuno_qg
(
pa
,
pb
,
pg
,
p1
,
pn
,
plbar
,
pl
,
aptype
,
bptype
,
Zprop
,
stw2
,
ctw
)
/
(
t1_top
*
t2_top
)
};
}
// This is a qq event
assert
(
is_anyquark
(
bptype
));
const
double
t1_bot
=
(
pa
-
pg
-
p1
).
m2
();
const
double
t2_bot
=
(
pb
-
pn
-
pZ
).
m2
();
std
::
vector
<
double
>
res
=
ME_Zuno_qQ
(
pa
,
pb
,
pg
,
p1
,
pn
,
plbar
,
pl
,
aptype
,
bptype
,
Zprop
,
stw2
,
ctw
);
assert
(
res
.
size
()
==
3
);
res
[
0
]
*=
pref
/
(
t1_top
*
t2_top
);
res
[
1
]
*=
pref
/
(
t1_bot
*
t2_bot
);
res
[
2
]
*=
pref
/
sqrt
(
t1_top
*
t2_top
*
t1_bot
*
t2_bot
);
return
res
;
}
/** Matrix element squared for backwards extremal qqbar tree-level current-current
* scattering With Z+Jets
*
* @param qptype PDG ID of final state quark in qqbar pair
* @param bptype Incoming particle b PDG ID
* @param pa Incoming particle a momentum
* @param pb Incoming particle b momentum
* @param pq Final state quark momentum
* @param pqbar Final state anti-quark momentum
* @param pn Final state particle n momentum
* @param plbar Final state positron momentum
* @param pl Final state electron momentum
* @param Zprop Z properties
* @param stw2 Value of sin(theta_w)^2
* @param ctw Value of cos(theta_w)
* @returns ME Squared for qqbar_exb Tree-Level Current-Current Scattering
*
* @note The qqbar_exf contribution can be calculated by reversing the argument ordering.
*/
std
::
vector
<
double
>
ME_Z_qqbar_current
(
const
ParticleID
qptype
,
const
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
pq
,
CLHEP
::
HepLorentzVector
const
&
pqbar
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
using
namespace
currents
;
const
auto
pZ
=
pl
+
plbar
;
const
double
t1_top
=
(
pa
-
pq
-
pqbar
-
pZ
).
m2
();
const
double
t2_top
=
(
pb
-
pn
).
m2
();
if
(
is_gluon
(
bptype
))
{
// This is a gg event -> Z emission from top leg
return
{
K
(
bptype
,
pn
,
pb
)
/
C_F
*
ME_ZExqqbar_gg
(
pa
,
pb
,
pq
,
pqbar
,
pn
,
plbar
,
pl
,
qptype
,
Zprop
,
stw2
,
ctw
)
/
(
t1_top
*
t2_top
)
};
}
// This is a gq event
assert
(
is_anyquark
(
bptype
));
const
double
t1_bot
=
(
pa
-
pq
-
pqbar
).
m2
();
const
double
t2_bot
=
(
pb
-
pn
-
pZ
).
m2
();
std
::
vector
<
double
>
res
=
ME_ZExqqbar_gq
(
pa
,
pb
,
pq
,
pqbar
,
pn
,
plbar
,
pl
,
qptype
,
bptype
,
Zprop
,
stw2
,
ctw
);
assert
(
res
.
size
()
==
3
);
res
[
0
]
/=
(
t1_top
*
t2_top
);
res
[
1
]
/=
(
t1_bot
*
t2_bot
);
res
[
2
]
/=
sqrt
(
t1_top
*
t2_top
*
t1_bot
*
t2_bot
);
return
res
;
}
/** \brief Matrix element squared for tree-level current-current scattering with Higgs
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param qH t-channel momentum before Higgs
* @param qHp1 t-channel momentum after Higgs
* @returns ME Squared for Tree-Level Current-Current Scattering with Higgs
*/
double
ME_Higgs_current
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
qH
,
// t-channel momentum before Higgs
CLHEP
::
HepLorentzVector
const
&
qHp1
,
// t-channel momentum after Higgs
double
mt
,
bool
include_bottom
,
double
mb
,
double
vev
){
const
double
t1
=
(
pa
-
p1
).
m2
();
const
double
tn
=
(
pb
-
pn
).
m2
();
return
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
*
currents
::
ME_H_qQ
(
pn
,
pb
,
p1
,
pa
,
-
qHp1
,
-
qH
,
mt
,
include_bottom
,
mb
,
vev
)
/
(
t1
*
tn
*
qH
.
m2
()
*
qHp1
.
m2
());
}
/** \brief Current matrix element squared with Higgs and unordered backward emission
* @param aptype Particle A PDG ID
* @param bptype Particle B PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param pg Unordered back Particle Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param qH t-channel momentum before Higgs
* @param qHp1 t-channel momentum after Higgs
* @returns ME Squared with Higgs and unordered backward emission
*
* @note This function assumes unordered gluon backwards from pa-p1 current.
* For unof, reverse call order
*/
double
ME_Higgs_current_uno
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pg
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
qH
,
// t-channel momentum before Higgs
CLHEP
::
HepLorentzVector
const
&
qHp1
,
// t-channel momentum after Higgs
double
mt
,
bool
include_bottom
,
double
mb
,
double
vev
){
const
double
t1
=
(
pa
-
p1
-
pg
).
m2
();
const
double
tn
=
(
pn
-
pb
).
m2
();
return
K
(
aptype
,
p1
,
pa
)
*
K
(
bptype
,
pn
,
pb
)
*
currents
::
ME_H_unob_qQ
(
pg
,
p1
,
pa
,
pn
,
pb
,
-
qH
,
-
qHp1
,
mt
,
include_bottom
,
mb
,
vev
)
/
(
t1
*
qH
.
m2
()
*
qHp1
.
m2
()
*
tn
);
}
/** Matrix element squared for tree-level scattering with WW+Jets
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param pl1bar Particle l1bar Momentum
* @param pl1 Particle l1 Momentum
* @param pl2bar Particle l2bar Momentum
* @param pl2 Particle l2 Momentum
* @returns ME Squared for Tree-Level Current-Current Scattering
*/
std
::
vector
<
double
>
ME_WW_current
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pn
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pl1bar
,
CLHEP
::
HepLorentzVector
const
&
pl1
,
CLHEP
::
HepLorentzVector
const
&
pl2bar
,
CLHEP
::
HepLorentzVector
const
&
pl2
,
ParticleProperties
const
&
Wprop
){
using
namespace
currents
;
if
(
aptype
>
0
&&
bptype
>
0
)
return
ME_WW_qQ
(
p1
,
pl1bar
,
pl1
,
pa
,
pn
,
pl2bar
,
pl2
,
pb
,
Wprop
);
if
(
aptype
<
0
&&
bptype
>
0
)
return
ME_WW_qbarQ
(
p1
,
pl1bar
,
pl1
,
pa
,
pn
,
pl2bar
,
pl2
,
pb
,
Wprop
);
if
(
aptype
>
0
&&
bptype
<
0
)
return
ME_WW_qQbar
(
p1
,
pl1bar
,
pl1
,
pa
,
pn
,
pl2bar
,
pl2
,
pb
,
Wprop
);
if
(
aptype
<
0
&&
bptype
<
0
)
return
ME_WW_qbarQbar
(
p1
,
pl1bar
,
pl1
,
pa
,
pn
,
pl2bar
,
pl2
,
pb
,
Wprop
);
throw
std
::
logic_error
(
"unreachable"
);
}
void
validate
(
MatrixElementConfig
const
&
config
)
{
#ifndef HEJ_BUILD_WITH_QCDLOOP
if
(
!
config
.
Higgs_coupling
.
use_impact_factors
)
{
throw
std
::
invalid_argument
{
"Invalid Higgs coupling settings.
\n
"
"HEJ without QCDloop support can only use impact factors.
\n
"
"Set use_impact_factors to true or recompile HEJ.
\n
"
};
}
#endif
if
(
config
.
Higgs_coupling
.
use_impact_factors
&&
config
.
Higgs_coupling
.
mt
!=
std
::
numeric_limits
<
double
>::
infinity
())
{
throw
std
::
invalid_argument
{
"Conflicting settings: "
"impact factors may only be used in the infinite top mass limit"
};
}
}
}
// namespace
MatrixElement
::
MatrixElement
(
std
::
function
<
double
(
double
)
>
alpha_s
,
MatrixElementConfig
conf
)
:
alpha_s_
{
std
::
move
(
alpha_s
)},
param_
{
std
::
move
(
conf
)}
{
validate
(
param_
);
}
std
::
vector
<
double
>
MatrixElement
::
tree_kin
(
Event
const
&
ev
)
const
{
if
(
!
ev
.
valid_hej_state
(
param_
.
soft_pt_regulator
))
return
{
0.
};
if
(
!
ev
.
valid_incoming
()){
throw
std
::
invalid_argument
{
"Invalid momentum for one or more incoming particles. "
"Incoming momenta must have vanishing mass and transverse momentum."
};
}
std
::
vector
<
Particle
>
bosons
=
filter_AWZH_bosons
(
ev
.
outgoing
());
if
(
bosons
.
empty
())
{
return
{
tree_kin_jets
(
ev
)};
}
if
(
bosons
.
size
()
==
1
)
{
switch
(
bosons
[
0
].
type
){
case
pid
::
Higgs
:
return
{
tree_kin_Higgs
(
ev
)};
case
pid
::
Wp
:
case
pid
::
Wm
:
return
{
tree_kin_W
(
ev
)};
case
pid
::
Z_photon_mix
:
return
tree_kin_Z
(
ev
);
// TODO
case
pid
::
photon
:
case
pid
::
Z
:
default
:
throw
not_implemented
(
"Emission of boson of unsupported type"
);
}
}
if
(
bosons
.
size
()
==
2
)
{
if
(
bosons
[
0
].
type
==
pid
::
Wp
&&
bosons
[
1
].
type
==
pid
::
Wp
){
return
tree_kin_WW
(
ev
);
}
else
if
(
bosons
[
0
].
type
==
pid
::
Wm
&&
bosons
[
1
].
type
==
pid
::
Wm
){
return
tree_kin_WW
(
ev
);
}
throw
not_implemented
(
"Emission of bosons of unsupported type"
);
}
throw
not_implemented
(
"Emission of >2 bosons is unsupported"
);
}
namespace
{
constexpr
int
EXTREMAL_JET_IDX
=
1
;
constexpr
int
NO_EXTREMAL_JET_IDX
=
0
;
bool
treat_as_extremal
(
Particle
const
&
parton
){
return
parton
.
p
.
user_index
()
==
EXTREMAL_JET_IDX
;
}
template
<
class
InputIterator
>
double
FKL_ladder_weight
(
InputIterator
begin_gluon
,
InputIterator
end_gluon
,
CLHEP
::
HepLorentzVector
const
&
q0
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pn
,
double
lambda
){
double
wt
=
1
;
auto
qi
=
q0
;
for
(
auto
gluon_it
=
begin_gluon
;
gluon_it
!=
end_gluon
;
++
gluon_it
){
assert
(
gluon_it
->
type
==
pid
::
gluon
);
const
auto
g
=
to_HepLorentzVector
(
*
gluon_it
);
const
auto
qip1
=
qi
-
g
;
if
(
treat_as_extremal
(
*
gluon_it
)){
wt
*=
C2Lipatovots
(
qip1
,
qi
,
pa
,
pb
,
lambda
)
*
C_A
;
}
else
{
wt
*=
C2Lipatovots
(
qip1
,
qi
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
C_A
;
}
qi
=
qip1
;
}
return
wt
;
}
template
<
class
InputIterator
>
std
::
vector
<
double
>
FKL_ladder_weight_mix
(
InputIterator
begin_gluon
,
InputIterator
end_gluon
,
CLHEP
::
HepLorentzVector
const
&
q0_t
,
CLHEP
::
HepLorentzVector
const
&
q0_b
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pn
,
const
double
lambda
){
double
wt_top
=
1
;
double
wt_bot
=
1
;
double
wt_mix
=
1
;
auto
qi_t
=
q0_t
;
auto
qi_b
=
q0_b
;
for
(
auto
gluon_it
=
begin_gluon
;
gluon_it
!=
end_gluon
;
++
gluon_it
){
assert
(
gluon_it
->
type
==
pid
::
gluon
);
const
auto
g
=
to_HepLorentzVector
(
*
gluon_it
);
const
auto
qip1_t
=
qi_t
-
g
;
const
auto
qip1_b
=
qi_b
-
g
;
if
(
treat_as_extremal
(
*
gluon_it
)){
wt_top
*=
C2Lipatovots
(
qip1_t
,
qi_t
,
pa
,
pb
,
lambda
)
*
C_A
;
wt_bot
*=
C2Lipatovots
(
qip1_b
,
qi_b
,
pa
,
pb
,
lambda
)
*
C_A
;
wt_mix
*=
C2Lipatovots_Mix
(
qip1_t
,
qi_t
,
qip1_b
,
qi_b
,
pa
,
pb
,
lambda
)
*
C_A
;
}
else
{
wt_top
*=
C2Lipatovots
(
qip1_t
,
qi_t
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
C_A
;
wt_bot
*=
C2Lipatovots
(
qip1_b
,
qi_b
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
C_A
;
wt_mix
*=
C2Lipatovots_Mix
(
qip1_t
,
qi_t
,
qip1_b
,
qi_b
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
C_A
;
}
qi_t
=
qip1_t
;
qi_b
=
qip1_b
;
}
return
{
wt_top
,
wt_bot
,
wt_mix
};
}
std
::
vector
<
Particle
>
tag_extremal_jet_partons
(
Event
const
&
ev
){
auto
out_partons
=
filter_partons
(
ev
.
outgoing
());
if
(
out_partons
.
size
()
==
ev
.
jets
().
size
()){
// no additional emissions in extremal jets, don't need to tag anything
for
(
auto
&
parton
:
out_partons
){
parton
.
p
.
set_user_index
(
NO_EXTREMAL_JET_IDX
);
}
return
out_partons
;
}
auto
const
&
jets
=
ev
.
jets
();
std
::
vector
<
fastjet
::
PseudoJet
>
extremal_jets
;
if
(
!
is_backward_g_to_h
(
ev
))
{
auto
most_backward
=
begin
(
jets
);
// skip jets caused by unordered emission or qqbar
if
(
ev
.
type
()
==
event_type
::
unob
||
ev
.
type
()
==
event_type
::
qqbar_exb
){
assert
(
jets
.
size
()
>=
2
);
++
most_backward
;
}
extremal_jets
.
emplace_back
(
*
most_backward
);
}
if
(
!
is_forward_g_to_h
(
ev
))
{
auto
most_forward
=
end
(
jets
)
-
1
;
if
(
ev
.
type
()
==
event_type
::
unof
||
ev
.
type
()
==
event_type
::
qqbar_exf
){
assert
(
jets
.
size
()
>=
2
);
--
most_forward
;
}
extremal_jets
.
emplace_back
(
*
most_forward
);
}
const
auto
extremal_jet_indices
=
ev
.
particle_jet_indices
(
extremal_jets
);
assert
(
extremal_jet_indices
.
size
()
==
out_partons
.
size
());
for
(
std
::
size_t
i
=
0
;
i
<
out_partons
.
size
();
++
i
){
assert
(
is_parton
(
out_partons
[
i
]));
const
int
idx
=
(
extremal_jet_indices
[
i
]
>=
0
)
?
EXTREMAL_JET_IDX
:
NO_EXTREMAL_JET_IDX
;
out_partons
[
i
].
p
.
set_user_index
(
idx
);
}
return
out_partons
;
}
double
tree_kin_jets_qqbar_mid
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
Particle
>
const
&
partons
,
double
lambda
){
const
auto
backmidquark
=
std
::
find_if
(
begin
(
partons
)
+
1
,
end
(
partons
)
-
1
,
[](
Particle
const
&
s
){
return
s
.
type
!=
pid
::
gluon
;
}
);
assert
(
backmidquark
!=
end
(
partons
)
-
1
);
const
bool
qbar_first
=
is_antiquark
(
backmidquark
->
type
);
const
auto
pq
=
to_HepLorentzVector
(
*
(
backmidquark
+
(
qbar_first
?
1
:
0
)));
const
auto
pqbar
=
to_HepLorentzVector
(
*
(
backmidquark
+
(
qbar_first
?
0
:
1
)));
const
auto
p1
=
to_HepLorentzVector
(
partons
[
0
]);
const
auto
pn
=
to_HepLorentzVector
(
partons
[
partons
.
size
()
-
1
]);
const
auto
begin_ladder_1
=
cbegin
(
partons
)
+
1
;
const
auto
end_ladder_1
=
(
backmidquark
);
const
auto
begin_ladder_2
=
(
backmidquark
+
2
);
const
auto
end_ladder_2
=
cend
(
partons
)
-
1
;
const
int
nabove
=
std
::
distance
(
begin_ladder_1
,
end_ladder_1
);
const
auto
q0
=
pa
-
p1
;
// t-channel momentum after qqbar
auto
q3
=
q0
;
for
(
auto
parton_it
=
begin_ladder_1
;
parton_it
!=
begin_ladder_2
;
++
parton_it
){
q3
-=
to_HepLorentzVector
(
*
parton_it
);
}
std
::
vector
<
CLHEP
::
HepLorentzVector
>
partonsHLV
;
partonsHLV
.
reserve
(
partons
.
size
());
for
(
Particle
const
&
parton
:
partons
)
{
partonsHLV
.
push_back
(
to_HepLorentzVector
(
parton
));
}
const
double
current_factor
=
ME_qqbar_mid_current
(
aptype
,
bptype
,
nabove
,
pa
,
pb
,
partonsHLV
,
qbar_first
);
const
double
ladder_factor
=
FKL_ladder_weight
(
begin_ladder_1
,
end_ladder_1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
FKL_ladder_weight
(
begin_ladder_2
,
end_ladder_2
,
q3
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
template
<
class
InIter
,
class
partIter
>
double
tree_kin_jets_qqbar
(
InIter
BeginIn
,
InIter
EndIn
,
partIter
BeginPart
,
partIter
EndPart
,
double
lambda
){
const
auto
pgin
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
EndIn
-
1
));
const
auto
p1
=
to_HepLorentzVector
(
*
BeginPart
);
const
auto
p2
=
to_HepLorentzVector
(
*
(
BeginPart
+
1
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
assert
((
BeginIn
)
->
type
==
pid
::
gluon
);
// Incoming a must be gluon.
const
double
current_factor
=
ME_qqbar_current
(
(
EndIn
-
1
)
->
type
,
pgin
,
p1
,
p2
,
pn
,
pb
)
/
(
4.
*
(
N_C
*
N_C
-
1.
));
const
double
ladder_factor
=
FKL_ladder_weight
(
(
BeginPart
+
2
),
(
EndPart
-
1
),
pgin
-
p1
-
p2
,
pgin
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
template
<
class
InIter
,
class
partIter
>
double
tree_kin_jets_uno
(
InIter
BeginIn
,
InIter
EndIn
,
partIter
BeginPart
,
partIter
EndPart
,
double
lambda
){
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
EndIn
-
1
));
const
auto
pg
=
to_HepLorentzVector
(
*
BeginPart
);
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
+
1
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
const
double
current_factor
=
ME_uno_current
(
(
BeginIn
)
->
type
,
(
EndIn
-
1
)
->
type
,
pg
,
pn
,
pb
,
p1
,
pa
)
/
(
4.
*
(
N_C
*
N_C
-
1.
));
const
double
ladder_factor
=
FKL_ladder_weight
(
(
BeginPart
+
2
),
(
EndPart
-
1
),
pa
-
p1
-
pg
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
}
// namespace
double
MatrixElement
::
tree_kin_jets
(
Event
const
&
ev
)
const
{
auto
const
&
incoming
=
ev
.
incoming
();
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
if
(
ev
.
type
()
==
event_type
::
FKL
){
const
auto
pa
=
to_HepLorentzVector
(
incoming
[
0
]);
const
auto
pb
=
to_HepLorentzVector
(
incoming
[
1
]);
const
auto
p1
=
to_HepLorentzVector
(
partons
.
front
());
const
auto
pn
=
to_HepLorentzVector
(
partons
.
back
());
return
ME_current
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pn
,
pb
,
p1
,
pa
)
/
(
4.
*
(
N_C
*
N_C
-
1.
))
*
FKL_ladder_weight
(
begin
(
partons
)
+
1
,
end
(
partons
)
-
1
,
pa
-
p1
,
pa
,
pb
,
p1
,
pn
,
param_
.
regulator_lambda
);
}
if
(
ev
.
type
()
==
event_type
::
unordered_backward
){
return
tree_kin_jets_uno
(
incoming
.
begin
(),
incoming
.
end
(),
partons
.
begin
(),
partons
.
end
(),
param_
.
regulator_lambda
);
}
if
(
ev
.
type
()
==
event_type
::
unordered_forward
){
return
tree_kin_jets_uno
(
incoming
.
rbegin
(),
incoming
.
rend
(),
partons
.
rbegin
(),
partons
.
rend
(),
param_
.
regulator_lambda
);
}
if
(
ev
.
type
()
==
event_type
::
extremal_qqbar_backward
){
return
tree_kin_jets_qqbar
(
incoming
.
begin
(),
incoming
.
end
(),
partons
.
begin
(),
partons
.
end
(),
param_
.
regulator_lambda
);
}
if
(
ev
.
type
()
==
event_type
::
extremal_qqbar_forward
){
return
tree_kin_jets_qqbar
(
incoming
.
rbegin
(),
incoming
.
rend
(),
partons
.
rbegin
(),
partons
.
rend
(),
param_
.
regulator_lambda
);
}
if
(
ev
.
type
()
==
event_type
::
central_qqbar
){
return
tree_kin_jets_qqbar_mid
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
to_HepLorentzVector
(
incoming
[
0
]),
to_HepLorentzVector
(
incoming
[
1
]),
partons
,
param_
.
regulator_lambda
);
}
throw
std
::
logic_error
(
"Cannot reweight non-resummable processes in Pure Jets"
);
}
namespace
{
double
tree_kin_W_FKL
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
Particle
>
const
&
partons
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
double
lambda
,
ParticleProperties
const
&
Wprop
){
auto
p1
=
to_HepLorentzVector
(
partons
[
0
]);
auto
pn
=
to_HepLorentzVector
(
partons
[
partons
.
size
()
-
1
]);
const
auto
begin_ladder
=
cbegin
(
partons
)
+
1
;
const
auto
end_ladder
=
cend
(
partons
)
-
1
;
bool
wc
=
aptype
==
partons
[
0
].
type
;
//leg b emits w
auto
q0
=
pa
-
p1
;
if
(
!
wc
)
q0
-=
pl
+
plbar
;
const
double
current_factor
=
ME_W_current
(
aptype
,
bptype
,
pn
,
pb
,
p1
,
pa
,
plbar
,
pl
,
wc
,
Wprop
);
const
double
ladder_factor
=
FKL_ladder_weight
(
begin_ladder
,
end_ladder
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
template
<
class
InIter
,
class
partIter
>
double
tree_kin_W_uno
(
InIter
BeginIn
,
partIter
BeginPart
,
partIter
EndPart
,
const
CLHEP
::
HepLorentzVector
&
plbar
,
const
CLHEP
::
HepLorentzVector
&
pl
,
double
lambda
,
ParticleProperties
const
&
Wprop
){
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
BeginIn
+
1
));
const
auto
pg
=
to_HepLorentzVector
(
*
BeginPart
);
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
+
1
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
bool
wc
=
(
BeginIn
)
->
type
==
(
BeginPart
+
1
)
->
type
;
//leg b emits w
auto
q0
=
pa
-
p1
-
pg
;
if
(
!
wc
)
q0
-=
pl
+
plbar
;
const
double
current_factor
=
ME_W_uno_current
(
(
BeginIn
)
->
type
,
(
BeginIn
+
1
)
->
type
,
pn
,
pb
,
p1
,
pa
,
pg
,
plbar
,
pl
,
wc
,
Wprop
);
const
double
ladder_factor
=
FKL_ladder_weight
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
template
<
class
InIter
,
class
partIter
>
double
tree_kin_W_qqbar
(
InIter
BeginIn
,
partIter
BeginPart
,
partIter
EndPart
,
const
CLHEP
::
HepLorentzVector
&
plbar
,
const
CLHEP
::
HepLorentzVector
&
pl
,
double
lambda
,
ParticleProperties
const
&
Wprop
){
const
bool
qbar_first
=
is_quark
(
*
BeginPart
);
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
BeginIn
+
1
));
const
auto
pq
=
to_HepLorentzVector
(
*
(
BeginPart
+
(
qbar_first
?
0
:
1
)));
const
auto
pqbar
=
to_HepLorentzVector
(
*
(
BeginPart
+
(
qbar_first
?
1
:
0
)));
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
const
bool
wc
=
(
BeginIn
+
1
)
->
type
!=
(
EndPart
-
1
)
->
type
;
//leg b emits w
auto
q0
=
pa
-
pq
-
pqbar
;
if
(
!
wc
)
q0
-=
pl
+
plbar
;
const
double
current_factor
=
ME_W_qqbar_current
(
(
BeginIn
+
1
)
->
type
,
pa
,
pb
,
pq
,
pqbar
,
pn
,
plbar
,
pl
,
wc
,
Wprop
);
const
double
ladder_factor
=
FKL_ladder_weight
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
double
tree_kin_W_qqbar_mid
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
Particle
>
const
&
partons
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
double
lambda
,
ParticleProperties
const
&
Wprop
){
const
auto
backmidquark
=
std
::
find_if
(
begin
(
partons
)
+
1
,
end
(
partons
)
-
1
,
[](
Particle
const
&
s
){
return
s
.
type
!=
pid
::
gluon
;
}
);
assert
(
backmidquark
!=
end
(
partons
)
-
1
);
const
bool
qbar_first
=
is_antiquark
(
backmidquark
->
type
);
const
auto
pq
=
to_HepLorentzVector
(
*
(
backmidquark
+
(
qbar_first
?
1
:
0
)));
const
auto
pqbar
=
to_HepLorentzVector
(
*
(
backmidquark
+
(
qbar_first
?
0
:
1
)));
const
auto
p1
=
to_HepLorentzVector
(
partons
.
front
());
const
auto
pn
=
to_HepLorentzVector
(
partons
.
back
());
const
auto
begin_ladder_1
=
cbegin
(
partons
)
+
1
;
const
auto
end_ladder_1
=
(
backmidquark
);
const
auto
begin_ladder_2
=
(
backmidquark
+
2
);
const
auto
end_ladder_2
=
cend
(
partons
)
-
1
;
const
int
nabove
=
std
::
distance
(
begin_ladder_1
,
end_ladder_1
);
const
int
nbelow
=
std
::
distance
(
begin_ladder_2
,
end_ladder_2
);
const
bool
wqq
=
backmidquark
->
type
!=
-
(
backmidquark
+
1
)
->
type
;
// qqbar emit W
const
bool
wc
=
!
wqq
&&
(
aptype
==
partons
.
front
().
type
);
//leg b emits w
assert
(
!
wqq
||
!
wc
);
auto
q0
=
pa
-
p1
;
// t-channel momentum after qqbar
auto
q3
=
q0
;
if
(
wqq
){
// emission from qqbar
q3
-=
pl
+
plbar
;
}
else
if
(
!
wc
)
{
// emission from leg a
q0
-=
pl
+
plbar
;
q3
-=
pl
+
plbar
;
}
for
(
auto
parton_it
=
begin_ladder_1
;
parton_it
!=
begin_ladder_2
;
++
parton_it
){
q3
-=
to_HepLorentzVector
(
*
parton_it
);
}
std
::
vector
<
CLHEP
::
HepLorentzVector
>
partonsHLV
;
partonsHLV
.
reserve
(
partons
.
size
());
for
(
Particle
const
&
parton
:
partons
)
{
partonsHLV
.
push_back
(
to_HepLorentzVector
(
parton
));
}
const
double
current_factor
=
ME_W_qqbar_mid_current
(
aptype
,
bptype
,
nabove
,
nbelow
,
pa
,
pb
,
partonsHLV
,
plbar
,
pl
,
qbar_first
,
wqq
,
wc
,
Wprop
);
const
double
ladder_factor
=
FKL_ladder_weight
(
begin_ladder_1
,
end_ladder_1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
)
*
FKL_ladder_weight
(
begin_ladder_2
,
end_ladder_2
,
q3
,
pa
,
pb
,
p1
,
pn
,
lambda
);
return
current_factor
*
ladder_factor
;
}
}
// namespace
double
MatrixElement
::
tree_kin_W
(
Event
const
&
ev
)
const
{
using
namespace
event_type
;
auto
const
&
incoming
(
ev
.
incoming
());
#ifndef NDEBUG
// assert that there is exactly one decay corresponding to the W
assert
(
ev
.
decays
().
size
()
==
1
);
auto
const
&
w_boson
{
std
::
find_if
(
ev
.
outgoing
().
cbegin
(),
ev
.
outgoing
().
cend
(),
[]
(
Particle
const
&
p
)
->
bool
{
return
std
::
abs
(
p
.
type
)
==
ParticleID
::
Wp
;
})
};
assert
(
w_boson
!=
ev
.
outgoing
().
cend
());
assert
(
static_cast
<
long
int
>
(
ev
.
decays
().
cbegin
()
->
first
)
==
std
::
distance
(
ev
.
outgoing
().
cbegin
(),
w_boson
)
);
#endif
// find decay products of W
auto
const
&
decay
{
ev
.
decays
().
cbegin
()
->
second
};
assert
(
decay
.
size
()
==
2
);
assert
(
(
is_anylepton
(
decay
.
at
(
0
))
&&
is_anyneutrino
(
decay
.
at
(
1
))
)
||
(
is_anylepton
(
decay
.
at
(
1
))
&&
is_anyneutrino
(
decay
.
at
(
0
))
)
);
// get lepton & neutrino
CLHEP
::
HepLorentzVector
plbar
;
CLHEP
::
HepLorentzVector
pl
;
if
(
decay
.
at
(
0
).
type
<
0
){
plbar
=
to_HepLorentzVector
(
decay
.
at
(
0
));
pl
=
to_HepLorentzVector
(
decay
.
at
(
1
));
}
else
{
pl
=
to_HepLorentzVector
(
decay
.
at
(
0
));
plbar
=
to_HepLorentzVector
(
decay
.
at
(
1
));
}
const
auto
pa
=
to_HepLorentzVector
(
incoming
[
0
]);
const
auto
pb
=
to_HepLorentzVector
(
incoming
[
1
]);
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
if
(
ev
.
type
()
==
FKL
){
return
tree_kin_W_FKL
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pa
,
pb
,
partons
,
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
if
(
ev
.
type
()
==
unordered_backward
){
return
tree_kin_W_uno
(
cbegin
(
incoming
),
cbegin
(
partons
),
cend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
if
(
ev
.
type
()
==
unordered_forward
){
return
tree_kin_W_uno
(
crbegin
(
incoming
),
crbegin
(
partons
),
crend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
if
(
ev
.
type
()
==
extremal_qqbar_backward
){
return
tree_kin_W_qqbar
(
cbegin
(
incoming
),
cbegin
(
partons
),
cend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
if
(
ev
.
type
()
==
extremal_qqbar_forward
){
return
tree_kin_W_qqbar
(
crbegin
(
incoming
),
crbegin
(
partons
),
crend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
assert
(
ev
.
type
()
==
central_qqbar
);
return
tree_kin_W_qqbar_mid
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pa
,
pb
,
partons
,
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
());
}
namespace
/* WW */
{
std
::
vector
<
double
>
tree_kin_WW_FKL
(
ParticleID
aptype
,
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
Particle
>
const
&
partons
,
CLHEP
::
HepLorentzVector
const
&
pl1bar
,
CLHEP
::
HepLorentzVector
const
&
pl1
,
CLHEP
::
HepLorentzVector
const
&
pl2bar
,
CLHEP
::
HepLorentzVector
const
&
pl2
,
double
lambda
,
ParticleProperties
const
&
Wprop
){
assert
(
is_anyquark
(
aptype
));
assert
(
is_anyquark
(
bptype
));
auto
p1
=
to_HepLorentzVector
(
partons
[
0
]);
auto
pn
=
to_HepLorentzVector
(
partons
[
partons
.
size
()
-
1
]);
const
std
::
vector
<
double
>
current_factor
=
ME_WW_current
(
aptype
,
bptype
,
pn
,
pb
,
p1
,
pa
,
pl1bar
,
pl1
,
pl2bar
,
pl2
,
Wprop
);
auto
const
begin_ladder
=
cbegin
(
partons
)
+
1
;
auto
const
end_ladder
=
cend
(
partons
)
-
1
;
// pa -> W1 p1, pb -> W2 + pn
const
auto
q0
=
pa
-
p1
-
(
pl1
+
pl1bar
);
// pa -> W2 p1, pb -> W1 + pn
const
auto
q1
=
pa
-
p1
-
(
pl2
+
pl2bar
);
const
std
::
vector
<
double
>
ladder_factor
=
FKL_ladder_weight_mix
(
begin_ladder
,
end_ladder
,
q0
,
q1
,
pa
,
pb
,
p1
,
pn
,
lambda
);
assert
(
current_factor
.
size
()
==
3
);
assert
(
current_factor
.
size
()
==
ladder_factor
.
size
());
std
::
vector
<
double
>
result
(
current_factor
.
size
());
for
(
size_t
i
=
0
;
i
<
current_factor
.
size
();
++
i
){
result
[
i
]
=
K_q
*
K_q
/
(
4.
*
(
N_C
*
N_C
-
1.
))
*
current_factor
.
at
(
i
)
*
ladder_factor
.
at
(
i
);
}
const
double
t1_top
=
q0
.
m2
();
const
double
t2_top
=
(
pb
-
pn
-
pl2bar
-
pl2
).
m2
();
const
double
t1_bot
=
q1
.
m2
();
const
double
t2_bot
=
(
pb
-
pn
-
pl1bar
-
pl1
).
m2
();
result
[
0
]
/=
t1_top
*
t2_top
;
result
[
1
]
/=
t1_bot
*
t2_bot
;
result
[
2
]
/=
sqrt
(
t1_top
*
t2_top
*
t1_bot
*
t2_bot
);
return
result
;
}
}
// namespace
std
::
vector
<
double
>
MatrixElement
::
tree_kin_WW
(
Event
const
&
ev
)
const
{
using
namespace
event_type
;
auto
const
&
incoming
(
ev
.
incoming
());
auto
const
pa
=
to_HepLorentzVector
(
incoming
[
0
]);
auto
const
pb
=
to_HepLorentzVector
(
incoming
[
1
]);
auto
const
partons
=
tag_extremal_jet_partons
(
ev
);
// W1 & W2
assert
(
ev
.
decays
().
size
()
==
2
);
std
::
vector
<
CLHEP
::
HepLorentzVector
>
plbar
;
std
::
vector
<
CLHEP
::
HepLorentzVector
>
pl
;
for
(
auto
const
&
decay_pair
:
ev
.
decays
())
{
auto
const
decay
=
decay_pair
.
second
;
// TODO: how to label W1, W2
if
(
decay
.
at
(
0
).
type
<
0
)
{
plbar
.
emplace_back
(
to_HepLorentzVector
(
decay
.
at
(
0
)));
pl
.
emplace_back
(
to_HepLorentzVector
(
decay
.
at
(
1
)));
}
else
{
pl
.
emplace_back
(
to_HepLorentzVector
(
decay
.
at
(
0
)));
plbar
.
emplace_back
(
to_HepLorentzVector
(
decay
.
at
(
1
)));
}
}
if
(
ev
.
type
()
==
FKL
)
{
return
tree_kin_WW_FKL
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pa
,
pb
,
partons
,
plbar
[
0
],
pl
[
0
],
plbar
[
1
],
pl
[
1
],
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Wprop
()
);
}
throw
std
::
logic_error
(
"Can only reweight FKL events in WW"
);
}
namespace
{
std
::
vector
<
double
>
tree_kin_Z_FKL
(
const
ParticleID
aptype
,
const
ParticleID
bptype
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
std
::
vector
<
Particle
>
const
&
partons
,
CLHEP
::
HepLorentzVector
const
&
plbar
,
CLHEP
::
HepLorentzVector
const
&
pl
,
const
double
lambda
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
const
auto
p1
=
to_HepLorentzVector
(
partons
[
0
]);
const
auto
pn
=
to_HepLorentzVector
(
partons
[
partons
.
size
()
-
1
]);
const
auto
begin_ladder
=
cbegin
(
partons
)
+
1
;
const
auto
end_ladder
=
cend
(
partons
)
-
1
;
const
std
::
vector
<
double
>
current_factor
=
ME_Z_current
(
aptype
,
bptype
,
pn
,
pb
,
p1
,
pa
,
plbar
,
pl
,
Zprop
,
stw2
,
ctw
);
std
::
vector
<
double
>
ladder_factor
;
if
(
is_gluon
(
bptype
)){
// This is a qg event
const
auto
q0
=
pa
-
p1
-
plbar
-
pl
;
ladder_factor
.
push_back
(
FKL_ladder_weight
(
begin_ladder
,
end_ladder
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
));
}
else
if
(
is_gluon
(
aptype
)){
// This is a gq event
const
auto
q0
=
pa
-
p1
;
ladder_factor
.
push_back
(
FKL_ladder_weight
(
begin_ladder
,
end_ladder
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
));
}
else
{
// This is a qq event
const
auto
q0
=
pa
-
p1
-
plbar
-
pl
;
const
auto
q1
=
pa
-
p1
;
ladder_factor
=
FKL_ladder_weight_mix
(
begin_ladder
,
end_ladder
,
q0
,
q1
,
pa
,
pb
,
p1
,
pn
,
lambda
);
}
std
::
vector
<
double
>
result
;
for
(
size_t
i
=
0
;
i
<
current_factor
.
size
();
++
i
){
result
.
push_back
(
current_factor
.
at
(
i
)
*
ladder_factor
.
at
(
i
));
}
return
result
;
}
template
<
class
InIter
,
class
partIter
>
std
::
vector
<
double
>
tree_kin_Z_uno
(
InIter
BeginIn
,
partIter
BeginPart
,
partIter
EndPart
,
const
CLHEP
::
HepLorentzVector
&
plbar
,
const
CLHEP
::
HepLorentzVector
&
pl
,
const
double
lambda
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
BeginIn
+
1
));
const
auto
pg
=
to_HepLorentzVector
(
*
BeginPart
);
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
+
1
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
const
ParticleID
aptype
=
(
BeginIn
)
->
type
;
const
ParticleID
bptype
=
(
BeginIn
+
1
)
->
type
;
// we only evaluate unordered backward -> first incoming particle must be a quark
assert
(
is_anyquark
(
aptype
));
const
std
::
vector
<
double
>
current_factor
=
ME_Z_uno_current
(
aptype
,
bptype
,
pn
,
pb
,
p1
,
pa
,
pg
,
plbar
,
pl
,
Zprop
,
stw2
,
ctw
);
std
::
vector
<
double
>
ladder_factor
;
const
auto
q0
=
pa
-
pg
-
p1
-
plbar
-
pl
;
if
(
is_gluon
(
bptype
)){
// This is a qg event
ladder_factor
.
push_back
(
FKL_ladder_weight
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
));
}
else
{
// This is a qq event
const
auto
q1
=
pa
-
pg
-
p1
;
ladder_factor
=
FKL_ladder_weight_mix
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
q1
,
pa
,
pb
,
p1
,
pn
,
lambda
);
}
std
::
vector
<
double
>
result
;
for
(
size_t
i
=
0
;
i
<
current_factor
.
size
();
++
i
){
result
.
push_back
(
current_factor
.
at
(
i
)
*
ladder_factor
.
at
(
i
));
}
return
result
;
}
template
<
class
InIter
,
class
partIter
>
std
::
vector
<
double
>
tree_kin_Z_qqbar
(
InIter
BeginIn
,
partIter
BeginPart
,
partIter
EndPart
,
const
CLHEP
::
HepLorentzVector
&
plbar
,
const
CLHEP
::
HepLorentzVector
&
pl
,
const
double
lambda
,
ParticleProperties
const
&
Zprop
,
const
double
stw2
,
const
double
ctw
){
const
bool
qbar_first
=
is_antiquark
(
*
BeginPart
);
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
BeginIn
+
1
));
const
auto
pq
=
to_HepLorentzVector
(
*
(
BeginPart
+
(
qbar_first
?
1
:
0
)));
const
auto
pqbar
=
to_HepLorentzVector
(
*
(
BeginPart
+
(
qbar_first
?
0
:
1
)));
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
const
ParticleID
qptype
=
(
BeginPart
+
(
qbar_first
?
1
:
0
))
->
type
;
const
ParticleID
bptype
=
(
BeginIn
+
1
)
->
type
;
const
std
::
vector
<
double
>
current_factor
=
ME_Z_qqbar_current
(
qptype
,
bptype
,
pa
,
pb
,
pq
,
pqbar
,
pn
,
plbar
,
pl
,
Zprop
,
stw2
,
ctw
);
std
::
vector
<
double
>
ladder_factor
;
const
auto
q0
=
pa
-
pq
-
pqbar
-
plbar
-
pl
;
if
(
is_gluon
(
bptype
)){
// This is a gg event
ladder_factor
.
push_back
(
FKL_ladder_weight
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
pa
,
pb
,
p1
,
pn
,
lambda
));
}
else
{
// This is a gq event
const
auto
q1
=
pa
-
pq
-
pqbar
;
ladder_factor
=
FKL_ladder_weight_mix
(
BeginPart
+
2
,
EndPart
-
1
,
q0
,
q1
,
pa
,
pb
,
p1
,
pn
,
lambda
);
}
std
::
vector
<
double
>
result
;
for
(
size_t
i
=
0
;
i
<
current_factor
.
size
();
++
i
){
result
.
push_back
(
current_factor
.
at
(
i
)
*
ladder_factor
.
at
(
i
));
}
return
result
;
}
}
// namespace
std
::
vector
<
double
>
MatrixElement
::
tree_kin_Z
(
Event
const
&
ev
)
const
{
using
namespace
event_type
;
auto
const
&
incoming
(
ev
.
incoming
());
// find decay products of Z
auto
const
&
decay
{
ev
.
decays
().
cbegin
()
->
second
};
assert
(
decay
.
size
()
==
2
);
assert
(
is_anylepton
(
decay
.
at
(
0
))
&&
!
is_anyneutrino
(
decay
.
at
(
0
))
&&
decay
.
at
(
0
).
type
==-
decay
.
at
(
1
).
type
);
// get leptons
CLHEP
::
HepLorentzVector
plbar
;
CLHEP
::
HepLorentzVector
pl
;
if
(
decay
.
at
(
0
).
type
<
0
){
plbar
=
to_HepLorentzVector
(
decay
.
at
(
0
));
pl
=
to_HepLorentzVector
(
decay
.
at
(
1
));
}
else
{
pl
=
to_HepLorentzVector
(
decay
.
at
(
0
));
plbar
=
to_HepLorentzVector
(
decay
.
at
(
1
));
}
const
auto
pa
=
to_HepLorentzVector
(
incoming
[
0
]);
const
auto
pb
=
to_HepLorentzVector
(
incoming
[
1
]);
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
const
double
stw2
=
param_
.
ew_parameters
.
sin2_tw
();
const
double
ctw
=
param_
.
ew_parameters
.
cos_tw
();
if
(
ev
.
type
()
==
FKL
){
return
tree_kin_Z_FKL
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pa
,
pb
,
partons
,
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Zprop
(),
stw2
,
ctw
);
}
if
(
ev
.
type
()
==
unordered_backward
){
return
tree_kin_Z_uno
(
cbegin
(
incoming
),
cbegin
(
partons
),
cend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Zprop
(),
stw2
,
ctw
);
}
if
(
ev
.
type
()
==
unordered_forward
){
auto
kin_rev
=
tree_kin_Z_uno
(
crbegin
(
incoming
),
crbegin
(
partons
),
crend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Zprop
(),
stw2
,
ctw
);
if
(
!
is_gluon
(
incoming
[
0
].
type
)){
// qq unordered forward: reorder contributions such that first/second
// value corresponds to Z emission from top/bottom leg respectively
std
::
swap
(
kin_rev
[
0
],
kin_rev
[
1
]);
}
return
kin_rev
;
}
if
(
ev
.
type
()
==
extremal_qqbar_backward
){
return
tree_kin_Z_qqbar
(
cbegin
(
incoming
),
cbegin
(
partons
),
cend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Zprop
(),
stw2
,
ctw
);
}
if
(
ev
.
type
()
==
extremal_qqbar_forward
){
auto
kin_rev
=
tree_kin_Z_qqbar
(
crbegin
(
incoming
),
crbegin
(
partons
),
crend
(
partons
),
plbar
,
pl
,
param_
.
regulator_lambda
,
param_
.
ew_parameters
.
Zprop
(),
stw2
,
ctw
);
if
(
!
is_gluon
(
incoming
[
0
].
type
)){
// qqbar forward with incoming qg: reorder contributions such that first/second
// value corresponds to Z emission from top/bottom leg respectively
std
::
swap
(
kin_rev
[
0
],
kin_rev
[
1
]);
}
return
kin_rev
;
}
throw
std
::
logic_error
(
"Can only reweight FKL/uno/exqqbar processes in Z+Jets"
);
}
double
MatrixElement
::
tree_kin_Higgs
(
Event
const
&
ev
)
const
{
if
(
ev
.
outgoing
().
front
().
type
==
pid
::
Higgs
){
return
tree_kin_Higgs_first
(
ev
);
}
if
(
ev
.
outgoing
().
back
().
type
==
pid
::
Higgs
){
return
tree_kin_Higgs_last
(
ev
);
}
return
tree_kin_Higgs_between
(
ev
);
}
// kinetic matrix element square for backward Higgs emission
// cf. eq:ME_h_jets_peripheral in developer manual,
// but without factors \alpha_s and the FKL ladder
double
MatrixElement
::
MH2_backwardH
(
const
ParticleID
type_forward
,
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
pH
,
CLHEP
::
HepLorentzVector
const
&
pn
)
const
{
using
namespace
currents
;
const
double
vev
=
param_
.
ew_parameters
.
vev
();
return
K
(
type_forward
,
pn
,
pb
)
*
ME_H_gq
(
pH
,
pa
,
pn
,
pb
,
param_
.
Higgs_coupling
.
mt
,
param_
.
Higgs_coupling
.
include_bottom
,
param_
.
Higgs_coupling
.
mb
,
vev
)
/
(
4.
*
(
N_C
*
N_C
-
1
)
*
(
pa
-
pH
).
m2
()
*
(
pb
-
pn
).
m2
());
}
// kinetic matrix element square for backward unordered emission
// and forward g -> Higgs
double
MatrixElement
::
MH2_unob_forwardH
(
CLHEP
::
HepLorentzVector
const
&
pa
,
CLHEP
::
HepLorentzVector
const
&
pb
,
CLHEP
::
HepLorentzVector
const
&
pg
,
CLHEP
::
HepLorentzVector
const
&
p1
,
CLHEP
::
HepLorentzVector
const
&
pH
)
const
{
using
namespace
currents
;
const
double
vev
=
param_
.
ew_parameters
.
vev
();
constexpr
double
K_f1
=
K_q
;
constexpr
double
nhel
=
4.
;
return
K_f1
*
ME_juno_jgH
(
pg
,
p1
,
pa
,
pH
,
pb
,
param_
.
Higgs_coupling
.
mt
,
param_
.
Higgs_coupling
.
include_bottom
,
param_
.
Higgs_coupling
.
mb
,
vev
)
/
(
nhel
*
(
N_C
*
N_C
-
1
)
*
(
pa
-
p1
-
pg
).
m2
()
*
(
pb
-
pH
).
m2
());
}
double
MatrixElement
::
tree_kin_Higgs_first
(
Event
const
&
ev
)
const
{
auto
const
&
incoming
=
ev
.
incoming
();
auto
const
&
outgoing
=
ev
.
outgoing
();
assert
(
outgoing
.
front
().
type
==
pid
::
Higgs
);
if
(
is_anyquark
(
incoming
.
front
()))
{
assert
(
incoming
.
front
().
type
==
outgoing
[
1
].
type
);
return
tree_kin_Higgs_between
(
ev
);
}
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
const
auto
pa
=
to_HepLorentzVector
(
incoming
.
front
());
const
auto
pb
=
to_HepLorentzVector
(
incoming
.
back
());
const
auto
pH
=
to_HepLorentzVector
(
outgoing
.
front
());
const
auto
end_ladder
=
end
(
partons
)
-
((
ev
.
type
()
==
event_type
::
unof
)
?
2
:
1
);
const
auto
pn
=
to_HepLorentzVector
(
*
end_ladder
);
const
double
ladder
=
FKL_ladder_weight
(
begin
(
partons
),
end_ladder
,
pa
-
pH
,
pa
,
pb
,
pa
,
pn
,
param_
.
regulator_lambda
);
if
(
ev
.
type
()
==
event_type
::
unof
)
{
const
auto
pg
=
to_HepLorentzVector
(
outgoing
.
back
());
return
MH2_unob_forwardH
(
pb
,
pa
,
pg
,
pn
,
pH
)
*
ladder
;
}
return
MH2_backwardH
(
incoming
.
back
().
type
,
pa
,
pb
,
pH
,
pn
)
*
ladder
;
}
double
MatrixElement
::
tree_kin_Higgs_last
(
Event
const
&
ev
)
const
{
auto
const
&
incoming
=
ev
.
incoming
();
auto
const
&
outgoing
=
ev
.
outgoing
();
assert
(
outgoing
.
back
().
type
==
pid
::
Higgs
);
if
(
is_anyquark
(
incoming
.
back
()))
{
assert
(
incoming
.
back
().
type
==
outgoing
[
outgoing
.
size
()
-
2
].
type
);
return
tree_kin_Higgs_between
(
ev
);
}
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
const
auto
pa
=
to_HepLorentzVector
(
incoming
.
front
());
const
auto
pb
=
to_HepLorentzVector
(
incoming
.
back
());
const
auto
pH
=
to_HepLorentzVector
(
outgoing
.
back
());
auto
begin_ladder
=
begin
(
partons
)
+
1
;
auto
q0
=
pa
-
to_HepLorentzVector
(
partons
.
front
());
if
(
ev
.
type
()
==
event_type
::
unob
)
{
q0
-=
to_HepLorentzVector
(
*
begin_ladder
);
++
begin_ladder
;
}
const
auto
p1
=
to_HepLorentzVector
(
*
(
begin_ladder
-
1
));
const
double
ladder
=
FKL_ladder_weight
(
begin_ladder
,
end
(
partons
),
q0
,
pa
,
pb
,
p1
,
pb
,
param_
.
regulator_lambda
);
if
(
ev
.
type
()
==
event_type
::
unob
)
{
const
auto
pg
=
to_HepLorentzVector
(
outgoing
.
front
());
return
MH2_unob_forwardH
(
pa
,
pb
,
pg
,
p1
,
pH
)
*
ladder
;
}
return
MH2_backwardH
(
incoming
.
front
().
type
,
pb
,
pa
,
pH
,
p1
)
*
ladder
;
}
namespace
{
template
<
class
InIter
,
class
partIter
>
double
tree_kin_Higgs_uno
(
InIter
BeginIn
,
InIter
EndIn
,
partIter
BeginPart
,
partIter
EndPart
,
CLHEP
::
HepLorentzVector
const
&
qH
,
CLHEP
::
HepLorentzVector
const
&
qHp1
,
double
mt
,
bool
inc_bot
,
double
mb
,
double
vev
){
const
auto
pa
=
to_HepLorentzVector
(
*
BeginIn
);
const
auto
pb
=
to_HepLorentzVector
(
*
(
EndIn
-
1
));
const
auto
pg
=
to_HepLorentzVector
(
*
BeginPart
);
const
auto
p1
=
to_HepLorentzVector
(
*
(
BeginPart
+
1
));
const
auto
pn
=
to_HepLorentzVector
(
*
(
EndPart
-
1
));
return
ME_Higgs_current_uno
(
(
BeginIn
)
->
type
,
(
EndIn
-
1
)
->
type
,
pg
,
pn
,
pb
,
p1
,
pa
,
qH
,
qHp1
,
mt
,
inc_bot
,
mb
,
vev
);
}
}
// namespace
double
MatrixElement
::
tree_kin_Higgs_between
(
Event
const
&
ev
)
const
{
using
namespace
event_type
;
auto
const
&
incoming
=
ev
.
incoming
();
auto
const
&
outgoing
=
ev
.
outgoing
();
const
auto
the_Higgs
=
std
::
find_if
(
begin
(
outgoing
),
end
(
outgoing
),
[](
Particle
const
&
s
){
return
s
.
type
==
pid
::
Higgs
;
}
);
assert
(
the_Higgs
!=
end
(
outgoing
));
const
auto
pH
=
to_HepLorentzVector
(
*
the_Higgs
);
const
auto
partons
=
tag_extremal_jet_partons
(
ev
);
const
auto
pa
=
to_HepLorentzVector
(
incoming
[
0
]);
const
auto
pb
=
to_HepLorentzVector
(
incoming
[
1
]);
auto
p1
=
to_HepLorentzVector
(
partons
[(
ev
.
type
()
==
unob
)
?
1
:
0
]
);
auto
pn
=
to_HepLorentzVector
(
partons
[
partons
.
size
()
-
((
ev
.
type
()
==
unof
)
?
2
:
1
)]
);
auto
first_after_Higgs
=
begin
(
partons
)
+
(
the_Higgs
-
begin
(
outgoing
));
assert
(
(
first_after_Higgs
==
end
(
partons
)
&&
(
(
ev
.
type
()
==
unob
)
||
partons
.
back
().
type
!=
pid
::
gluon
))
||
first_after_Higgs
->
rapidity
()
>=
the_Higgs
->
rapidity
()
);
assert
(
(
first_after_Higgs
==
begin
(
partons
)
&&
(
(
ev
.
type
()
==
unof
)
||
partons
.
front
().
type
!=
pid
::
gluon
))
||
(
first_after_Higgs
-
1
)
->
rapidity
()
<=
the_Higgs
->
rapidity
()
);
// always treat the Higgs as if it were in between the extremal FKL partons
if
(
first_after_Higgs
==
begin
(
partons
))
++
first_after_Higgs
;
else
if
(
first_after_Higgs
==
end
(
partons
))
--
first_after_Higgs
;
// t-channel momentum before Higgs
auto
qH
=
pa
;
for
(
auto
parton_it
=
begin
(
partons
);
parton_it
!=
first_after_Higgs
;
++
parton_it
){
qH
-=
to_HepLorentzVector
(
*
parton_it
);
}
auto
q0
=
pa
-
p1
;
auto
begin_ladder
=
begin
(
partons
)
+
1
;
auto
end_ladder
=
end
(
partons
)
-
1
;
double
current_factor
=
NAN
;
if
(
ev
.
type
()
==
FKL
){
current_factor
=
ME_Higgs_current
(
incoming
[
0
].
type
,
incoming
[
1
].
type
,
pn
,
pb
,
p1
,
pa
,
qH
,
qH
-
pH
,
param_
.
Higgs_coupling
.
mt
,
param_
.
Higgs_coupling
.
include_bottom
,
param_
.
Higgs_coupling
.
mb
,
param_
.
ew_parameters
.
vev
()
);
}
else
if
(
ev
.
type
()
==
unob
){
current_factor
=
tree_kin_Higgs_uno
(
begin
(
incoming
),
end
(
incoming
),
begin
(
partons
),
end
(
partons
),
qH
,
qH
-
pH
,
param_
.
Higgs_coupling
.
mt
,
param_
.
Higgs_coupling
.
include_bottom
,
param_
.
Higgs_coupling
.
mb
,
param_
.
ew_parameters
.
vev
()
);
const
auto
p_unob
=
to_HepLorentzVector
(
partons
.
front
());
q0
-=
p_unob
;
p1
+=
p_unob
;
++
begin_ladder
;
}
else
if
(
ev
.
type
()
==
unof
){
current_factor
=
tree_kin_Higgs_uno
(
rbegin
(
incoming
),
rend
(
incoming
),
rbegin
(
partons
),
rend
(
partons
),
qH
-
pH
,
qH
,
param_
.
Higgs_coupling
.
mt
,
param_
.
Higgs_coupling
.
include_bottom
,
param_
.
Higgs_coupling
.
mb
,
param_
.
ew_parameters
.
vev
()
);
pn
+=
to_HepLorentzVector
(
partons
.
back
());
--
end_ladder
;
}
else
{
throw
std
::
logic_error
(
"Can only reweight FKL or uno processes in H+Jets"
);
}
const
double
ladder_factor
=
FKL_ladder_weight
(
begin_ladder
,
first_after_Higgs
,
q0
,
pa
,
pb
,
p1
,
pn
,
param_
.
regulator_lambda
)
*
FKL_ladder_weight
(
first_after_Higgs
,
end_ladder
,
qH
-
pH
,
pa
,
pb
,
p1
,
pn
,
param_
.
regulator_lambda
);
return
current_factor
/
(
4.
*
(
N_C
*
N_C
-
1.
))
*
ladder_factor
;
}
namespace
{
double
get_AWZH_coupling
(
Event
const
&
ev
,
double
alpha_s
,
double
alpha_w
)
{
std
::
vector
<
Particle
>
bosons
=
filter_AWZH_bosons
(
ev
.
outgoing
());
if
(
bosons
.
empty
())
{
return
1.
;
}
if
(
bosons
.
size
()
==
1
)
{
switch
(
bosons
[
0
].
type
){
case
pid
::
Higgs
:
return
alpha_s
*
alpha_s
;
case
pid
::
Wp
:
case
pid
::
Wm
:
return
alpha_w
*
alpha_w
;
case
pid
::
Z_photon_mix
:
return
alpha_w
*
alpha_w
;
// TODO
case
pid
::
photon
:
case
pid
::
Z
:
default
:
throw
not_implemented
(
"Emission of boson of unsupported type"
);
}
}
if
(
bosons
.
size
()
==
2
)
{
if
(
bosons
[
0
].
type
==
pid
::
Wp
&&
bosons
[
1
].
type
==
pid
::
Wp
)
{
return
alpha_w
*
alpha_w
*
alpha_w
*
alpha_w
;
}
else
if
(
bosons
[
0
].
type
==
pid
::
Wm
&&
bosons
[
1
].
type
==
pid
::
Wm
)
{
return
alpha_w
*
alpha_w
*
alpha_w
*
alpha_w
;
}
throw
not_implemented
(
"Emission of bosons of unsupported type"
);
}
throw
not_implemented
(
"Emission of >2 bosons is unsupported"
);
}
}
// namespace
double
MatrixElement
::
tree_param
(
Event
const
&
ev
,
double
mur
)
const
{
assert
(
is_resummable
(
ev
.
type
()));
const
auto
begin_partons
=
ev
.
begin_partons
();
const
auto
end_partons
=
ev
.
end_partons
();
const
auto
num_partons
=
std
::
distance
(
begin_partons
,
end_partons
);
const
double
alpha_s
=
alpha_s_
(
mur
);
const
double
gs2
=
4.
*
M_PI
*
alpha_s
;
double
res
=
std
::
pow
(
gs2
,
num_partons
);
if
(
param_
.
log_correction
){
// use alpha_s(q_perp), evolved to mur
assert
(
num_partons
>=
2
);
const
auto
first_emission
=
std
::
next
(
begin_partons
);
const
auto
last_emission
=
std
::
prev
(
end_partons
);
for
(
auto
parton
=
first_emission
;
parton
!=
last_emission
;
++
parton
){
res
*=
1.
+
alpha_s
/
(
2.
*
M_PI
)
*
BETA0
*
std
::
log
(
mur
/
parton
->
perp
());
}
}
return
get_AWZH_coupling
(
ev
,
alpha_s
,
param_
.
ew_parameters
.
alpha_w
())
*
res
;
}
}
// namespace HEJ
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Sep 30, 4:40 AM (22 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
6553287
Default Alt Text
MatrixElement.cc (91 KB)
Attached To
Mode
rHEJ HEJ
Attached
Detach File
Event Timeline
Log In to Comment