Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-08 03:06:52

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