File indexing completed on 2025-06-14 00:06:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include "CondFormats/BeamSpotObjects/interface/BeamSpotObjects.h"
0014 #include "CondFormats/DataRecord/interface/BeamSpotObjectsRcd.h"
0015 #include "CondFormats/BeamSpotObjects/interface/BeamSpotOnlineObjects.h"
0016 #include "CondFormats/DataRecord/interface/BeamSpotOnlineHLTObjectsRcd.h"
0017 #include "CondFormats/DataRecord/interface/BeamSpotOnlineLegacyObjectsRcd.h"
0018 #include "DataFormats/BeamSpot/interface/BeamSpot.h"
0019 #include "DataFormats/Common/interface/Handle.h"
0020 #include "DataFormats/GeometryCommonDetAlgo/interface/GlobalError.h"
0021 #include "DataFormats/L1GlobalTrigger/interface/L1GlobalTriggerEvmReadoutRecord.h"
0022 #include "DataFormats/Scalers/interface/BeamSpotOnline.h"
0023 #include "FWCore/Framework/interface/ESHandle.h"
0024 #include "FWCore/Framework/interface/Event.h"
0025 #include "FWCore/Framework/interface/EventSetup.h"
0026 #include "FWCore/Framework/interface/stream/EDProducer.h"
0027 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0028 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0029 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0030 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0031 #include "FWCore/Utilities/interface/ESGetToken.h"
0032 #include "FWCore/Utilities/interface/TypeDemangler.h"
0033
0034 #include <optional>
0035
0036 class BeamSpotOnlineProducer : public edm::stream::EDProducer<> {
0037 public:
0038
0039 explicit BeamSpotOnlineProducer(const edm::ParameterSet& iConf);
0040
0041 void beginLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) override;
0042
0043
0044 void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override;
0045
0046
0047 static void fillDescriptions(edm::ConfigurationDescriptions& iDesc);
0048
0049 private:
0050
0051 bool shouldShout(const edm::Event& iEvent) const;
0052 std::optional<reco::BeamSpot> processRecords(const edm::LuminosityBlock& iLumi,
0053 const edm::EventSetup& iSetup,
0054 bool shoutMODE) const;
0055 reco::BeamSpot createBeamSpotFromRecord(const BeamSpotObjects& spotDB) const;
0056 template <typename RecordType, typename TokenType>
0057 const BeamSpotOnlineObjects* getBeamSpotFromRecord(const TokenType& token,
0058 const edm::LuminosityBlock& lumi,
0059 const edm::EventSetup& setup) const;
0060 const BeamSpotOnlineObjects* chooseBS(const BeamSpotOnlineObjects* bs1, const BeamSpotOnlineObjects* bs2) const;
0061 std::optional<reco::BeamSpot> processScalers(const edm::Event& iEvent, bool shoutMODE) const;
0062 reco::BeamSpot createBeamSpotFromScaler(const BeamSpotOnline& spotOnline) const;
0063 bool isInvalidScaler(const BeamSpotOnline& spotOnline, bool shoutMODE) const;
0064 reco::BeamSpot createBeamSpotFromDB(const edm::EventSetup& iSetup, bool shoutMODE) const;
0065
0066
0067 const bool changeFrame_;
0068 const double theMaxZ, theSetSigmaZ;
0069 double theMaxR2;
0070 const int timeThreshold_;
0071 const double sigmaZThreshold_, sigmaXYThreshold_;
0072 const bool useBSOnlineRecords_;
0073 const edm::EDGetTokenT<BeamSpotOnlineCollection> scalerToken_;
0074 const edm::EDGetTokenT<L1GlobalTriggerEvmReadoutRecord> l1GtEvmReadoutRecordToken_;
0075 const edm::ESGetToken<BeamSpotObjects, BeamSpotObjectsRcd> beamToken_;
0076 const edm::ESGetToken<BeamSpotOnlineObjects, BeamSpotOnlineLegacyObjectsRcd> beamTokenLegacy_;
0077 const edm::ESGetToken<BeamSpotOnlineObjects, BeamSpotOnlineHLTObjectsRcd> beamTokenHLT_;
0078
0079 std::optional<reco::BeamSpot> lumiResult_;
0080 const unsigned int theBeamShoutMode;
0081 };
0082
0083 using namespace edm;
0084
0085 BeamSpotOnlineProducer::BeamSpotOnlineProducer(const ParameterSet& iconf)
0086 : changeFrame_(iconf.getParameter<bool>("changeToCMSCoordinates")),
0087 theMaxZ(iconf.getParameter<double>("maxZ")),
0088 theSetSigmaZ(iconf.getParameter<double>("setSigmaZ")),
0089 timeThreshold_(iconf.getParameter<int>("timeThreshold")),
0090 sigmaZThreshold_(iconf.getParameter<double>("sigmaZThreshold")),
0091 sigmaXYThreshold_(iconf.getParameter<double>("sigmaXYThreshold") * 1E-4),
0092 useBSOnlineRecords_(iconf.getParameter<bool>("useBSOnlineRecords")),
0093 scalerToken_(useBSOnlineRecords_ ? edm::EDGetTokenT<BeamSpotOnlineCollection>()
0094 : consumes<BeamSpotOnlineCollection>(iconf.getParameter<InputTag>("src"))),
0095 l1GtEvmReadoutRecordToken_(consumes<L1GlobalTriggerEvmReadoutRecord>(iconf.getParameter<InputTag>("gtEvmLabel"))),
0096 beamToken_(esConsumes<BeamSpotObjects, BeamSpotObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0097 beamTokenLegacy_(
0098 esConsumes<BeamSpotOnlineObjects, BeamSpotOnlineLegacyObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0099 beamTokenHLT_(
0100 esConsumes<BeamSpotOnlineObjects, BeamSpotOnlineHLTObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0101 theBeamShoutMode(iconf.getUntrackedParameter<unsigned int>("beamMode", 11)) {
0102 theMaxR2 = iconf.getParameter<double>("maxRadius");
0103 theMaxR2 *= theMaxR2;
0104
0105 produces<reco::BeamSpot>();
0106 }
0107
0108 void BeamSpotOnlineProducer::fillDescriptions(edm::ConfigurationDescriptions& iDesc) {
0109 edm::ParameterSetDescription ps;
0110 ps.add<bool>("changeToCMSCoordinates", false);
0111 ps.add<double>("maxZ", 40.);
0112 ps.add<double>("setSigmaZ", -1.);
0113 ps.addUntracked<unsigned int>("beamMode", 11);
0114 ps.addOptional<InputTag>("src", InputTag("hltScalersRawToDigi"))->setComment("SCAL decommissioned after Run 2");
0115 ps.add<InputTag>("gtEvmLabel", InputTag(""));
0116 ps.add<double>("maxRadius", 2.0);
0117 ps.add<bool>("useBSOnlineRecords", false);
0118 ps.add<int>("timeThreshold", 48)->setComment("hours");
0119 ps.add<double>("sigmaZThreshold", 2.)->setComment("cm");
0120 ps.add<double>("sigmaXYThreshold", 4.)->setComment("um");
0121 iDesc.addWithDefaultLabel(ps);
0122 }
0123
0124 void BeamSpotOnlineProducer::beginLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) {
0125
0126 if (useBSOnlineRecords_) {
0127 lumiResult_ = processRecords(lumi, setup, true);
0128 if (lumiResult_)
0129 return;
0130 }
0131 lumiResult_ = createBeamSpotFromDB(setup, true);
0132 }
0133
0134 void BeamSpotOnlineProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0135
0136 bool shoutMODE = shouldShout(iEvent);
0137
0138 std::unique_ptr<reco::BeamSpot> toput;
0139 if (not useBSOnlineRecords_) {
0140
0141 auto bs = processScalers(iEvent, shoutMODE);
0142 if (bs) {
0143 toput = std::make_unique<reco::BeamSpot>(std::move(*bs));
0144 }
0145 }
0146 if (not toput) {
0147 assert(lumiResult_);
0148 toput = std::make_unique<reco::BeamSpot>(*lumiResult_);
0149 }
0150 iEvent.put(std::move(toput));
0151 }
0152
0153 bool BeamSpotOnlineProducer::shouldShout(const edm::Event& iEvent) const {
0154 edm::Handle<L1GlobalTriggerEvmReadoutRecord> gtEvmReadoutRecord;
0155 if (iEvent.getByToken(l1GtEvmReadoutRecordToken_, gtEvmReadoutRecord)) {
0156 return gtEvmReadoutRecord->gtfeWord().beamMode() == theBeamShoutMode;
0157 }
0158 return true;
0159 }
0160
0161 std::optional<reco::BeamSpot> BeamSpotOnlineProducer::processRecords(const edm::LuminosityBlock& iLumi,
0162 const edm::EventSetup& iSetup,
0163 bool shoutMODE) const {
0164 auto const* spotDBLegacy = getBeamSpotFromRecord<BeamSpotOnlineLegacyObjectsRcd>(beamTokenLegacy_, iLumi, iSetup);
0165 auto const* spotDBHLT = getBeamSpotFromRecord<BeamSpotOnlineHLTObjectsRcd>(beamTokenHLT_, iLumi, iSetup);
0166 auto const* spotDB = chooseBS(spotDBLegacy, spotDBHLT);
0167
0168 if (not spotDB) {
0169 if (shoutMODE) {
0170 edm::LogWarning("BeamSpotOnlineProducer") << "None of the online records holds a valid beam spot. The Online "
0171 "Beam Spot producer falls back to the PCL value.";
0172 }
0173 return {};
0174 }
0175
0176
0177 return createBeamSpotFromRecord(*spotDB);
0178 }
0179
0180 template <typename RecordType, typename TokenType>
0181 const BeamSpotOnlineObjects* BeamSpotOnlineProducer::getBeamSpotFromRecord(const TokenType& token,
0182 const LuminosityBlock& lumi,
0183 const EventSetup& setup) const {
0184 auto const bsRecord = setup.tryToGet<RecordType>();
0185 if (!bsRecord) {
0186 const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0187 edm::LogWarning("BeamSpotOnlineProducer") << "No " << recordTypeName << " found in the EventSetup";
0188 return nullptr;
0189 }
0190 const auto& bsHandle = setup.getHandle(token);
0191 if (bsHandle.isValid()) {
0192 const auto& bs = *bsHandle;
0193 if (bs.sigmaZ() < sigmaZThreshold_ || bs.beamWidthX() < sigmaXYThreshold_ || bs.beamWidthY() < sigmaXYThreshold_ ||
0194 bs.beamType() != reco::BeamSpot::Tracker) {
0195 const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0196 edm::LogWarning("BeamSpotOnlineProducer")
0197 << "The beam spot record does not pass the fit sanity checks (record: " << recordTypeName << ")" << std::endl
0198 << "sigmaZ: " << bs.sigmaZ() << std::endl
0199 << "sigmaX: " << bs.beamWidthX() << std::endl
0200 << "sigmaY: " << bs.beamWidthY() << std::endl
0201 << "type: " << bs.beamType();
0202 return nullptr;
0203 }
0204 auto lumitime = std::chrono::seconds(lumi.beginTime().unixTime());
0205 auto bstime = std::chrono::microseconds(bs.creationTime());
0206 auto threshold = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::hours(timeThreshold_)).count();
0207 if ((lumitime - bstime).count() > threshold) {
0208 const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0209 edm::LogWarning("BeamSpotOnlineProducer")
0210 << "The beam spot record is too old. (record: " << recordTypeName << ")" << std::endl
0211 << " record creation time: " << std::chrono::duration_cast<std::chrono::seconds>(bstime).count()
0212 << " lumi block time: " << std::chrono::duration_cast<std::chrono::seconds>(lumitime).count();
0213 return nullptr;
0214 }
0215 return &bs;
0216 } else {
0217 const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0218 edm::LogWarning("BeamSpotOnlineProducer") << "Invalid online beam spot handle for the record: " << recordTypeName;
0219 return nullptr;
0220 }
0221 }
0222
0223 const BeamSpotOnlineObjects* BeamSpotOnlineProducer::chooseBS(const BeamSpotOnlineObjects* bs1,
0224 const BeamSpotOnlineObjects* bs2) const {
0225 if (bs1 and bs2 and bs1->beamType() == reco::BeamSpot::Tracker && bs2->beamType() == reco::BeamSpot::Tracker) {
0226 return bs1->sigmaZ() > bs2->sigmaZ() ? bs1 : bs2;
0227 } else if (bs1 and bs1->beamType() == reco::BeamSpot::Tracker) {
0228 return bs1;
0229 } else if (bs2 and bs2->beamType() == reco::BeamSpot::Tracker) {
0230 return bs2;
0231 } else {
0232 return nullptr;
0233 }
0234 }
0235
0236 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromRecord(const BeamSpotObjects& spotDB) const {
0237 double f = changeFrame_ ? -1.0 : 1.0;
0238 reco::BeamSpot::Point apoint(f * spotDB.x(), f * spotDB.y(), f * spotDB.z());
0239
0240 reco::BeamSpot::CovarianceMatrix matrix;
0241 for (int i = 0; i < reco::BeamSpot::dimension; ++i) {
0242 for (int j = 0; j < reco::BeamSpot::dimension; ++j) {
0243 matrix(i, j) = spotDB.covariance(i, j);
0244 }
0245 }
0246
0247 double sigmaZ = (theSetSigmaZ > 0) ? theSetSigmaZ : spotDB.sigmaZ();
0248 reco::BeamSpot result(apoint, sigmaZ, spotDB.dxdz(), spotDB.dydz(), spotDB.beamWidthX(), matrix);
0249 result.setBeamWidthY(spotDB.beamWidthY());
0250 result.setEmittanceX(spotDB.emittanceX());
0251 result.setEmittanceY(spotDB.emittanceY());
0252 result.setbetaStar(spotDB.betaStar());
0253 result.setType(reco::BeamSpot::Tracker);
0254 return result;
0255 }
0256
0257 std::optional<reco::BeamSpot> BeamSpotOnlineProducer::processScalers(const edm::Event& iEvent, bool shoutMODE) const {
0258 edm::Handle<BeamSpotOnlineCollection> handleScaler;
0259 iEvent.getByToken(scalerToken_, handleScaler);
0260
0261 if (handleScaler->empty()) {
0262 if (shoutMODE && iEvent.isRealData()) {
0263 edm::LogWarning("BeamSpotOnlineProducer") << " Scalers handle is empty. The Online "
0264 "Beam Spot producer falls back to the PCL value.";
0265 }
0266 return {};
0267 }
0268
0269
0270 BeamSpotOnline spotOnline = *(handleScaler->begin());
0271
0272 if (isInvalidScaler(spotOnline, shoutMODE)) {
0273 return {};
0274 }
0275 return createBeamSpotFromScaler(spotOnline);
0276 }
0277
0278 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromScaler(const BeamSpotOnline& spotOnline) const {
0279 double f = changeFrame_ ? -1.0 : 1.0;
0280 reco::BeamSpot::Point apoint(f * spotOnline.x(), spotOnline.y(), f * spotOnline.z());
0281
0282 reco::BeamSpot::CovarianceMatrix matrix;
0283 matrix(0, 0) = spotOnline.err_x() * spotOnline.err_x();
0284 matrix(1, 1) = spotOnline.err_y() * spotOnline.err_y();
0285 matrix(2, 2) = spotOnline.err_z() * spotOnline.err_z();
0286 matrix(3, 3) = spotOnline.err_sigma_z() * spotOnline.err_sigma_z();
0287
0288 double sigmaZ = (theSetSigmaZ > 0) ? theSetSigmaZ : spotOnline.sigma_z();
0289 reco::BeamSpot result(apoint, sigmaZ, spotOnline.dxdz(), f * spotOnline.dydz(), spotOnline.width_x(), matrix);
0290 result.setBeamWidthY(spotOnline.width_y());
0291 result.setEmittanceX(0.0);
0292 result.setEmittanceY(0.0);
0293 result.setbetaStar(0.0);
0294 result.setType(reco::BeamSpot::LHC);
0295 return result;
0296 }
0297
0298 bool BeamSpotOnlineProducer::isInvalidScaler(const BeamSpotOnline& spotOnline, bool shoutMODE) const {
0299 if (spotOnline.x() == 0 && spotOnline.y() == 0 && spotOnline.z() == 0 && spotOnline.width_x() == 0 &&
0300 spotOnline.width_y() == 0) {
0301 if (shoutMODE) {
0302 edm::LogWarning("BeamSpotOnlineProducer")
0303 << "Online Beam Spot producer falls back to DB due to zero scaler values.";
0304 }
0305 return true;
0306 }
0307
0308 double r2 = spotOnline.x() * spotOnline.x() + spotOnline.y() * spotOnline.y();
0309 if (std::abs(spotOnline.z()) >= theMaxZ || r2 >= theMaxR2) {
0310 if (shoutMODE) {
0311 edm::LogError("BeamSpotOnlineProducer")
0312 << "Online Beam Spot producer falls back to DB due to out-of-range scaler values: " << spotOnline.x() << ", "
0313 << spotOnline.y() << ", " << spotOnline.z();
0314 }
0315 return true;
0316 }
0317 return false;
0318 }
0319
0320 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromDB(const edm::EventSetup& iSetup, bool shoutMODE) const {
0321 edm::ESHandle<BeamSpotObjects> beamhandle = iSetup.getHandle(beamToken_);
0322 const BeamSpotObjects* spotDB = beamhandle.product();
0323
0324 reco::BeamSpot::Point apoint(spotDB->x(), spotDB->y(), spotDB->z());
0325
0326 reco::BeamSpot::CovarianceMatrix matrix;
0327 for (int i = 0; i < reco::BeamSpot::dimension; ++i) {
0328 for (int j = 0; j < reco::BeamSpot::dimension; ++j) {
0329 matrix(i, j) = spotDB->covariance(i, j);
0330 }
0331 }
0332
0333 reco::BeamSpot result(apoint, spotDB->sigmaZ(), spotDB->dxdz(), spotDB->dydz(), spotDB->beamWidthX(), matrix);
0334 result.setBeamWidthY(spotDB->beamWidthY());
0335 result.setEmittanceX(spotDB->emittanceX());
0336 result.setEmittanceY(spotDB->emittanceY());
0337 result.setbetaStar(spotDB->betaStar());
0338 result.setType(reco::BeamSpot::Tracker);
0339
0340 GlobalError bse(result.rotatedCovariance3D());
0341 if ((bse.cxx() <= 0.0) || (bse.cyy() <= 0.0) || (bse.czz() <= 0.0)) {
0342 edm::LogError("UnusableBeamSpot") << "Beamspot from DB fallback has invalid errors: " << result.covariance();
0343 }
0344 return result;
0345 }
0346
0347 #include "FWCore/Framework/interface/MakerMacros.h"
0348 DEFINE_FWK_MODULE(BeamSpotOnlineProducer);