File indexing completed on 2024-04-06 11:56:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "Alignment/CommonAlignmentAlgorithm/interface/IntegratedCalibrationBase.h"
0015 #include "Alignment/CommonAlignmentAlgorithm/interface/TkModuleGroupSelector.h"
0016
0017 #include "SiStripReadoutModeEnums.h"
0018 #include "TreeStruct.h"
0019
0020 #include "CondCore/DBOutputService/interface/PoolDBOutputService.h"
0021 #include "CondFormats/DataRecord/interface/SiStripCondDataRecords.h"
0022 #include "CondFormats/SiStripObjects/interface/SiStripLatency.h"
0023 #include "CondFormats/SiStripObjects/interface/SiStripLorentzAngle.h"
0024
0025 #include "CondFormats/SiStripObjects/interface/SiStripBackPlaneCorrection.h"
0026
0027 #include "DataFormats/DetId/interface/DetId.h"
0028 #include "DataFormats/SiStripDetId/interface/SiStripDetId.h"
0029
0030 #include "FWCore/Framework/interface/ConsumesCollector.h"
0031 #include "FWCore/Framework/interface/ESWatcher.h"
0032 #include "FWCore/Framework/interface/Run.h"
0033 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0034 #include "FWCore/ServiceRegistry/interface/Service.h"
0035 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0036
0037 #include "Geometry/CommonDetUnit/interface/GeomDet.h"
0038 #include "MagneticField/Engine/interface/MagneticField.h"
0039 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
0040 #include "TrackingTools/TransientTrackingRecHit/interface/TransientTrackingRecHit.h"
0041
0042 #include "TTree.h"
0043 #include "TFile.h"
0044 #include "TString.h"
0045
0046 #include <vector>
0047 #include <map>
0048 #include <sstream>
0049 #include <cstdio>
0050 #include <memory>
0051 #include <functional>
0052
0053 class SiStripLorentzAngleCalibration : public IntegratedCalibrationBase {
0054 public:
0055
0056 explicit SiStripLorentzAngleCalibration(const edm::ParameterSet &cfg, edm::ConsumesCollector &iC);
0057
0058
0059 ~SiStripLorentzAngleCalibration() override = default;
0060
0061
0062 unsigned int numParameters() const override;
0063
0064
0065
0066 unsigned int derivatives(std::vector<ValuesIndexPair> &outDerivInds,
0067 const TransientTrackingRecHit &hit,
0068 const TrajectoryStateOnSurface &tsos,
0069 const edm::EventSetup &setup,
0070 const EventInfo &eventInfo) const override;
0071
0072
0073
0074 bool setParameter(unsigned int index, double value) override;
0075
0076
0077
0078 bool setParameterError(unsigned int index, double error) override;
0079
0080
0081
0082 double getParameter(unsigned int index) const override;
0083
0084
0085
0086 double getParameterError(unsigned int index) const override;
0087
0088
0089 void beginOfJob(AlignableTracker *tracker, AlignableMuon *muon, AlignableExtras *extras) override;
0090
0091
0092 void beginRun(const edm::Run &, const edm::EventSetup &) override;
0093
0094
0095
0096 void endOfJob() override;
0097
0098 private:
0099
0100
0101
0102 const SiStripLorentzAngle *getLorentzAnglesInput(const align::RunNumber & = 0);
0103
0104 double effectiveThickness(const GeomDet *det, int16_t mode, const edm::EventSetup &setup) const;
0105
0106
0107
0108 double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const;
0109
0110 void writeTree(const SiStripLorentzAngle *lorentzAngle,
0111 const std::map<unsigned int, TreeStruct> &treeInfo,
0112 const char *treeName) const;
0113 SiStripLorentzAngle createFromTree(const char *fileName, const char *treeName) const;
0114
0115 const std::string readoutModeName_;
0116 int16_t readoutMode_;
0117 const bool saveToDB_;
0118 const std::string recordNameDBwrite_;
0119 const std::string outFileName_;
0120 const std::vector<std::string> mergeFileNames_;
0121
0122 edm::ESWatcher<SiStripLorentzAngleRcd> watchLorentzAngleRcd_;
0123
0124 std::map<align::RunNumber, SiStripLorentzAngle> cachedLorentzAngleInputs_;
0125 SiStripLorentzAngle *siStripLorentzAngleInput_{nullptr};
0126 align::RunNumber currentIOV_{0};
0127
0128 std::vector<double> parameters_;
0129 std::vector<double> paramUncertainties_;
0130
0131 std::unique_ptr<TkModuleGroupSelector> moduleGroupSelector_;
0132 const edm::ParameterSet moduleGroupSelCfg_;
0133
0134 const edm::ESGetToken<SiStripLatency, SiStripLatencyRcd> latencyToken_;
0135 const edm::ESGetToken<SiStripLorentzAngle, SiStripLorentzAngleRcd> lorentzAngleToken_;
0136 const edm::ESGetToken<MagneticField, IdealMagneticFieldRecord> magFieldToken_;
0137 const edm::ESGetToken<SiStripBackPlaneCorrection, SiStripBackPlaneCorrectionRcd> backPlaneCorrToken_;
0138 };
0139
0140
0141
0142
0143
0144 SiStripLorentzAngleCalibration::SiStripLorentzAngleCalibration(const edm::ParameterSet &cfg, edm::ConsumesCollector &iC)
0145 : IntegratedCalibrationBase(cfg),
0146 readoutModeName_(cfg.getParameter<std::string>("readoutMode")),
0147 saveToDB_(cfg.getParameter<bool>("saveToDB")),
0148 recordNameDBwrite_(cfg.getParameter<std::string>("recordNameDBwrite")),
0149 outFileName_(cfg.getParameter<std::string>("treeFile")),
0150 mergeFileNames_(cfg.getParameter<std::vector<std::string> >("mergeTreeFiles")),
0151 moduleGroupSelCfg_(cfg.getParameter<edm::ParameterSet>("LorentzAngleModuleGroups")),
0152 latencyToken_(iC.esConsumes()),
0153 lorentzAngleToken_(iC.esConsumes<edm::Transition::BeginRun>(edm::ESInputTag("", readoutModeName_))),
0154 magFieldToken_(iC.esConsumes()),
0155 backPlaneCorrToken_(iC.esConsumes(edm::ESInputTag("", readoutModeName_))) {
0156
0157
0158
0159 if (readoutModeName_ == "peak") {
0160 readoutMode_ = kPeakMode;
0161 } else if (readoutModeName_ == "deconvolution") {
0162 readoutMode_ = kDeconvolutionMode;
0163 } else {
0164 throw cms::Exception("BadConfig") << "SiStripLorentzAngleCalibration:\n"
0165 << "Unknown mode '" << readoutModeName_
0166 << "', should be 'peak' or 'deconvolution' .\n";
0167 }
0168 }
0169
0170
0171 unsigned int SiStripLorentzAngleCalibration::numParameters() const { return parameters_.size(); }
0172
0173
0174 void SiStripLorentzAngleCalibration::beginRun(const edm::Run &run, const edm::EventSetup &setup) {
0175
0176 if (!(watchLorentzAngleRcd_.check(setup)))
0177 return;
0178
0179 const auto runNumber = run.run();
0180 auto firstRun = cond::timeTypeSpecs[cond::runnumber].beginValue;
0181
0182
0183
0184 for (unsigned int i = moduleGroupSelector_->numIovs(); i-- > 0;) {
0185 const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(i);
0186 if (runNumber >= firstRunOfIOV) {
0187 firstRun = firstRunOfIOV;
0188 break;
0189 }
0190 }
0191
0192 const SiStripLorentzAngle *lorentzAngleHandle = &setup.getData(lorentzAngleToken_);
0193 const auto &lorentzAngleRcd = setup.get<SiStripLorentzAngleRcd>();
0194 if (cachedLorentzAngleInputs_.find(firstRun) == cachedLorentzAngleInputs_.end()) {
0195 cachedLorentzAngleInputs_.emplace(firstRun, SiStripLorentzAngle(*lorentzAngleHandle));
0196 } else {
0197 if (lorentzAngleRcd.validityInterval().first().eventID().run() > firstRun &&
0198 lorentzAngleHandle->getLorentzAngles()
0199 != cachedLorentzAngleInputs_[firstRun].getLorentzAngles()) {
0200
0201
0202 throw cms::Exception("BadInput") << "Trying to cache SiStripLorentzAngle payload for a run (" << runNumber
0203 << ") in an IOV (" << firstRun << ") that was already cached.\n"
0204 << "The following record in your input database tag has an IOV "
0205 << "boundary that does not match your IOV definition:\n"
0206 << " - SiStripLorentzAngleRcd '" << lorentzAngleRcd.key().name() << "' (since "
0207 << lorentzAngleRcd.validityInterval().first().eventID().run() << ")\n";
0208 }
0209 }
0210
0211 siStripLorentzAngleInput_ = &(cachedLorentzAngleInputs_[firstRun]);
0212 currentIOV_ = firstRun;
0213 }
0214
0215
0216 unsigned int SiStripLorentzAngleCalibration::derivatives(std::vector<ValuesIndexPair> &outDerivInds,
0217 const TransientTrackingRecHit &hit,
0218 const TrajectoryStateOnSurface &tsos,
0219 const edm::EventSetup &setup,
0220 const EventInfo &eventInfo) const {
0221 outDerivInds.clear();
0222
0223 const SiStripLatency *latency = &setup.getData(latencyToken_);
0224 const int16_t mode = latency->singleReadOutMode();
0225 if (mode == readoutMode_) {
0226 if (hit.det()) {
0227
0228 const int index =
0229 moduleGroupSelector_->getParameterIndexFromDetId(hit.det()->geographicalId(), eventInfo.eventId().run());
0230 if (index >= 0) {
0231 const MagneticField *magneticField = &setup.getData(magFieldToken_);
0232 const GlobalVector bField(magneticField->inTesla(hit.det()->surface().position()));
0233 const LocalVector bFieldLocal(hit.det()->surface().toLocal(bField));
0234 const double dZ = this->effectiveThickness(hit.det(), mode, setup);
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 const double xDerivative = bFieldLocal.y() * dZ * -0.5;
0246 const double yDerivative = bFieldLocal.x() * dZ * 0.5;
0247 if (xDerivative || yDerivative) {
0248 const Values derivs{xDerivative, yDerivative};
0249 outDerivInds.push_back(ValuesIndexPair(derivs, index));
0250 }
0251 }
0252 } else {
0253 edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::derivatives1"
0254 << "Hit without GeomDet, skip!";
0255 }
0256 } else if (mode != kDeconvolutionMode && mode != kPeakMode) {
0257
0258 edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::derivatives2"
0259 << "Readout mode is " << mode << ", but looking for " << readoutMode_ << " ("
0260 << readoutModeName_ << ").";
0261 }
0262
0263 return outDerivInds.size();
0264 }
0265
0266
0267 bool SiStripLorentzAngleCalibration::setParameter(unsigned int index, double value) {
0268 if (index >= parameters_.size()) {
0269 return false;
0270 } else {
0271 parameters_[index] = value;
0272 return true;
0273 }
0274 }
0275
0276
0277 bool SiStripLorentzAngleCalibration::setParameterError(unsigned int index, double error) {
0278 if (index >= paramUncertainties_.size()) {
0279 return false;
0280 } else {
0281 paramUncertainties_[index] = error;
0282 return true;
0283 }
0284 }
0285
0286
0287 double SiStripLorentzAngleCalibration::getParameter(unsigned int index) const {
0288 return (index >= parameters_.size() ? 0. : parameters_[index]);
0289 }
0290
0291
0292 double SiStripLorentzAngleCalibration::getParameterError(unsigned int index) const {
0293 return (index >= paramUncertainties_.size() ? 0. : paramUncertainties_[index]);
0294 }
0295
0296
0297 void SiStripLorentzAngleCalibration::beginOfJob(AlignableTracker *aliTracker,
0298 AlignableMuon * ,
0299 AlignableExtras * ) {
0300
0301 const std::vector<int> sdets = {SiStripDetId::TIB, SiStripDetId::TOB, SiStripDetId::TID, SiStripDetId::TEC};
0302 moduleGroupSelector_ = std::make_unique<TkModuleGroupSelector>(aliTracker, moduleGroupSelCfg_, sdets);
0303
0304 parameters_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
0305 paramUncertainties_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
0306
0307 edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration"
0308 << "Created with name " << this->name() << " for readout mode '" << readoutModeName_
0309 << "',\n"
0310 << this->numParameters() << " parameters to be determined."
0311 << "\nsaveToDB = " << saveToDB_ << "\n outFileName = " << outFileName_
0312 << "\n N(merge files) = " << mergeFileNames_.size()
0313 << "\n number of IOVs = " << moduleGroupSelector_->numIovs();
0314
0315 if (!mergeFileNames_.empty()) {
0316 edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration"
0317 << "First file to merge: " << mergeFileNames_[0];
0318 }
0319 }
0320
0321
0322 void SiStripLorentzAngleCalibration::endOfJob() {
0323
0324 std::ostringstream out;
0325 out << "Parameter results for readout mode '" << readoutModeName_ << "'\n";
0326 for (unsigned int iPar = 0; iPar < parameters_.size(); ++iPar) {
0327 out << iPar << ": " << parameters_[iPar] << " +- " << paramUncertainties_[iPar] << "\n";
0328 }
0329 edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration::endOfJob" << out.str();
0330
0331 std::map<unsigned int, TreeStruct> treeInfo;
0332
0333
0334 const std::string treeName{this->name() + '_' + readoutModeName_ + '_'};
0335 std::vector<const SiStripLorentzAngle *> inputs{};
0336 inputs.reserve(moduleGroupSelector_->numIovs());
0337 for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
0338 const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(iIOV);
0339 inputs.push_back(this->getLorentzAnglesInput(firstRunOfIOV));
0340 this->writeTree(inputs.back(),
0341 treeInfo,
0342 (treeName + "input_" + std::to_string(firstRunOfIOV)).c_str());
0343
0344 if (inputs.back()->getLorentzAngles().empty()) {
0345 edm::LogError("Alignment") << "@SUB=SiStripLorentzAngleCalibration::endOfJob"
0346 << "Input Lorentz angle map is empty ('" << readoutModeName_
0347 << "' mode), skip writing output!";
0348 return;
0349 }
0350 }
0351
0352 const unsigned int nonZeroParamsOrErrors =
0353 count_if(parameters_.begin(), parameters_.end(), [](auto c) { return c != 0.; }) +
0354 count_if(paramUncertainties_.begin(), paramUncertainties_.end(), [](auto c) { return c != 0.; });
0355
0356 for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
0357 auto firstRunOfIOV = static_cast<cond::Time_t>(moduleGroupSelector_->firstRunOfIOV(iIOV));
0358 SiStripLorentzAngle output{};
0359
0360 for (const auto &iterIdValue : inputs[iIOV]->getLorentzAngles()) {
0361
0362 const auto detId = iterIdValue.first;
0363
0364
0365
0366
0367
0368
0369
0370
0371 const double param = this->getParameterForDetId(detId, firstRunOfIOV);
0372
0373 auto value = iterIdValue.second + static_cast<float>(param);
0374 output.putLorentzAngle(detId, value);
0375 const int paramIndex = moduleGroupSelector_->getParameterIndexFromDetId(detId, firstRunOfIOV);
0376 treeInfo[detId] = TreeStruct(param, this->getParameterError(paramIndex), paramIndex);
0377 }
0378
0379 if (saveToDB_ || nonZeroParamsOrErrors != 0) {
0380 this->writeTree(&output, treeInfo, (treeName + Form("result_%lld", firstRunOfIOV)).c_str());
0381 }
0382
0383 if (saveToDB_) {
0384 edm::Service<cond::service::PoolDBOutputService> dbService;
0385 if (dbService.isAvailable()) {
0386 dbService->writeOneIOV(output, firstRunOfIOV, recordNameDBwrite_);
0387 } else {
0388 edm::LogError("BadConfig") << "@SUB=SiStripLorentzAngleCalibration::endOfJob"
0389 << "No PoolDBOutputService available, but saveToDB true!";
0390 }
0391 }
0392 }
0393 }
0394
0395
0396 double SiStripLorentzAngleCalibration::effectiveThickness(const GeomDet *det,
0397 int16_t mode,
0398 const edm::EventSetup &setup) const {
0399 if (!det)
0400 return 0.;
0401 double dZ = det->surface().bounds().thickness();
0402 const SiStripDetId id(det->geographicalId());
0403 const SiStripBackPlaneCorrection *backPlaneHandle = &setup.getData(backPlaneCorrToken_);
0404
0405
0406 const double bpCor = backPlaneHandle->getBackPlaneCorrection(id);
0407
0408 dZ *= (1. - bpCor);
0409
0410 return dZ;
0411 }
0412
0413
0414 const SiStripLorentzAngle *SiStripLorentzAngleCalibration::getLorentzAnglesInput(const align::RunNumber &run) {
0415 const auto &resolvedRun = run > 0 ? run : currentIOV_;
0416
0417
0418
0419
0420 const std::string treeName{this->name() + "_" + readoutModeName_ + "_input_" + std::to_string(resolvedRun)};
0421 for (const auto &iFile : mergeFileNames_) {
0422 auto la = this->createFromTree(iFile.c_str(), treeName.c_str());
0423
0424
0425 if (!siStripLorentzAngleInput_ || siStripLorentzAngleInput_->getLorentzAngles().empty()) {
0426 cachedLorentzAngleInputs_[resolvedRun] = la;
0427 siStripLorentzAngleInput_ = &(cachedLorentzAngleInputs_[resolvedRun]);
0428 currentIOV_ = resolvedRun;
0429 } else {
0430
0431 if (!la.getLorentzAngles().empty() &&
0432 la.getLorentzAngles() != siStripLorentzAngleInput_->getLorentzAngles()) {
0433
0434 edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
0435 << "Different input values from tree " << treeName << " in file " << iFile << ".";
0436 }
0437 }
0438 }
0439
0440 if (!siStripLorentzAngleInput_) {
0441
0442 siStripLorentzAngleInput_ = &(cachedLorentzAngleInputs_[resolvedRun]);
0443 currentIOV_ = resolvedRun;
0444 edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
0445 << "No input, create an empty one ('" << readoutModeName_ << "' mode)!";
0446 } else if (siStripLorentzAngleInput_->getLorentzAngles().empty()) {
0447 edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
0448 << "Empty result ('" << readoutModeName_ << "' mode)!";
0449 }
0450
0451 return siStripLorentzAngleInput_;
0452 }
0453
0454
0455 double SiStripLorentzAngleCalibration::getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const {
0456 const int index = moduleGroupSelector_->getParameterIndexFromDetId(detId, run);
0457
0458 return (index < 0 ? 0. : parameters_[index]);
0459 }
0460
0461
0462 void SiStripLorentzAngleCalibration::writeTree(const SiStripLorentzAngle *lorentzAngle,
0463 const std::map<unsigned int, TreeStruct> &treeInfo,
0464 const char *treeName) const {
0465 if (!lorentzAngle)
0466 return;
0467
0468 TFile *file = TFile::Open(outFileName_.c_str(), "UPDATE");
0469 if (!file) {
0470 edm::LogError("BadConfig") << "@SUB=SiStripLorentzAngleCalibration::writeTree"
0471 << "Could not open file '" << outFileName_ << "'.";
0472 return;
0473 }
0474
0475 TTree *tree = new TTree(treeName, treeName);
0476 unsigned int id = 0;
0477 float value = 0.;
0478 TreeStruct treeStruct;
0479 tree->Branch("detId", &id, "detId/i");
0480 tree->Branch("value", &value, "value/F");
0481 tree->Branch("treeStruct", &treeStruct, TreeStruct::LeafList());
0482
0483 for (auto iterIdValue = lorentzAngle->getLorentzAngles().begin();
0484 iterIdValue != lorentzAngle->getLorentzAngles().end();
0485 ++iterIdValue) {
0486
0487 id = iterIdValue->first;
0488 value = iterIdValue->second;
0489
0490 auto treeStructIter = treeInfo.find(id);
0491 if (treeStructIter != treeInfo.end()) {
0492 treeStruct = treeStructIter->second;
0493 } else {
0494 const cond::Time_t run1of1stIov = moduleGroupSelector_->firstRunOfIOV(0);
0495 const int ind = moduleGroupSelector_->getParameterIndexFromDetId(id, run1of1stIov);
0496 treeStruct = TreeStruct(ind);
0497 }
0498 tree->Fill();
0499 }
0500 tree->Write();
0501 delete file;
0502 }
0503
0504
0505 SiStripLorentzAngle SiStripLorentzAngleCalibration::createFromTree(const char *fileName, const char *treeName) const {
0506
0507
0508 TFile *file = nullptr;
0509 FILE *testFile = fopen(fileName, "r");
0510 if (testFile) {
0511 fclose(testFile);
0512 file = TFile::Open(fileName, "READ");
0513 }
0514
0515 TTree *tree = nullptr;
0516 if (file)
0517 file->GetObject(treeName, tree);
0518
0519 SiStripLorentzAngle result{};
0520 if (tree) {
0521 unsigned int id = 0;
0522 float value = 0.;
0523 tree->SetBranchAddress("detId", &id);
0524 tree->SetBranchAddress("value", &value);
0525
0526 const Long64_t nEntries = tree->GetEntries();
0527 for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) {
0528 tree->GetEntry(iEntry);
0529 result.putLorentzAngle(id, value);
0530 }
0531 } else {
0532 edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::createFromTree"
0533 << "Could not get TTree '" << treeName << "' from file '" << fileName
0534 << (file ? "'." : "' (file does not exist).");
0535 }
0536
0537 delete file;
0538 return result;
0539 }
0540
0541
0542
0543
0544
0545 #include "Alignment/CommonAlignmentAlgorithm/interface/IntegratedCalibrationPluginFactory.h"
0546
0547 DEFINE_EDM_PLUGIN(IntegratedCalibrationPluginFactory, SiStripLorentzAngleCalibration, "SiStripLorentzAngleCalibration");