Skip to content

Internal

# BjetTLA.SyntheticHemisphereType.
julia
mutable struct SyntheticHemisphere
    runNumber::Int64
    eventNumber::Int64
    jet::Vector{LorentzVectorCyl{Float64}}
    photon::Vector{LorentzVectorCyl{Float64}}
    normal_vector::Vector{Float64} #This is the normal vector to the plane we used to split the hemispheres
    jet_EMFrac::Vector{Float64}
    jet_fastDIPS::Vector{Float64}

source


# BjetTLA.ATLAS_f_4pMethod.
julia
@. ATLAS_f_4p(x, p) = p[1]*(1-x)^p[2] * x^(-(p[3] + p[4]*log(x)))
p1(1x)p2x(p3+p4log(x))

source


# BjetTLA.ATLAS_f_5pMethod.
julia
@. ATLAS_f_5p(x, p) = p[1]*(1-x)^p[2] * x^(-(p[3] + p[4]*log(x) + p[5]*abs2(log(x))))
p1(1x)p2x(p3+p4log(x)+p5log2(x))

source


# BjetTLA.antiparallel_rotation_matrixMethod.
julia
antiparallel_rotation_matrix(v::AbstractVector, u::AbstractVector)

Returns a rotation matrix `M` such that `M*v` is antiparallel to `u`.

source


# BjetTLA.calc_dbMethod.
julia
calc_db(b::Number, c::Number, u::Number; fc=0.018) -> Float64
calc_db(b::Vector, c::Vector, u::Vector; fc=0.018) -> Vector{Float64}

Compute the b-tagging discriminants, see https://cds.cern.ch/record/2862499 for more detail

The output is: Db=logbcfc+(1fc)u

Note

The log operation usese safeLogRatio to prevent producing Inf and NaN.

source


# BjetTLA.chi2Method.
julia
chi2(os, cs, σs) -> Float64

Calculate chi2 given three arrays of data points, model points and errors.

χ2=i(oici)2σi2
  • os: observed data points

  • cs: calculated model points

  • σs: errors of the observed data points

source


# BjetTLA.extract_dsidMethod.
julia
extract_dsid(path::String) -> String

Extract the DSID from the path of a file. It works by using a regular expression to match the DSID (\d{6}) in the path.

source


# BjetTLA.get_fill_wgtMethod.
julia
get_fill_wgt(evt, pmgWeight, sumWeight;)

Get the fill weight for the event, if the evt has the mcEventWeight property, the weight is calculated as evt.mcEventWeight * (pmgWeight / sumWeight), otherwise the weight is 1.0 for real data.

source


# BjetTLA.get_pmg_weightMethod.
julia
get_pmg_weight(dsid::Union{Integer, AbstractString};
md_path = "/cvmfs/atlas.cern.ch/repo/sw/database/GroupData/dev/PMGTools/PMGxsecDB_mc23.txt")

Get the PMG weight from cvmfs database for a given dsid: returns crossSection_pb * genFiltEff * kFactor

Example

julia
julia> signal_dsid = 510392
510392

julia> BjetTLA.get_pmg_weight(signal_dsid)
0.7831930217100002

julia> BjetTLA.get_pmg_weight("510392")
0.7831930217100002

source


# BjetTLA.get_shortnameMethod.
julia
get_shortname(dsid, map)

Convert dsid to a short name, following the naming map.

source


# BjetTLA.hem_axis_rotation_matrixMethod.
julia
hem_axis_rotation_matrix(b_vec_1::AbstractVector, b_vec_2::, normal_vector::AbstractVector, ref_angle)

Returns a rotation matrix `M` that will rotate b_vec_2 about the axis defined by normal_vector such that the angle
between b_vec_1 and b_vec_2 equals ref_angle.

source


# BjetTLA.load_treesFunction.
julia
load_trees(input_path::String, pattern::String = "*.root"; 
  split::Bool=false, tree_name::String="TreeAlgo_noCalib/nominal",)

