diff --git a/Corrections.py b/Corrections.py index 7821356f..ccf6250f 100644 --- a/Corrections.py +++ b/Corrections.py @@ -172,6 +172,7 @@ def __init__( self.Vpt_ = None self.JetVetoMap_ = None self.btag_shape_norm_ = None + self.bosonicRecoil_ = None @property def xs_db(self): @@ -370,6 +371,21 @@ def trg(self): ) return self.trg_ + @property + def bosonicRecoil(self): + if self.bosonicRecoil_ is None: + from .bosonicRecoil import BosonicRecoilCorrection + + self.bosonicRecoil_ = BosonicRecoilCorrection( + period=self.period, + config=self.to_apply.get("bosonicRecoil", {}), + isData=self.isData, + dataset_name=self.dataset_name, + process_name=self.process_name, + process_cfg=self.process_cfg, + ) + return self.bosonicRecoil_ + @property def btag_norm(self): if self.btag_shape_norm_ is None: @@ -706,6 +722,20 @@ def getNormalisationCorrections( return df, all_weights + def applyBosonicRecoil(self, df): + if self.stage != "HistTuple": + return df + + if self.isData: + return df + + if "bosonicRecoil" not in self.to_apply: + return df + + return self.bosonicRecoil.applyBosonicRecoilCorrections( + df, self.process_cfg, self.to_apply + ) + # amcatnlo problem # https://cms-talk.web.cern.ch/t/correct-way-to-stitch-lo-w-jet-inclusive-and-jet-binned-samples/17651/3 diff --git a/bosonicRecoil.h b/bosonicRecoil.h new file mode 100644 index 00000000..b46a8714 --- /dev/null +++ b/bosonicRecoil.h @@ -0,0 +1,297 @@ +#pragma once + +#include "correction.h" +#include "corrections.h" + +namespace correction { + + // Bosonic recoil corrections following Higgs LepRare recommendation: https://cms-higgs-leprare.docs.cern.ch/htt-common/V_recoil/ + + class BosonicRecoilProvider : public CorrectionsBase { + public: + using LorentzVectorM = correction::LorentzVectorM; + using RVecF = correction::RVecF; + using RVecI = correction::RVecI; + + struct PolarVector { + double pt{0.}; + double phi{0.}; + }; + struct XYVector { + double px{0.}; + double py{0.}; + }; + + struct RecoilResult { + double upara{0.}; + double uperp{0.}; + double upara_corr{0.}; + double uperp_corr{0.}; + double met_pt_corr{0.}; + double met_phi_corr{0.}; + }; + + struct RecoilSystematics { + double hpara{0.}; + double hperp{0.}; + double hpara_variation{0.}; + double hperp_variation{0.}; + double met_pt{0.}; + double met_phi{0.}; + }; + + BosonicRecoilProvider(const std::string& jsonFile) + : cset_(CorrectionSet::from_file(jsonFile)), + corr_rescaling_(cset_->at("Recoil_correction_Rescaling")), + corr_qmphist_(cset_->at("Recoil_correction_QuantileMapHist")), + corr_qmpfit_(cset_->at("Recoil_correction_QuantileMapFit")), + corr_unc_(cset_->at("Recoil_correction_Uncertainty")) {} + + // start of workaround if AnaProd does not save GenPart inputs + static bool IsNeutrino(const int pdgId) { + const int apdg = std::abs(pdgId); + return apdg == 12 || apdg == 14 || apdg == 16; + } + + static bool IsChargedLepton(const int pdgId) { + const int apdg = std::abs(pdgId); + return apdg == 11 || apdg == 13 || apdg == 15; + } + + static bool PassLHEBosonParticleSelection(const int pdgId, const int status, const bool includeNeutrinos) { + // LHEPart_status == -1 incoming, 1 outgoing + if (status != 1) + return false; + + const bool isChargedLep = IsChargedLepton(pdgId); + const bool isNu = IsNeutrino(pdgId); + + if (isChargedLep) + return true; + if (includeNeutrinos && isNu) + return true; + return false; + } + + static LorentzVectorM GetLHEBosonP4(const RVecF& pt, + const RVecF& eta, + const RVecF& phi, + const RVecF& mass, + const RVecI& pdgId, + const RVecI& status) { + const size_t n = pt.size(); + if (eta.size() != n || phi.size() != n || mass.size() != n || pdgId.size() != n || status.size() != n) { + throw std::runtime_error("GetLHEBosonP4: inconsistent LHEPart collection sizes"); + } + + LorentzVectorM p4; + for (size_t i = 0; i < n; ++i) { + if (!PassLHEBosonParticleSelection(pdgId[i], status[i], true)) + continue; + p4 += LorentzVectorM(pt[i], eta[i], phi[i], mass[i]); + } + return p4; + } + + static bool HasValidLepVisGenMatch(const int lep1_gen_kind, const int lep2_gen_kind) { + // for bbtautau anaTuples, tau1_gen_kind==NoMatch is the default when gen matching is unavailable + // the following is used for the workaround calculations. + return lep1_gen_kind != 6 && + lep2_gen_kind != 6; // 6 = GenLeptonMatch::NoMatch in anaTuples for tau_gen_kind + } + + static LorentzVectorM GetVisibleBosonP4FromLepGenVis(const float lep1_pt, + const float lep1_eta, + const float lep1_phi, + const float lep1_mass, + const float lep2_pt, + const float lep2_eta, + const float lep2_phi, + const float lep2_mass) { + LorentzVectorM lep1(lep1_pt, lep1_eta, lep1_phi, lep1_mass); + LorentzVectorM lep2(lep2_pt, lep2_eta, lep2_phi, lep2_mass); + return lep1 + lep2; + } + + // the function below is called when NoMatch for tau1_gen_kind or tau2_gen_kind + // the puppimet_pt and puppimet_phi are returned + static RecoilResult GetIdentityRecoilResult( + double bosonPt, double bosonPhi, double visPt, double visPhi, double metPt, double metPhi) { + const auto [upara, uperp] = computeU(bosonPt, bosonPhi, visPt, visPhi, metPt, metPhi); + return {upara, uperp, upara, uperp, metPt, metPhi}; + } + + // the function below is called when NoMatch for tau1_gen_kind or tau2_gen_kind + // the puppimet_pt and puppimet_phi are returned + static RecoilSystematics GetIdentityRecoilSystematics( + double bosonPt, double bosonPhi, double visPt, double visPhi, double metPt, double metPhi) { + const auto [hpara, hperp] = computeH(bosonPt, bosonPhi, visPt, visPhi, metPt, metPhi); + return {hpara, hperp, hpara, hperp, metPt, metPhi}; + } + + // end of workaround if AnaProd does not save GenPart inputs + + static bool PassRecoilJetHornLogic(const float pt, const float eta) { + const float abs_eta = std::abs(eta); + const bool in_horn = (abs_eta > 2.5f && abs_eta < 3.0f); + if (in_horn) + return pt > 50.f; + return pt > 30.f; + } + + static float GetRecoilNJetFromReco(const float b1_pt, + const float b1_eta, + const float b2_pt, + const float b2_eta, + const RVecF& vbf_pt, + const RVecF& vbf_eta) { + if (vbf_pt.size() != vbf_eta.size()) { + throw std::runtime_error("GetRecoilNJetFromReco: inconsistent VBF jet collection size"); + } + int nbjet = 0; + if (PassRecoilJetHornLogic(b1_pt, b1_eta)) + ++nbjet; + if (PassRecoilJetHornLogic(b2_pt, b2_eta)) + ++nbjet; + + int nvbfjet = 0; + for (std::size_t i = 0; i < vbf_pt.size(); ++i) { + if (PassRecoilJetHornLogic(vbf_pt[i], vbf_eta[i])) + ++nvbfjet; + } + + const int njet = nbjet + nvbfjet; + if (njet <= 0) + return 0.f; + if (njet == 1) + return 1.f; + return 2.f; + } + + static XYVector ptPhiToXY(double pt, double phi) { return {pt * std::cos(phi), pt * std::sin(phi)}; } + + static PolarVector xyToPtPhi(double px, double py) { return {std::hypot(px, py), std::atan2(py, px)}; } + + static std::pair projectParallelPerp(double x, double y, double refx, double refy) { + const double refpt = std::hypot(refx, refy); + if (refpt < 1e-12) + return {0., 0.}; + const double ux = refx / refpt; + const double uy = refy / refpt; + const double vx = -uy; + const double vy = ux; + return {x * ux + y * uy, x * vx + y * vy}; + } + + static XYVector buildFromParallelPerp(double para, double perp, double refx, double refy) { + const double refpt = std::hypot(refx, refy); + if (refpt < 1e-12) + return {0., 0.}; + const double ux = refx / refpt; + const double uy = refy / refpt; + const double vx = -uy; + const double vy = ux; + return {para * ux + perp * vx, para * uy + perp * vy}; + } + + static std::pair computeU( + double bosonPt, double bosonPhi, double visPt, double visPhi, double metPt, double metPhi) { + const auto V = ptPhiToXY(bosonPt, bosonPhi); + const auto Vvis = ptPhiToXY(visPt, visPhi); + const auto MET = ptPhiToXY(metPt, metPhi); + const double Ux = MET.px + Vvis.px - V.px; + const double Uy = MET.py + Vvis.py - V.py; + return projectParallelPerp(Ux, Uy, V.px, V.py); + } + + static std::pair computeH( + double bosonPt, double bosonPhi, double visPt, double visPhi, double metPt, double metPhi) { + const auto V = ptPhiToXY(bosonPt, bosonPhi); + const auto Vvis = ptPhiToXY(visPt, visPhi); + const auto MET = ptPhiToXY(metPt, metPhi); + const double Hx = -Vvis.px - MET.px; + const double Hy = -Vvis.py - MET.py; + return projectParallelPerp(Hx, Hy, V.px, V.py); + } + + static PolarVector metFromU( + double bosonPt, double bosonPhi, double visPt, double visPhi, double upara, double uperp) { + const auto V = ptPhiToXY(bosonPt, bosonPhi); + const auto Vvis = ptPhiToXY(visPt, visPhi); + const auto U = buildFromParallelPerp(upara, uperp, V.px, V.py); + return xyToPtPhi(U.px - Vvis.px + V.px, U.py - Vvis.py + V.py); + } + + static PolarVector metFromH( + double bosonPt, double bosonPhi, double visPt, double visPhi, double hpara, double hperp) { + const auto V = ptPhiToXY(bosonPt, bosonPhi); + const auto Vvis = ptPhiToXY(visPt, visPhi); + const auto H = buildFromParallelPerp(hpara, hperp, V.px, V.py); + return xyToPtPhi(-H.px - Vvis.px, -H.py - Vvis.py); + } + + double correctComponent(const std::string& order, + double njet, + double ptll, + const std::string& var, + double val, + const std::string& method) const { + if (method == "Rescaling") { + return safeEvaluate(corr_rescaling_, order, njet, ptll, var, val); + } + if (method == "QuantileMapHist") { + return safeEvaluate(corr_qmphist_, order, njet, ptll, var, val); + } + if (method == "QuantileMapFit") { + if (std::abs(val) > 150.) { + return safeEvaluate(corr_rescaling_, order, njet, ptll, var, val); + } + throw std::runtime_error("QuantileMapFit not implemented in the current setup"); + } + throw std::runtime_error("Unknown recoil correction method: " + method); + } + + RecoilResult correctMET(const std::string& order, + double njet, + double ptll, + double bosonPt, + double bosonPhi, + double visPt, + double visPhi, + double metPt, + double metPhi, + const std::string& method) const { + const auto [upara, uperp] = computeU(bosonPt, bosonPhi, visPt, visPhi, metPt, metPhi); + const double uparaCorr = correctComponent(order, njet, ptll, "Upara", upara, method); + const double uperpCorr = correctComponent(order, njet, ptll, "Uperp", uperp, method); + const auto metCorr = metFromU(bosonPt, bosonPhi, visPt, visPhi, uparaCorr, uperpCorr); + return {upara, uperp, uparaCorr, uperpCorr, metCorr.pt, metCorr.phi}; + } + + RecoilSystematics applyUncertainty(const std::string& order, + double njet, + double ptll, + double bosonPt, + double bosonPhi, + double visPt, + double visPhi, + double metPtNom, + double metPhiNom, + const std::string& syst) const { + if (syst != "RespUp" && syst != "RespDown" && syst != "ResolUp" && syst != "ResolDown") { + throw std::runtime_error("Unknown recoil systematic: " + syst); + } + + const auto [hpara, hperp] = computeH(bosonPt, bosonPhi, visPt, visPhi, metPtNom, metPhiNom); + const double hparaVar = safeEvaluate(corr_unc_, order, njet, ptll, std::string("Hpara"), hpara, syst); + const double hperpVar = safeEvaluate(corr_unc_, order, njet, ptll, std::string("Hperp"), hperp, syst); + const auto metVar = metFromH(bosonPt, bosonPhi, visPt, visPhi, hparaVar, hperpVar); + return {hpara, hperp, hparaVar, hperpVar, metVar.pt, metVar.phi}; + } + + private: + std::unique_ptr cset_; + Correction::Ref corr_rescaling_, corr_qmphist_, corr_qmpfit_, corr_unc_; + }; + +} //namespace correction \ No newline at end of file diff --git a/bosonicRecoil.py b/bosonicRecoil.py new file mode 100644 index 00000000..3d0a2ad4 --- /dev/null +++ b/bosonicRecoil.py @@ -0,0 +1,268 @@ +import os +import ROOT +from .CorrectionsCore import * + +# Bosonic recoil corrections following recommendations from https://cms-higgs-leprare.docs.cern.ch/htt-common/V_recoil/ + + +class BosonicRecoilCorrection: + initialized = False + + json_map = { + "Run3_2022": "Recoil_corrections_2022preEE_v5.json.gz", + "Run3_2022EE": "Recoil_corrections_2022postEE_v5.json.gz", + "Run3_2023": "Recoil_corrections_2023preBPix_v5.json.gz", + "Run3_2023BPix": "Recoil_corrections_2023postBPix_v5.json.gz", + "Run3_2024": "Recoil_corrections_2024_v5.json.gz", + } + + def __init__(self, period, config, isData, dataset_name, process_name, process_cfg): + self.period = period + self.config = config + self.isData = isData + self.dataset_name = dataset_name + self.process_name = process_name + self.process_cfg = process_cfg + + json_file = os.path.join( + os.environ["ANALYSIS_PATH"], + "Corrections/data/hleprare/bosonicRecoil", + self.json_map[period], + ) + + if not BosonicRecoilCorrection.initialized: + headers_dir = os.path.dirname(os.path.abspath(__file__)) + header_path = os.path.join(headers_dir, "bosonicRecoil.h") + ROOT.gInterpreter.Declare(f'#include "{header_path}"') + ROOT.gInterpreter.ProcessLine( + f'::correction::BosonicRecoilProvider::Initialize("{json_file}")' + ) + BosonicRecoilCorrection.initialized = True + + def applyBosonicRecoilCorrections(self, df, process_cfg, to_apply): + if self.isData: + return df + + if "bosonicRecoil" not in to_apply: + return df + + recoil_cfg = process_cfg.get("corrections", {}).get("bosonicRecoil", {}) + if not recoil_cfg.get("enabled", False): + return df + + recoil_order = recoil_cfg.get("order", "None") + if recoil_order not in ["LO", "NLO", "NNLO"]: + raise RuntimeError( + f"Process order {recoil_order} not recognized for Bosonic Recoil Corrections. Supported values are 'LO', 'NLO', 'NNLO'." + ) + + print(f"Applying bosonic recoil corrections with order {recoil_order}.") + recoil_method = to_apply["bosonicRecoil"].get("method", "QuantileMapHist") + apply_systematics = to_apply["bosonicRecoil"].get("apply_systematics", True) + + column_names = [str(c) for c in df.GetColumnNames()] + has_gen_recoil_inputs = all( + c in column_names + for c in [ + "recoil_GenBoson_pt", + "recoil_GenBoson_phi", + "recoil_GenBoson_vis_pt", + "recoil_GenBoson_vis_phi", + ] + ) + + df = df.Define("recoil_ptll", "static_cast(LHE_Vpt)") + df = df.Define( + "recoil_njet", + "::correction::BosonicRecoilProvider::GetRecoilNJetFromReco(" + "static_cast(b1_pt), " + "static_cast(b1_eta), " + "static_cast(b2_pt), " + "static_cast(b2_eta), " + "VBFJet_pt, " + "VBFJet_eta)", + ) + + if has_gen_recoil_inputs: # this is following hleprare recommendation + df = df.Define("recoil_boson_pt", "static_cast(recoil_GenBoson_pt)") + df = df.Define( + "recoil_boson_phi", "static_cast(recoil_GenBoson_phi)" + ) + df = df.Define( + "recoil_boson_vis_pt", "static_cast(recoil_GenBoson_vis_pt)" + ) + df = df.Define( + "recoil_boson_vis_phi", "static_cast(recoil_GenBoson_vis_phi)" + ) + df = df.Define( + "recoil_nom_result", + f"::correction::BosonicRecoilProvider::getGlobal().correctMET(" + f'"{recoil_order}", ' + f"static_cast(recoil_njet), " + f"static_cast(recoil_ptll), " + f"static_cast(recoil_boson_pt), " + f"static_cast(recoil_boson_phi), " + f"static_cast(recoil_boson_vis_pt), " + f"static_cast(recoil_boson_vis_phi), " + f"static_cast(PuppiMET_pt), " + f"static_cast(PuppiMET_phi), " + f'"{recoil_method}")', + ) + else: # workaround for when Gen-level recoil inputs are not available + df = df.Define( + "recoil_lhe_boson_p4", + "::correction::BosonicRecoilProvider::GetLHEBosonP4(" + "LHEPart_pt, LHEPart_eta, LHEPart_phi, LHEPart_mass, " + "LHEPart_pdgId, LHEPart_status)", + ) + df = df.Define( + "recoil_lep_vis_boson_p4", + "::correction::BosonicRecoilProvider::GetVisibleBosonP4FromLepGenVis(" + "static_cast(tau1_gen_vis_pt), " + "static_cast(tau1_gen_vis_eta), " + "static_cast(tau1_gen_vis_phi), " + "static_cast(tau1_gen_vis_mass), " + "static_cast(tau2_gen_vis_pt), " + "static_cast(tau2_gen_vis_eta), " + "static_cast(tau2_gen_vis_phi), " + "static_cast(tau2_gen_vis_mass))", + ) + df = df.Define( + "recoil_boson_pt", "static_cast(recoil_lhe_boson_p4.pt())" + ) + df = df.Define( + "recoil_boson_phi", "static_cast(recoil_lhe_boson_p4.phi())" + ) + df = df.Define( + "recoil_boson_vis_pt", + "static_cast(recoil_lep_vis_boson_p4.pt())", + ) + df = df.Define( + "recoil_boson_vis_phi", + "static_cast(recoil_lep_vis_boson_p4.phi())", + ) + + df = df.Define( + "recoil_valid_lep_vis", + "::correction::BosonicRecoilProvider::HasValidLepVisGenMatch(" + "static_cast(tau1_gen_kind), " + "static_cast(tau2_gen_kind))", + ) + + df = df.Define( + "recoil_nom_result", + f""" + if (!recoil_valid_lep_vis) {{ + return ::correction::BosonicRecoilProvider::GetIdentityRecoilResult( + static_cast(recoil_boson_pt), + static_cast(recoil_boson_phi), + static_cast(recoil_boson_vis_pt), + static_cast(recoil_boson_vis_phi), + static_cast(PuppiMET_pt), + static_cast(PuppiMET_phi) + ); + }} + return ::correction::BosonicRecoilProvider::getGlobal().correctMET( + "{recoil_order}", + static_cast(recoil_njet), + static_cast(recoil_ptll), + static_cast(recoil_boson_pt), + static_cast(recoil_boson_phi), + static_cast(recoil_boson_vis_pt), + static_cast(recoil_boson_vis_phi), + static_cast(PuppiMET_pt), + static_cast(PuppiMET_phi), + "{recoil_method}" + ); + """, + ) + print( + "Warning: Gen-level recoil inputs not available. Using workaround with LHE boson and gen visible tau pair. This is a temporary solution for bosonic recoil. Make sure that necessary GenPart related inputs are saved in AnaTuple stage" + ) + + df = df.Define( + "PuppiMET_pt_recoil", "static_cast(recoil_nom_result.met_pt_corr)" + ) + + df = df.Define( + "PuppiMET_phi_recoil", "static_cast(recoil_nom_result.met_phi_corr)" + ) + + df = df.Define("recoil_upara", "static_cast(recoil_nom_result.upara)") + + df = df.Define("recoil_uperp", "static_cast(recoil_nom_result.uperp)") + + df = df.Define( + "recoil_upara_corr", "static_cast(recoil_nom_result.upara_corr)" + ) + + df = df.Define( + "recoil_uperp_corr", "static_cast(recoil_nom_result.uperp_corr)" + ) + + if apply_systematics: + for syst in ["RespUp", "RespDown", "ResolUp", "ResolDown"]: + result_name = f"recoil_{syst}" + if has_gen_recoil_inputs: + df = df.Define( + result_name, + f"::correction::BosonicRecoilProvider::getGlobal().applyUncertainty(" + f'"{recoil_order}", ' + f"static_cast(recoil_njet), " + f"static_cast(recoil_ptll), " + f"static_cast(recoil_boson_pt), " + f"static_cast(recoil_boson_phi), " + f"static_cast(recoil_boson_vis_pt), " + f"static_cast(recoil_boson_vis_phi), " + f"static_cast(PuppiMET_pt_recoil), " + f"static_cast(PuppiMET_phi_recoil), " + f'"{syst}")', + ) + else: + df = df.Define( + result_name, + f""" + if (!recoil_valid_lep_vis) {{ + return ::correction::BosonicRecoilProvider::GetIdentityRecoilSystematics( + static_cast(recoil_boson_pt), + static_cast(recoil_boson_phi), + static_cast(recoil_boson_vis_pt), + static_cast(recoil_boson_vis_phi), + static_cast(PuppiMET_pt_recoil), + static_cast(PuppiMET_phi_recoil) + ); + }} + return ::correction::BosonicRecoilProvider::getGlobal().applyUncertainty( + "{recoil_order}", + static_cast(recoil_njet), + static_cast(recoil_ptll), + static_cast(recoil_boson_pt), + static_cast(recoil_boson_phi), + static_cast(recoil_boson_vis_pt), + static_cast(recoil_boson_vis_phi), + static_cast(PuppiMET_pt_recoil), + static_cast(PuppiMET_phi_recoil), + "{syst}" + ); + """, + ) + + df = df.Define( + f"PuppiMET_pt_recoil_{syst}", + f"static_cast({result_name}.met_pt)", + ) + + df = df.Define( + f"PuppiMET_phi_recoil_{syst}", + f"static_cast({result_name}.met_phi)", + ) + + return df + + @property + def method(self): + return self.config.get("method", "QuantileMapHist") + + @property + def apply_systematics(self): + return self.config.get("apply_systematics", True) diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_2022postEE_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_2022postEE_v5.json.gz new file mode 100644 index 00000000..603ab88b --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_2022postEE_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9db97add064b76c9aed6473a658fcea1fdca67803e820dde172d3072163636c4 +size 287578 diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_2022preEE_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_2022preEE_v5.json.gz new file mode 100644 index 00000000..b9158c32 --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_2022preEE_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60e2e9f0dac9960c148c5ca6af4f7fb7817c3f02631c98525233b5b33b2f4560 +size 266069 diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_2023postBPix_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_2023postBPix_v5.json.gz new file mode 100644 index 00000000..afbf98c3 --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_2023postBPix_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5525b3ee287a379691a73bf95df4457ff3c618e2c3da4be3cbc1e327c829b658 +size 272193 diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_2023preBPix_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_2023preBPix_v5.json.gz new file mode 100644 index 00000000..9ced962b --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_2023preBPix_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0da20546df5dd9c56c969264e195711c10cff8d492906ca0501333f406689a66 +size 280366 diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_2024_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_2024_v5.json.gz new file mode 100644 index 00000000..2228e2d7 --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_2024_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b732ac3a8386c21537e8895838e365facd4155e88679ca76be155435231b65dd +size 301202 diff --git a/data/hleprare/bosonicRecoil/Recoil_corrections_v5.json.gz b/data/hleprare/bosonicRecoil/Recoil_corrections_v5.json.gz new file mode 100644 index 00000000..d58ece2b --- /dev/null +++ b/data/hleprare/bosonicRecoil/Recoil_corrections_v5.json.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fa297c9ca5e952eff1c259384704a77e8e632ac170a5d884be737e2f1f8e4c4 +size 1422220