Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F19251839
PhaseSpacePoint.cc
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
27 KB
Referenced Files
None
Subscribers
None
PhaseSpacePoint.cc
View Options
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include
"HEJ/PhaseSpacePoint.hh"
#include
<algorithm>
#include
<assert.h>
#include
<numeric>
#include
<random>
#include
"fastjet/ClusterSequence.hh"
#include
"HEJ/Constants.hh"
#include
"HEJ/Event.hh"
#include
"HEJ/JetSplitter.hh"
#include
"HEJ/kinematics.hh"
#include
"HEJ/resummation_jet.hh"
#include
"HEJ/utility.hh"
#include
"HEJ/PDG_codes.hh"
#include
"HEJ/event_types.hh"
namespace
HEJ
{
namespace
{
constexpr
int
max_jet_user_idx
=
PhaseSpacePoint
::
ng_max
;
bool
is_nonjet_parton
(
fastjet
::
PseudoJet
const
&
parton
){
assert
(
parton
.
user_index
()
!=
-
1
);
return
parton
.
user_index
()
>
max_jet_user_idx
;
}
bool
is_jet_parton
(
fastjet
::
PseudoJet
const
&
parton
){
assert
(
parton
.
user_index
()
!=
-
1
);
return
parton
.
user_index
()
<=
max_jet_user_idx
;
}
// user indices for partons with extremal rapidity
constexpr
int
qqxmid1_idx
=
-
9
;
constexpr
int
qqxmid2_idx
=
-
8
;
constexpr
int
qqxb_idx
=
-
7
;
constexpr
int
qqxf_idx
=
-
6
;
constexpr
int
unob_idx
=
-
5
;
constexpr
int
unof_idx
=
-
4
;
constexpr
int
backward_FKL_idx
=
-
3
;
constexpr
int
forward_FKL_idx
=
-
2
;
}
namespace
{
double
estimate_ng_mean
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
){
const
double
delta_y
=
Born_jets
.
back
().
rapidity
()
-
Born_jets
.
front
().
rapidity
();
assert
(
delta_y
>
0
);
// Formula derived from fit in arXiv:1805.04446 (see Fig. 2)
return
0.975052
*
delta_y
;
}
}
std
::
vector
<
fastjet
::
PseudoJet
>
PhaseSpacePoint
::
cluster_jets
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
partons
)
const
{
fastjet
::
ClusterSequence
cs
(
partons
,
param_
.
jet_param
.
def
);
return
sorted_by_rapidity
(
cs
.
inclusive_jets
(
param_
.
jet_param
.
min_pt
));
}
bool
PhaseSpacePoint
::
pass_resummation_cuts
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
)
const
{
return
cluster_jets
(
jets
).
size
()
==
jets
.
size
();
}
int
PhaseSpacePoint
::
sample_ng
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
){
const
double
ng_mean
=
estimate_ng_mean
(
Born_jets
);
std
::
poisson_distribution
<
int
>
dist
(
ng_mean
);
const
int
ng
=
dist
(
ran_
.
get
());
assert
(
ng
>=
0
);
assert
(
ng
<
ng_max
);
weight_
*=
std
::
tgamma
(
ng
+
1
)
*
std
::
exp
(
ng_mean
)
*
std
::
pow
(
ng_mean
,
-
ng
);
return
ng
;
}
void
PhaseSpacePoint
::
copy_AWZH_boson_from
(
Event
const
&
event
){
auto
const
&
from
=
event
.
outgoing
();
const
auto
AWZH_boson
=
std
::
find_if
(
begin
(
from
),
end
(
from
),
[](
Particle
const
&
p
){
return
is_AWZH_boson
(
p
);
}
);
if
(
AWZH_boson
==
end
(
from
))
return
;
auto
insertion_point
=
std
::
lower_bound
(
begin
(
outgoing_
),
end
(
outgoing_
),
*
AWZH_boson
,
rapidity_less
{}
);
outgoing_
.
insert
(
insertion_point
,
*
AWZH_boson
);
// copy decay products
const
int
idx
=
std
::
distance
(
begin
(
from
),
AWZH_boson
);
assert
(
idx
>=
0
);
const
auto
decay_it
=
event
.
decays
().
find
(
idx
);
if
(
decay_it
!=
end
(
event
.
decays
())){
const
int
new_idx
=
std
::
distance
(
begin
(
outgoing_
),
insertion_point
);
assert
(
new_idx
>=
0
);
assert
(
outgoing_
[
new_idx
].
type
==
AWZH_boson
->
type
);
decays_
.
emplace
(
new_idx
,
decay_it
->
second
);
}
assert
(
std
::
is_sorted
(
begin
(
outgoing_
),
end
(
outgoing_
),
rapidity_less
{}));
}
namespace
{
auto
get_first_anyquark_emission
(
Event
const
&
ev
)
{
// find born quarks (ignore extremal partons)
auto
const
firstquark
=
std
::
find_if
(
std
::
next
(
ev
.
begin_partons
()),
std
::
prev
(
ev
.
end_partons
(),
2
),
[](
Particle
const
&
s
){
return
(
is_anyquark
(
s
));
}
);
// assert that it is a q-q_bar pair.
assert
(
std
::
distance
(
firstquark
,
ev
.
end_partons
())
!=
2
);
assert
(
(
is_quark
(
*
firstquark
)
&&
is_antiquark
(
*
std
::
next
(
firstquark
))
)
||
(
is_antiquark
(
*
firstquark
)
&&
is_quark
(
*
std
::
next
(
firstquark
))
)
);
return
firstquark
;
}
//! returns index of most backward q-qbar jet
template
<
class
Iterator
>
int
get_back_quark_jet
(
Event
const
&
ev
,
Iterator
firstquark
){
// find jets at FO corresponding to the quarks
// technically this isn't necessary for LO
std
::
vector
<
int
>
const
born_indices
{
ev
.
particle_jet_indices
(
ev
.
jets
())
};
const
auto
firstquark_idx
=
std
::
distance
(
ev
.
begin_partons
(),
firstquark
);
int
const
firstjet_idx
=
born_indices
[
firstquark_idx
];
assert
(
firstjet_idx
>
0
);
assert
(
born_indices
[
firstquark_idx
+
1
]
==
firstjet_idx
+
1
);
return
firstjet_idx
;
}
//! returns index of most backward q-qbar jet
int
getBackQuarkJet
(
Event
const
&
ev
){
const
auto
firstquark
=
get_first_anyquark_emission
(
ev
);
return
get_back_quark_jet
(
ev
,
firstquark
);
}
template
<
class
ConstIterator
,
class
Iterator
>
void
label_extremal_qqx
(
ConstIterator
born_begin
,
ConstIterator
born_end
,
Iterator
first_out
){
// find born quarks
const
auto
firstquark
=
std
::
find_if
(
born_begin
,
born_end
-
1
,
[](
Particle
const
&
s
){
return
(
is_anyquark
(
s
));
}
);
assert
(
firstquark
!=
born_end
-
1
);
const
auto
secondquark
=
std
::
find_if
(
firstquark
+
1
,
born_end
,
[](
Particle
const
&
s
){
return
(
is_anyquark
(
s
));
}
);
assert
(
secondquark
!=
born_end
);
assert
(
(
is_quark
(
*
firstquark
)
&&
is_antiquark
(
*
secondquark
)
)
||
(
is_antiquark
(
*
firstquark
)
&&
is_quark
(
*
secondquark
)
));
assert
(
first_out
->
type
==
ParticleID
::
gluon
);
assert
((
first_out
+
1
)
->
type
==
ParticleID
::
gluon
);
// copy type from born
first_out
->
type
=
firstquark
->
type
;
(
first_out
+
1
)
->
type
=
secondquark
->
type
;
}
}
void
PhaseSpacePoint
::
label_qqx
(
Event
const
&
event
){
assert
(
std
::
is_sorted
(
begin
(
outgoing_
),
end
(
outgoing_
),
rapidity_less
{}));
assert
(
filter_partons
(
outgoing_
).
size
()
==
outgoing_
.
size
());
if
(
qqxb_
){
label_extremal_qqx
(
event
.
outgoing
().
cbegin
(),
event
.
outgoing
().
cend
(),
outgoing_
.
begin
()
);
return
;
}
if
(
qqxf_
){
// same as qqxb with reversed order
label_extremal_qqx
(
event
.
outgoing
().
crbegin
(),
event
.
outgoing
().
crend
(),
outgoing_
.
rbegin
()
);
return
;
}
// central qqx
const
auto
firstquark
=
get_first_anyquark_emission
(
event
);
// find jets at FO corresponding to the quarks
// technically this isn't necessary for LO
const
auto
firstjet_idx
=
get_back_quark_jet
(
event
,
firstquark
);
// find corresponding jets after resummation
fastjet
::
ClusterSequence
cs
{
to_PseudoJet
(
outgoing_
),
param_
.
jet_param
.
def
};
auto
const
jets
=
fastjet
::
sorted_by_rapidity
(
cs
.
inclusive_jets
(
param_
.
jet_param
.
min_pt
));
std
::
vector
<
int
>
const
resum_indices
{
cs
.
particle_jet_indices
({
jets
})
};
// assert that jets didn't move
assert
(
nearby_ep
(
(
event
.
jets
().
cbegin
()
+
firstjet_idx
)
->
rapidity
(),
jets
[
firstjet_idx
].
rapidity
(),
1e-2
)
);
assert
(
nearby_ep
(
(
event
.
jets
().
cbegin
()
+
firstjet_idx
+
1
)
->
rapidity
(),
jets
[
firstjet_idx
+
1
].
rapidity
(),
1e-2
)
);
// find last partons in first (central) jet
size_t
idx_out
=
0
;
for
(
size_t
i
=
resum_indices
.
size
()
-
2
;
i
>
0
;
--
i
)
if
(
resum_indices
[
i
]
==
firstjet_idx
){
idx_out
=
i
;
break
;
}
assert
(
idx_out
!=
0
);
// check that there is sufficient pt in jets from the quarks
const
double
minpartonjetpt
=
1.
-
param_
.
max_ext_soft_pt_fraction
;
if
(
outgoing_
[
idx_out
].
p
.
pt
()
<
minpartonjetpt
*
(
event
.
jets
().
cbegin
()
+
firstjet_idx
)
->
pt
()){
weight_
=
0.
;
status_
=
StatusCode
::
wrong_jets
;
return
;
}
if
(
outgoing_
[
idx_out
+
1
].
p
.
pt
()
<
minpartonjetpt
*
(
event
.
jets
().
cbegin
()
+
firstjet_idx
+
1
)
->
pt
()){
weight_
=
0.
;
status_
=
StatusCode
::
wrong_jets
;
return
;
}
// check that no additional emission between jets
// such configurations are possible if we have an gluon gets generated
// inside the rapidities of the qqx chain, but clusted to a
// differnet/outside jet. Changing this is non trivial
if
(
resum_indices
[
idx_out
+
1
]
!=
resum_indices
[
idx_out
]
+
1
){
weight_
=
0.
;
status_
=
StatusCode
::
gluon_in_qqx
;
return
;
}
outgoing_
[
idx_out
].
type
=
firstquark
->
type
;
outgoing_
[
idx_out
+
1
].
type
=
std
::
next
(
firstquark
)
->
type
;
}
void
PhaseSpacePoint
::
label_quarks
(
Event
const
&
ev
){
const
auto
WEmit
=
std
::
find_if
(
begin
(
ev
.
outgoing
()),
end
(
ev
.
outgoing
()),
[](
Particle
const
&
s
){
return
abs
(
s
.
type
)
==
pid
::
Wp
;
}
);
if
(
WEmit
!=
end
(
ev
.
outgoing
())){
if
(
!
qqxb_
)
{
const
size_t
backward_FKL_idx
=
unob_
?
1
:
0
;
const
auto
backward_FKL
=
std
::
next
(
ev
.
begin_partons
(),
backward_FKL_idx
);
outgoing_
[
backward_FKL_idx
].
type
=
backward_FKL
->
type
;
}
if
(
!
qqxf_
)
{
const
size_t
forward_FKL_idx
=
unof_
?
1
:
0
;
const
auto
forward_FKL
=
std
::
prev
(
ev
.
end_partons
(),
1
+
forward_FKL_idx
);
outgoing_
.
rbegin
()[
unof_
].
type
=
forward_FKL
->
type
;
}
}
else
{
most_backward_FKL
(
outgoing_
).
type
=
ev
.
incoming
().
front
().
type
;
most_forward_FKL
(
outgoing_
).
type
=
ev
.
incoming
().
back
().
type
;
}
if
(
qqxmid_
||
qqxb_
||
qqxf_
){
label_qqx
(
ev
);
}
}
PhaseSpacePoint
::
PhaseSpacePoint
(
Event
const
&
ev
,
PhaseSpacePointConfig
conf
,
HEJ
::
RNG
&
ran
)
:
unob_
{
ev
.
type
()
==
event_type
::
unob
},
unof_
{
ev
.
type
()
==
event_type
::
unof
},
qqxb_
{
ev
.
type
()
==
event_type
::
qqxexb
},
qqxf_
{
ev
.
type
()
==
event_type
::
qqxexf
},
qqxmid_
{
ev
.
type
()
==
event_type
::
qqxmid
},
param_
{
std
::
move
(
conf
)},
ran_
{
ran
},
status_
{
unspecified
}
{
weight_
=
1
;
const
auto
&
Born_jets
=
ev
.
jets
();
const
int
ng
=
sample_ng
(
Born_jets
);
weight_
/=
std
::
tgamma
(
ng
+
1
);
const
int
ng_jets
=
sample_ng_jets
(
ng
,
Born_jets
);
std
::
vector
<
fastjet
::
PseudoJet
>
out_partons
=
gen_non_jet
(
ng
-
ng_jets
,
CMINPT
,
param_
.
jet_param
.
min_pt
);
int
qqxbackjet
(
-
1
);
if
(
qqxmid_
){
qqxbackjet
=
getBackQuarkJet
(
ev
);
}
const
auto
qperp
=
std
::
accumulate
(
begin
(
out_partons
),
end
(
out_partons
),
fastjet
::
PseudoJet
{}
);
const
auto
jets
=
reshuffle
(
Born_jets
,
qperp
);
if
(
weight_
==
0.
)
{
status_
=
failed_reshuffle
;
return
;
}
if
(
!
pass_resummation_cuts
(
jets
)){
status_
=
failed_resummation_cuts
;
weight_
=
0.
;
return
;
}
std
::
vector
<
fastjet
::
PseudoJet
>
jet_partons
=
split
(
jets
,
ng_jets
,
qqxbackjet
);
if
(
weight_
==
0.
)
{
status_
=
StatusCode
::
failed_split
;
return
;
}
if
(
qqxmid_
){
rescale_qqx_rapidities
(
out_partons
,
jets
,
most_backward_FKL
(
jet_partons
).
rapidity
(),
most_forward_FKL
(
jet_partons
).
rapidity
(),
qqxbackjet
);
}
else
{
rescale_rapidities
(
out_partons
,
most_backward_FKL
(
jet_partons
).
rapidity
(),
most_forward_FKL
(
jet_partons
).
rapidity
()
);
}
if
(
!
cluster_jets
(
out_partons
).
empty
()){
weight_
=
0.
;
status_
=
StatusCode
::
empty_jets
;
return
;
}
std
::
sort
(
begin
(
out_partons
),
end
(
out_partons
),
rapidity_less
{});
assert
(
std
::
is_sorted
(
begin
(
jet_partons
),
end
(
jet_partons
),
rapidity_less
{})
);
const
auto
first_jet_parton
=
out_partons
.
insert
(
end
(
out_partons
),
begin
(
jet_partons
),
end
(
jet_partons
)
);
std
::
inplace_merge
(
begin
(
out_partons
),
first_jet_parton
,
end
(
out_partons
),
rapidity_less
{}
);
if
(
!
jets_ok
(
Born_jets
,
out_partons
)){
weight_
=
0.
;
status_
=
StatusCode
::
wrong_jets
;
return
;
}
weight_
*=
phase_space_normalisation
(
Born_jets
.
size
(),
out_partons
.
size
());
outgoing_
.
reserve
(
out_partons
.
size
()
+
1
);
// one slot for possible A, W, Z, H
for
(
auto
&
p
:
out_partons
){
outgoing_
.
emplace_back
(
Particle
{
pid
::
gluon
,
std
::
move
(
p
),
{}});
}
assert
(
!
outgoing_
.
empty
());
label_quarks
(
ev
);
if
(
weight_
==
0.
)
{
//! @TODO optimise s.t. this is not possible
// status is handled internally
return
;
}
copy_AWZH_boson_from
(
ev
);
reconstruct_incoming
(
ev
.
incoming
());
status_
=
StatusCode
::
good
;
}
std
::
vector
<
fastjet
::
PseudoJet
>
PhaseSpacePoint
::
gen_non_jet
(
int
count
,
double
ptmin
,
double
ptmax
){
// heuristic parameters for pt sampling
const
double
ptpar
=
1.3
+
count
/
5.
;
const
double
temp1
=
atan
((
ptmax
-
ptmin
)
/
ptpar
);
std
::
vector
<
fastjet
::
PseudoJet
>
partons
(
count
);
for
(
size_t
i
=
0
;
i
<
(
size_t
)
count
;
++
i
){
const
double
r1
=
ran_
.
get
().
flat
();
const
double
pt
=
ptmin
+
ptpar
*
tan
(
r1
*
temp1
);
const
double
temp2
=
cos
(
r1
*
temp1
);
const
double
phi
=
2
*
M_PI
*
ran_
.
get
().
flat
();
weight_
*=
2.0
*
M_PI
*
pt
*
ptpar
*
temp1
/
(
temp2
*
temp2
);
// we don't know the allowed rapidity span yet,
// set a random value to be rescaled later on
const
double
y
=
ran_
.
get
().
flat
();
partons
[
i
].
reset_PtYPhiM
(
pt
,
y
,
phi
);
// Set user index higher than any jet-parton index
// in order to assert that these are not inside jets
partons
[
i
].
set_user_index
(
i
+
1
+
ng_max
);
assert
(
ptmin
-
1e-5
<=
partons
[
i
].
pt
()
&&
partons
[
i
].
pt
()
<=
ptmax
+
1e-5
);
}
assert
(
std
::
all_of
(
partons
.
cbegin
(),
partons
.
cend
(),
is_nonjet_parton
));
return
sorted_by_rapidity
(
partons
);
}
void
PhaseSpacePoint
::
rescale_qqx_rapidities
(
std
::
vector
<
fastjet
::
PseudoJet
>
&
out_partons
,
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
,
const
double
ymin1
,
const
double
ymax2
,
const
int
qqxbackjet
){
const
double
ymax1
=
jets
[
qqxbackjet
].
rapidity
();
const
double
ymin2
=
jets
[
qqxbackjet
+
1
].
rapidity
();
constexpr
double
ep
=
1e-7
;
const
double
tot_y
=
ymax1
-
ymin1
+
ymax2
-
ymin2
;
std
::
vector
<
std
::
reference_wrapper
<
fastjet
::
PseudoJet
>>
refpart
(
out_partons
.
begin
(),
out_partons
.
end
());
double
ratio
=
(
ymax1
-
ymin1
)
/
tot_y
;
const
auto
gap
{
std
::
find_if
(
refpart
.
begin
(),
refpart
.
end
(),
[
ratio
](
fastjet
::
PseudoJet
p
){
return
(
p
.
rapidity
()
>=
ratio
);}
)
};
double
ymin
=
ymin1
;
double
ymax
=
ymax1
;
double
dy
=
ymax
-
ymin
-
2
*
ep
;
double
offset
=
0.
;
for
(
auto
it_part
=
refpart
.
begin
();
it_part
<
refpart
.
end
();
++
it_part
){
if
(
it_part
==
gap
){
ymin
=
ymin2
;
ymax
=
ymax2
;
dy
=
ymax
-
ymin
-
2
*
ep
;
offset
=
ratio
;
ratio
=
1
-
ratio
;
}
fastjet
::
PseudoJet
&
part
=
*
it_part
;
assert
(
offset
<=
part
.
rapidity
()
&&
part
.
rapidity
()
<
ratio
+
offset
);
const
double
y
=
ymin
+
ep
+
dy
*
((
part
.
rapidity
()
-
offset
)
/
ratio
);
part
.
reset_momentum_PtYPhiM
(
part
.
pt
(),
y
,
part
.
phi
());
weight_
*=
tot_y
-
4.
*
ep
;
assert
(
ymin
<=
part
.
rapidity
()
&&
part
.
rapidity
()
<=
ymax
);
}
assert
(
is_sorted
(
begin
(
out_partons
),
end
(
out_partons
),
rapidity_less
{}));
}
void
PhaseSpacePoint
::
rescale_rapidities
(
std
::
vector
<
fastjet
::
PseudoJet
>
&
partons
,
double
ymin
,
double
ymax
){
constexpr
double
ep
=
1e-7
;
for
(
auto
&
parton
:
partons
){
assert
(
0
<=
parton
.
rapidity
()
&&
parton
.
rapidity
()
<=
1
);
const
double
dy
=
ymax
-
ymin
-
2
*
ep
;
const
double
y
=
ymin
+
ep
+
dy
*
parton
.
rapidity
();
parton
.
reset_momentum_PtYPhiM
(
parton
.
pt
(),
y
,
parton
.
phi
());
weight_
*=
dy
;
assert
(
ymin
<=
parton
.
rapidity
()
&&
parton
.
rapidity
()
<=
ymax
);
}
}
namespace
{
template
<
typename
T
,
typename
...
Rest
>
auto
min
(
T
const
&
a
,
T
const
&
b
,
Rest
&&
...
r
)
{
using
std
::
min
;
return
min
(
a
,
min
(
b
,
std
::
forward
<
Rest
>
(
r
)...));
}
}
double
PhaseSpacePoint
::
probability_in_jet
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
)
const
{
assert
(
std
::
is_sorted
(
begin
(
Born_jets
),
end
(
Born_jets
),
rapidity_less
{}));
assert
(
Born_jets
.
size
()
>=
2
);
const
double
dy
=
Born_jets
.
back
().
rapidity
()
-
Born_jets
.
front
().
rapidity
();
const
double
R
=
param_
.
jet_param
.
def
.
R
();
const
int
njets
=
Born_jets
.
size
();
const
double
p_J_y_large
=
(
njets
-
1
)
*
R
*
R
/
(
2.
*
dy
);
const
double
p_J_y0
=
njets
*
R
/
M_PI
;
return
min
(
p_J_y_large
,
p_J_y0
,
1.
);
}
int
PhaseSpacePoint
::
sample_ng_jets
(
int
ng
,
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
){
const
double
p_J
=
probability_in_jet
(
Born_jets
);
std
::
binomial_distribution
<>
bin_dist
(
ng
,
p_J
);
const
int
ng_J
=
bin_dist
(
ran_
.
get
());
weight_
*=
std
::
pow
(
p_J
,
-
ng_J
)
*
std
::
pow
(
1
-
p_J
,
ng_J
-
ng
);
return
ng_J
;
}
std
::
vector
<
fastjet
::
PseudoJet
>
PhaseSpacePoint
::
reshuffle
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
,
fastjet
::
PseudoJet
const
&
q
){
if
(
q
==
fastjet
::
PseudoJet
{
0
,
0
,
0
,
0
})
return
Born_jets
;
const
auto
jets
=
resummation_jet_momenta
(
Born_jets
,
q
);
if
(
jets
.
empty
()){
weight_
=
0
;
return
{};
}
// additional Jacobian to ensure Born integration over delta gives 1
weight_
*=
resummation_jet_weight
(
Born_jets
,
q
);
return
jets
;
}
std
::
vector
<
int
>
PhaseSpacePoint
::
distribute_jet_partons
(
int
ng_jets
,
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
){
size_t
first_valid_jet
=
0
;
size_t
num_valid_jets
=
jets
.
size
();
const
double
R_eff
=
5.
/
3.
*
param_
.
jet_param
.
def
.
R
();
// if there is an unordered jet too far away from the FKL jets
// then extra gluon constituents of the unordered jet would
// violate the FKL rapidity ordering
if
((
unob_
||
qqxb_
)
&&
jets
[
0
].
delta_R
(
jets
[
1
])
>
R_eff
){
++
first_valid_jet
;
--
num_valid_jets
;
}
else
if
((
unof_
||
qqxf_
)
&&
jets
[
jets
.
size
()
-
1
].
delta_R
(
jets
[
jets
.
size
()
-
2
])
>
R_eff
){
--
num_valid_jets
;
}
std
::
vector
<
int
>
np
(
jets
.
size
(),
1
);
for
(
int
i
=
0
;
i
<
ng_jets
;
++
i
){
++
np
[
first_valid_jet
+
ran_
.
get
().
flat
()
*
num_valid_jets
];
}
weight_
*=
std
::
pow
(
num_valid_jets
,
ng_jets
);
return
np
;
}
#ifndef NDEBUG
namespace
{
bool
tagged_FKL_backward
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jet_partons
){
return
std
::
find_if
(
begin
(
jet_partons
),
end
(
jet_partons
),
[](
fastjet
::
PseudoJet
const
&
p
){
return
p
.
user_index
()
==
backward_FKL_idx
;
}
)
!=
end
(
jet_partons
);
}
bool
tagged_FKL_forward
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jet_partons
){
// the most forward FKL parton is most likely near the end of jet_partons;
// start search from there
return
std
::
find_if
(
jet_partons
.
rbegin
(),
jet_partons
.
rend
(),
[](
fastjet
::
PseudoJet
const
&
p
){
return
p
.
user_index
()
==
forward_FKL_idx
;
}
)
!=
jet_partons
.
rend
();
}
bool
tagged_FKL_extremal
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jet_partons
){
return
tagged_FKL_backward
(
jet_partons
)
&&
tagged_FKL_forward
(
jet_partons
);
}
}
// namespace anonymous
#endif
std
::
vector
<
fastjet
::
PseudoJet
>
PhaseSpacePoint
::
split
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
,
int
ng_jets
,
size_t
qqxbackjet
){
return
split
(
jets
,
distribute_jet_partons
(
ng_jets
,
jets
),
qqxbackjet
);
}
bool
PhaseSpacePoint
::
pass_extremal_cuts
(
fastjet
::
PseudoJet
const
&
ext_parton
,
fastjet
::
PseudoJet
const
&
jet
)
const
{
if
(
ext_parton
.
pt
()
<
param_
.
min_extparton_pt
)
return
false
;
return
(
ext_parton
-
jet
).
pt
()
/
jet
.
pt
()
<
param_
.
max_ext_soft_pt_fraction
;
}
std
::
vector
<
fastjet
::
PseudoJet
>
PhaseSpacePoint
::
split
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
,
std
::
vector
<
int
>
const
&
np
,
size_t
qqxbackjet
){
assert
(
!
jets
.
empty
());
assert
(
jets
.
size
()
==
np
.
size
());
assert
(
pass_resummation_cuts
(
jets
));
const
size_t
most_backward_FKL_idx
=
0
+
unob_
+
qqxb_
;
const
size_t
most_forward_FKL_idx
=
jets
.
size
()
-
1
-
unof_
-
qqxf_
;
const
auto
&
jet
=
param_
.
jet_param
;
const
JetSplitter
jet_splitter
{
jet
.
def
,
jet
.
min_pt
,
ran_
};
std
::
vector
<
fastjet
::
PseudoJet
>
jet_partons
;
// randomly distribute jet gluons among jets
for
(
size_t
i
=
0
;
i
<
jets
.
size
();
++
i
){
auto
split_res
=
jet_splitter
.
split
(
jets
[
i
],
np
[
i
]);
weight_
*=
split_res
.
weight
;
if
(
weight_
==
0
)
return
{};
assert
(
std
::
all_of
(
begin
(
split_res
.
constituents
),
end
(
split_res
.
constituents
),
is_jet_parton
)
);
const
auto
first_new_parton
=
jet_partons
.
insert
(
end
(
jet_partons
),
begin
(
split_res
.
constituents
),
end
(
split_res
.
constituents
)
);
// mark uno and extremal FKL emissions here so we can check
// their position once all emissions are generated
// also mark qqxmid partons, and apply appropriate pt cut.
auto
extremal
=
end
(
jet_partons
);
if
(
i
==
most_backward_FKL_idx
){
//FKL backward emission
extremal
=
std
::
min_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
(
backward_FKL_idx
);
}
else
if
(((
unob_
||
qqxb_
)
&&
i
==
0
)){
// unordered/qqxb
extremal
=
std
::
min_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
((
unob_
)
?
unob_idx
:
qqxb_idx
);
}
else
if
(
i
==
most_forward_FKL_idx
){
extremal
=
std
::
max_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
(
forward_FKL_idx
);
}
else
if
(((
unof_
||
qqxf_
)
&&
i
==
jets
.
size
()
-
1
)){
// unordered/qqxf
extremal
=
std
::
max_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
((
unof_
)
?
unof_idx
:
qqxf_idx
);
}
else
if
((
qqxmid_
&&
i
==
qqxbackjet
)){
extremal
=
std
::
max_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
(
qqxmid1_idx
);
}
else
if
((
qqxmid_
&&
i
==
qqxbackjet
+
1
)){
extremal
=
std
::
min_element
(
first_new_parton
,
end
(
jet_partons
),
rapidity_less
{}
);
extremal
->
set_user_index
(
qqxmid2_idx
);
}
if
(
extremal
!=
end
(
jet_partons
)
&&
!
pass_extremal_cuts
(
*
extremal
,
jets
[
i
])
){
weight_
=
0
;
return
{};
}
}
assert
(
tagged_FKL_extremal
(
jet_partons
));
std
::
sort
(
begin
(
jet_partons
),
end
(
jet_partons
),
rapidity_less
{});
if
(
!
extremal_ok
(
jet_partons
)
||
!
split_preserved_jets
(
jets
,
jet_partons
)
){
weight_
=
0.
;
return
{};
}
return
jet_partons
;
}
bool
PhaseSpacePoint
::
extremal_ok
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
partons
)
const
{
assert
(
std
::
is_sorted
(
begin
(
partons
),
end
(
partons
),
rapidity_less
{}));
if
(
unob_
&&
partons
.
front
().
user_index
()
!=
unob_idx
)
return
false
;
if
(
unof_
&&
partons
.
back
().
user_index
()
!=
unof_idx
)
return
false
;
if
(
qqxb_
&&
partons
.
front
().
user_index
()
!=
qqxb_idx
)
return
false
;
if
(
qqxf_
&&
partons
.
back
().
user_index
()
!=
qqxf_idx
)
return
false
;
return
most_backward_FKL
(
partons
).
user_index
()
==
backward_FKL_idx
&&
most_forward_FKL
(
partons
).
user_index
()
==
forward_FKL_idx
;
}
bool
PhaseSpacePoint
::
split_preserved_jets
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jets
,
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
jet_partons
)
const
{
assert
(
std
::
is_sorted
(
begin
(
jets
),
end
(
jets
),
rapidity_less
{}));
const
auto
split_jets
=
cluster_jets
(
jet_partons
);
// this can happen if two overlapping jets
// are both split into more than one parton
if
(
split_jets
.
size
()
!=
jets
.
size
())
return
false
;
for
(
size_t
i
=
0
;
i
<
split_jets
.
size
();
++
i
){
// this can happen if there are two overlapping jets
// and a parton is assigned to the "wrong" jet
if
(
!
nearby_ep
(
jets
[
i
].
rapidity
(),
split_jets
[
i
].
rapidity
(),
1e-2
)){
return
false
;
}
}
return
true
;
}
template
<
class
Particle
>
Particle
const
&
PhaseSpacePoint
::
most_backward_FKL
(
std
::
vector
<
Particle
>
const
&
partons
)
const
{
return
partons
[
0
+
unob_
+
qqxb_
];
}
template
<
class
Particle
>
Particle
const
&
PhaseSpacePoint
::
most_forward_FKL
(
std
::
vector
<
Particle
>
const
&
partons
)
const
{
const
size_t
idx
=
partons
.
size
()
-
1
-
unof_
-
qqxf_
;
assert
(
idx
<
partons
.
size
());
return
partons
[
idx
];
}
template
<
class
Particle
>
Particle
&
PhaseSpacePoint
::
most_backward_FKL
(
std
::
vector
<
Particle
>
&
partons
)
const
{
return
partons
[
0
+
unob_
+
qqxb_
];
}
template
<
class
Particle
>
Particle
&
PhaseSpacePoint
::
most_forward_FKL
(
std
::
vector
<
Particle
>
&
partons
)
const
{
const
size_t
idx
=
partons
.
size
()
-
1
-
unof_
-
qqxf_
;
assert
(
idx
<
partons
.
size
());
return
partons
[
idx
];
}
bool
PhaseSpacePoint
::
contains_idx
(
fastjet
::
PseudoJet
const
&
jet
,
fastjet
::
PseudoJet
const
&
parton
)
const
{
auto
const
&
constituents
=
jet
.
constituents
();
const
int
idx
=
parton
.
user_index
();
const
bool
injet
=
std
::
find_if
(
begin
(
constituents
),
end
(
constituents
),
[
idx
](
fastjet
::
PseudoJet
const
&
con
){
return
con
.
user_index
()
==
idx
;}
)
!=
end
(
constituents
);
const
double
minpartonjetpt
=
1.
-
param_
.
max_ext_soft_pt_fraction
;
return
((
parton
.
pt
()
>
minpartonjetpt
*
jet
.
pt
())
&&
injet
);
}
bool
PhaseSpacePoint
::
jets_ok
(
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
Born_jets
,
std
::
vector
<
fastjet
::
PseudoJet
>
const
&
partons
)
const
{
fastjet
::
ClusterSequence
cs
(
partons
,
param_
.
jet_param
.
def
);
const
auto
jets
=
sorted_by_rapidity
(
cs
.
inclusive_jets
(
param_
.
jet_param
.
min_pt
));
if
(
jets
.
size
()
!=
Born_jets
.
size
())
return
false
;
int
in_jet
=
0
;
for
(
size_t
i
=
0
;
i
<
jets
.
size
();
++
i
){
assert
(
jets
[
i
].
has_constituents
());
for
(
auto
&&
parton
:
jets
[
i
].
constituents
()){
if
(
is_nonjet_parton
(
parton
))
return
false
;
}
in_jet
+=
jets
[
i
].
constituents
().
size
();
}
const
int
expect_in_jet
=
std
::
count_if
(
partons
.
cbegin
(),
partons
.
cend
(),
is_jet_parton
);
if
(
in_jet
!=
expect_in_jet
)
return
false
;
// note that PseudoJet::contains does not work here
if
(
!
(
contains_idx
(
most_backward_FKL
(
jets
),
most_backward_FKL
(
partons
))
&&
contains_idx
(
most_forward_FKL
(
jets
),
most_forward_FKL
(
partons
))
))
return
false
;
if
(
unob_
&&
!
contains_idx
(
jets
.
front
(),
partons
.
front
()))
return
false
;
if
(
qqxb_
&&
!
contains_idx
(
jets
.
front
(),
partons
.
front
()))
return
false
;
if
(
unof_
&&
!
contains_idx
(
jets
.
back
(),
partons
.
back
()))
return
false
;
if
(
qqxf_
&&
!
contains_idx
(
jets
.
back
(),
partons
.
back
()))
return
false
;
for
(
size_t
i
=
0
;
i
<
jets
.
size
();
++
i
){
assert
(
nearby_ep
(
jets
[
i
].
rapidity
(),
Born_jets
[
i
].
rapidity
(),
1e-2
));
}
return
true
;
}
void
PhaseSpacePoint
::
reconstruct_incoming
(
std
::
array
<
Particle
,
2
>
const
&
Born_incoming
){
std
::
tie
(
incoming_
[
0
].
p
,
incoming_
[
1
].
p
)
=
incoming_momenta
(
outgoing_
);
for
(
size_t
i
=
0
;
i
<
incoming_
.
size
();
++
i
){
incoming_
[
i
].
type
=
Born_incoming
[
i
].
type
;
}
assert
(
momentum_conserved
());
}
double
PhaseSpacePoint
::
phase_space_normalisation
(
int
num_Born_jets
,
int
num_out_partons
)
const
{
return
pow
(
16
*
pow
(
M_PI
,
3
),
num_Born_jets
-
num_out_partons
);
}
bool
PhaseSpacePoint
::
momentum_conserved
()
const
{
fastjet
::
PseudoJet
diff
;
for
(
auto
const
&
in
:
incoming
())
diff
+=
in
.
p
;
const
double
norm
=
diff
.
E
();
for
(
auto
const
&
out
:
outgoing
())
diff
-=
out
.
p
;
return
nearby
(
diff
,
fastjet
::
PseudoJet
{},
norm
);
}
}
//namespace HEJ
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Sep 30, 6:11 AM (20 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
6465635
Default Alt Text
PhaseSpacePoint.cc (27 KB)
Attached To
Mode
rHEJ HEJ
Attached
Detach File
Event Timeline
Log In to Comment