Load ROOT trees, chaining multiple files with same Tree name.

source


# BjetTLA.nonoverlap_maskMethod.
julia
nonoverlap_mask(photons, jets; cutoff=0.4) -> Vector{Bool}

Create a mask that can be used to get non-overlapping jets.

Example

julia
mask = nonoverlap_mask(photons, jets)
clean_jets = @view jets[mask]

source


# BjetTLA.optim_fitMethod.
julia
optim_fit(func::Callable, hist0::FHist.Hist1D, p0; sqrt_s=13600)

Fit a χ² fit using a func to a 1D histogram.

  • func: a function that takes two arguments, x and p, and returns a model value.

  • hist0: a 1D histogram to fit.

  • p0: initial parameters.

Note

The func should be defined with @., and the p0 should be a vector. See ATLAS_f_4p for an example.

Also, the x-axis (bincenters()) of the hist0 will be divided by sqrt_s to normalize the x-axis.

It returns the result of the optimization.

Example

julia> hist_mjj12_mask
edges: [130.0, 132.0, 134.0, 136.0, 138.0, 140.0, 142.0, 144.0, 146.0, 148.0  …  482.0, 484.0, 486.0, 488.0, 490.0, 492.0, 494.0, 496.0, 498.0, 500.0]
bin counts: [650.0, 603.0, 649.0, 566.0, 595.0, 593.0, 535.0, 487.0, 492.0, 466.0  …  2.0, 10.0, 13.0, 9.0, 13.0, 10.0, 10.0, 8.0, 15.0, 8.0]
total count: 22293.0

julia> sol4 = optim_fit(ATLAS_f_4p, hist_mjj12_mask, ones(4))
retcode: Success
u: 4-element Vector{Float64}:
  0.0001086906699655396
 91.12405771249554l
  1.2345307604384157
 -0.03547447344008578

julia> sol4.u
4-element Vector{Float64}:
  0.0001086906699655396
 91.12405771249554
  1.2345307604384157
 -0.03547447344008578

source


# BjetTLA.parse_inputFunction.
julia
parse_input(input_path::String, pattern::String = "*.root";  split::Bool=false)

parse input into a list of files: input_path can be a path to a file or directory, and a wildcarded pattern can be passed via the pattern option if input_path is a folder. If split is set to true, a dicitonary of files splitted by dsid is returned

source


# BjetTLA.pass_filter_jetsMethod.
julia
pass_filter_jets(evt, hlt_pfjets, photons; min_pt = 20.0, dR_cutoff=0.4, min_Jvt = 0.2, sort=true)

Filter the HLT jets collection and related variables by doing the following:

  • require pt > min_pt

  • require abs(eta) < dR_cutoff

  • remove jets that overlap with the photons collection by dR < dR_cutoff

  • require jvt > min_Jvt (jvt = jet vertex tagger)

Finally, return the following as a NamedTuple so you can select one or more at call site:

  • clean_jets: the cleaned jets collection

  • clean_jets_btags: the cleaned jets b-tagging values

  • clean_jets_emfracs: the cleaned jets EM fractions

  • clean_jets_jvts: the cleaned jets JVT values

Note

If sort is true, all the returnred arrays are sorted by the jet pt in descending order.

source


# BjetTLA.pass_filter_photonsMethod.
julia
clean_photons(hlt_photons; eta_cuts = true, min_pt = 20.0) -> vector of photon lorentz vectors

Clean photons from the HLT photon collection. The cleaning is done by removing photons that satisfy the any of the following conditions:

  • pt < min_pt

  • abs(eta) > 2.37

  • 1.37 < abs(eta) < 1.52

source


# BjetTLA.plane_bisectorMethod.
julia
plane_bisector(v::AbstractVector, u::AbstractVector)

Returns a vector perpendicular to the plane which bisects the angle formed by the vectors v and u.

