File indexing completed on 2024-07-03 04:18:02
0001 #ifndef L1Trigger_Phase2L1GT_L1GT3BodyCut_h
0002 #define L1Trigger_Phase2L1GT_L1GT3BodyCut_h
0003
0004 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0005 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0006 #include "DataFormats/L1Trigger/interface/P2GTCandidate.h"
0007
0008 #include "L1Trigger/Phase2L1GT/interface/L1GTInvariantMassError.h"
0009
0010 #include "L1Trigger/Phase2L1GT/interface/L1GTScales.h"
0011
0012 #include "L1GTSingleInOutLUT.h"
0013 #include "L1GTOptionalParam.h"
0014
0015 #include <optional>
0016 #include <cinttypes>
0017
0018 namespace l1t {
0019
0020 class L1GT3BodyCut {
0021 public:
0022 L1GT3BodyCut(const edm::ParameterSet& config,
0023 const edm::ParameterSet& lutConfig,
0024 const L1GTScales& scales,
0025 bool inv_mass_checks = false)
0026 : scales_(scales),
0027 coshEtaLUT_(lutConfig.getParameterSet("cosh_eta_lut")),
0028 coshEtaLUT2_(lutConfig.getParameterSet("cosh_eta_lut2")),
0029 cosPhiLUT_(lutConfig.getParameterSet("cos_phi_lut")),
0030 minInvMassSqrDiv2_(getOptionalParam<int64_t, double>("minInvMass",
0031 config,
0032 [&](double value) {
0033 return std::round(scales.to_hw_InvMassSqrDiv2(value) *
0034 cosPhiLUT_.output_scale());
0035 })),
0036 maxInvMassSqrDiv2_(getOptionalParam<int64_t, double>("maxInvMass",
0037 config,
0038 [&](double value) {
0039 return std::round(scales.to_hw_InvMassSqrDiv2(value) *
0040 cosPhiLUT_.output_scale());
0041 })),
0042 minTransMassSqrDiv2_(getOptionalParam<int64_t, double>(
0043 "minTransMass",
0044 config,
0045 [&](double value) {
0046 return std::round(scales.to_hw_TransMassSqrDiv2(value) * cosPhiLUT_.output_scale());
0047 })),
0048 maxTransMassSqrDiv2_(getOptionalParam<int64_t, double>(
0049 "maxTransMass",
0050 config,
0051 [&](double value) {
0052 return std::round(scales.to_hw_TransMassSqrDiv2(value) * cosPhiLUT_.output_scale());
0053 })),
0054 scaleNormalShift_(std::round(std::log2(std::ceil(coshEtaLUT_.output_scale() / coshEtaLUT2_.output_scale())))),
0055 invMassResolutionReduceShift_([&]() {
0056 if (minInvMassSqrDiv2_) {
0057 return std::max<int>(
0058 std::ceil(std::log2(minInvMassSqrDiv2_.value() * cosPhiLUT_.output_scale() + 1.0)) - 16, 0);
0059 } else if (maxInvMassSqrDiv2_) {
0060 return std::max<int>(std::ceil(std::log2(maxInvMassSqrDiv2_.value() * cosPhiLUT_.output_scale())) - 16,
0061 0);
0062 } else {
0063 return 0;
0064 }
0065 }()),
0066 transMassResolutionReduceShift_([&]() {
0067 if (minTransMassSqrDiv2_) {
0068 return std::max<int>(
0069 std::ceil(std::log2(minTransMassSqrDiv2_.value() * cosPhiLUT_.output_scale() + 1.0)) - 16, 0);
0070 } else if (maxTransMassSqrDiv2_) {
0071 return std::max<int>(std::ceil(std::log2(maxTransMassSqrDiv2_.value() * cosPhiLUT_.output_scale())) - 16,
0072 0);
0073 } else {
0074 return 0;
0075 }
0076 }()),
0077 inv_mass_checks_(inv_mass_checks) {}
0078
0079 bool checkObjects(const P2GTCandidate& obj1,
0080 const P2GTCandidate& obj2,
0081 const P2GTCandidate& obj3,
0082 InvariantMassErrorCollection& massErrors) const {
0083 bool res = true;
0084
0085 if (minInvMassSqrDiv2_ || maxInvMassSqrDiv2_) {
0086 int64_t invMassSqrDiv2 = (calc2BodyInvMass(obj1, obj2, massErrors) >> invMassResolutionReduceShift_) +
0087 (calc2BodyInvMass(obj1, obj3, massErrors) >> invMassResolutionReduceShift_) +
0088 (calc2BodyInvMass(obj2, obj3, massErrors) >> invMassResolutionReduceShift_);
0089
0090 res &= minInvMassSqrDiv2_ ? invMassSqrDiv2 > minInvMassSqrDiv2_.value() >> invMassResolutionReduceShift_ : true;
0091 res &= maxInvMassSqrDiv2_ ? invMassSqrDiv2 < maxInvMassSqrDiv2_.value() >> invMassResolutionReduceShift_ : true;
0092 }
0093
0094 if (minTransMassSqrDiv2_ || maxTransMassSqrDiv2_) {
0095 int64_t transMassDiv2 = (calc2BodyTransMass(obj1, obj2) >> transMassResolutionReduceShift_) +
0096 (calc2BodyTransMass(obj1, obj3) >> transMassResolutionReduceShift_) +
0097 (calc2BodyTransMass(obj2, obj3) >> transMassResolutionReduceShift_);
0098
0099 res &= minTransMassSqrDiv2_ ? transMassDiv2 > minTransMassSqrDiv2_.value() >> transMassResolutionReduceShift_
0100 : true;
0101 res &= maxTransMassSqrDiv2_ ? transMassDiv2 < maxTransMassSqrDiv2_.value() >> transMassResolutionReduceShift_
0102 : true;
0103 }
0104
0105 return res;
0106 }
0107
0108 static void fillPSetDescription(edm::ParameterSetDescription& desc) {
0109 desc.addOptional<double>("minInvMass");
0110 desc.addOptional<double>("maxInvMass");
0111 desc.addOptional<double>("minTransMass");
0112 desc.addOptional<double>("maxTransMass");
0113 }
0114
0115 private:
0116 static constexpr int HW_PI = 1 << (P2GTCandidate::hwPhi_t::width - 1);
0117
0118 int64_t calc2BodyInvMass(const P2GTCandidate& obj1,
0119 const P2GTCandidate& obj2,
0120 InvariantMassErrorCollection& massErrors) const {
0121 uint32_t dEta = (obj1.hwEta() > obj2.hwEta()) ? obj1.hwEta().to_int() - obj2.hwEta().to_int()
0122 : obj2.hwEta().to_int() - obj1.hwEta().to_int();
0123 int32_t lutCoshDEta = dEta < L1GTSingleInOutLUT::DETA_LUT_SPLIT
0124 ? coshEtaLUT_[dEta]
0125 : coshEtaLUT2_[dEta - L1GTSingleInOutLUT::DETA_LUT_SPLIT];
0126
0127
0128 uint32_t dPhi = HW_PI - abs(abs(obj1.hwPhi().to_int() - obj2.hwPhi().to_int()) - HW_PI);
0129
0130
0131 int32_t lutCosDPhi = dPhi >= HW_PI ? -cosPhiLUT_[dPhi] : cosPhiLUT_[dPhi];
0132
0133 int64_t invMassSqrDiv2;
0134
0135 if (dEta < L1GTSingleInOutLUT::DETA_LUT_SPLIT) {
0136
0137 invMassSqrDiv2 = obj1.hwPT().to_int64() * obj2.hwPT().to_int64() * (lutCoshDEta - lutCosDPhi);
0138 } else {
0139
0140 invMassSqrDiv2 = obj1.hwPT().to_int64() * obj2.hwPT().to_int64() * lutCoshDEta;
0141 }
0142
0143 if (inv_mass_checks_) {
0144 double precInvMass =
0145 scales_.pT_lsb() * std::sqrt(2 * obj1.hwPT().to_double() * obj2.hwPT().to_double() *
0146 (std::cosh(dEta * scales_.eta_lsb()) - std::cos(dPhi * scales_.phi_lsb())));
0147
0148 double lutInvMass =
0149 scales_.pT_lsb() * std::sqrt(2 * static_cast<double>(invMassSqrDiv2) /
0150 (dEta < L1GTSingleInOutLUT::DETA_LUT_SPLIT ? coshEtaLUT_.output_scale()
0151 : coshEtaLUT2_.output_scale()));
0152
0153 double error = std::abs(precInvMass - lutInvMass);
0154 massErrors.emplace_back(InvariantMassError{error, error / precInvMass, precInvMass});
0155 }
0156
0157
0158 return dEta < L1GTSingleInOutLUT::DETA_LUT_SPLIT ? invMassSqrDiv2 : invMassSqrDiv2 << scaleNormalShift_;
0159 }
0160
0161 int64_t calc2BodyTransMass(const P2GTCandidate& obj1, const P2GTCandidate& obj2) const {
0162
0163 uint32_t dPhi = HW_PI - abs(abs(obj1.hwPhi().to_int() - obj2.hwPhi().to_int()) - HW_PI);
0164
0165
0166 int32_t lutCosDPhi = dPhi >= HW_PI ? -cosPhiLUT_[dPhi] : cosPhiLUT_[dPhi];
0167
0168 return obj1.hwPT().to_int64() * obj2.hwPT().to_int64() *
0169 (static_cast<int64_t>(std::round(cosPhiLUT_.output_scale())) - lutCosDPhi);
0170 }
0171
0172 const L1GTScales& scales_;
0173
0174 const L1GTSingleInOutLUT coshEtaLUT_;
0175 const L1GTSingleInOutLUT coshEtaLUT2_;
0176 const L1GTSingleInOutLUT cosPhiLUT_;
0177
0178 const std::optional<int64_t> minInvMassSqrDiv2_;
0179 const std::optional<int64_t> maxInvMassSqrDiv2_;
0180 const std::optional<int64_t> minTransMassSqrDiv2_;
0181 const std::optional<int64_t> maxTransMassSqrDiv2_;
0182
0183 const int scaleNormalShift_;
0184 const int invMassResolutionReduceShift_;
0185 const int transMassResolutionReduceShift_;
0186
0187 const bool inv_mass_checks_;
0188 };
0189
0190 }
0191
0192 #endif