source


# BjetTLA.private_mainMethod.
julia
private_main(path::String, main::Function; isMC=false, kw...)

Single root file entry point for the main analysis loop. This function is used to parse the metadata histogram and get the sum of weights for the MC samples.

It prepares the following weigts:

  • sumWeight: extracted from ROOTFile["MetaData_EventCount"] histogram.

  • pmgWeight: the weight for the PMG samples, see get_pmg_weight

  • kw...: additional keyword arguments to be passed to the main function as keyword arguments.

Finally, it will run and return main(tree; sumWeight, pmgWeight, kw...).

Note

Currently it's assumed TTree is stored in the TreeAlgo_noCalib/nominal inside the root file. Systematics is not handled in this function.

source


# BjetTLA.safeLogRatioMethod.
julia
safeLogRatio(num,den)

Safe log computation, to emulate athena implementation:

  • If iszero(den), return 15.0

  • If iszero(num), return -10.0

  • otherwise, return log(num/den) as expected

source


# BjetTLA.sensitivity_studyMethod.
julia
sensitivity_study(tree::LazyTree; sumWeight = 1.0, pmgWeight = 1.0) -> NamedTuple of Histograms

Main analysis loop for the sensitivity study. It should be used with the private_main function.

Example

julia
julia> npath = "/data/jiling/TLA/eos_ntuples/mc23a/Zprime_bb/nv2/user.sfranche.510392.MGPy8EG_S1_qqa_Ph25_mRp125_gASp1_qContentUDSC.e8514_s4162_r15315.nv2_tree.root/merged.root"

julia> mc_hists_sensitivity = BjetTLA.private_main(npath, BjetTLA.sensitivity_study; isMC=true);

source


# BjetTLA.skip_JZ_eventFunction.
julia
pass_JZ_cleaning(j_pt, jz, eps=0.2)

Apply cleaning filter for JZ slices, checks if the average pT of the two leading jets is in the expected range for slice jz, within a eps tolerance.

source


# BjetTLA.split_by_dsidMethod.
julia
split_by_dsid(strings::Vector{String})

Splits a vector of strings into a dictionary based on the dsid, a sequence of six digits preceeded and followed by ".". If that criteria fails, looks for a run number instead (sequence of eight digits).

source


# BjetTLA.split_hemispheresMethod.
julia
split_hemispheres(evt) -> Tuple{SyntheticHemisphere, SyntheticHemisphere}

Given a single event, this function will split the event into two hemispheres based on the two leading b-jets in the event. The function returns two SyntheticHemisphere objects.

source


# BjetTLA.@cutflowMacro.
julia
@cutflow counter hist name_list name wgt

Convinient macro to generate cutflow histogram filling code. It will increment the counter by 1, check if the name_list[counter] is equal to expected name, and then push the counter to the hist with the given wgt.

BjetTLA.@cutflow counter hist name_list name wgt

is equivalent to:

counter += 1
@assert name_list[counter] == name
atomic_push!(hist, counter, wgt)

source


# BjetTLA.@fourmomentaMacro.
julia
@fourmomenta evt obj_prefix

Creates the fourmomenta for a given object type in the event. Returns a StructArray of LorentzVectorCyl.

It assumes that the event is a structure containig all the projections of the 4-vectors: evt.obj_pt, evt.obj_eta, evt.obj_phi, evt.obj_m (or evt.obj_E for jets).

Concretely,

julia
@fourmomenta evt ph

would expand to:

julia
StructArray(LorentzVectorCyl(
    evt.ph_pt,
    evt.ph_eta,
    evt.ph_phi,
    evt.ph_m
))

For jets, it will call fromPtEtaPhiE and the return type stays the same.

Example

julia
julia> for evt in tree
            hlt_jets = @fourmomenta evt jet
            count(>(25), hlt_jets.pt) # count how many jets have pt > 25 GeV
            ...
        end

source