CMS 3D CMS Logo

SiStripLorentzAngleCalibration.cc
Go to the documentation of this file.
1 
16 // include 'locally':
18 #include "TreeStruct.h"
19 
24 //#include "CalibTracker/Records/interface/SiStripDependentRecords.h"
26 
29 
36 
41 
42 #include "TTree.h"
43 #include "TFile.h"
44 #include "TString.h"
45 
46 #include <vector>
47 #include <map>
48 #include <sstream>
49 #include <cstdio>
50 #include <memory>
51 #include <functional>
52 
54 {
55 public:
58 
60  ~SiStripLorentzAngleCalibration() override = default;
61 
63  unsigned int numParameters() const override;
64 
67  unsigned int derivatives(std::vector<ValuesIndexPair> &outDerivInds,
69  const TrajectoryStateOnSurface &tsos,
70  const edm::EventSetup &setup,
71  const EventInfo &eventInfo) const override;
72 
75  bool setParameter(unsigned int index, double value) override;
76 
79  bool setParameterError(unsigned int index, double error) override;
80 
83  double getParameter(unsigned int index) const override;
84 
87  double getParameterError(unsigned int index) const override;
88 
89  // /// Call at beginning of job:
92  AlignableExtras *extras) override;
93 
95  void beginRun(const edm::Run&, const edm::EventSetup&) override;
96 
99  void endOfJob() override;
100 
101 private:
107  double effectiveThickness(const GeomDet *det, int16_t mode, const edm::EventSetup &setup) const;
108 
111  double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const;
112 
113  void writeTree(const SiStripLorentzAngle *lorentzAngle,
114  const std::map<unsigned int,TreeStruct> &treeInfo, const char *treeName) const;
115  SiStripLorentzAngle createFromTree(const char *fileName, const char *treeName) const;
116 
118  int16_t readoutMode_;
119  const bool saveToDB_;
122  const std::vector<std::string> mergeFileNames_;
123 
125 
126  std::map<align::RunNumber, SiStripLorentzAngle> cachedLorentzAngleInputs_;
129 
130  std::vector<double> parameters_;
131  std::vector<double> paramUncertainties_;
132 
133  std::unique_ptr<TkModuleGroupSelector> moduleGroupSelector_;
135 };
136 
137 //======================================================================
138 //======================================================================
139 //======================================================================
140 
143  readoutModeName_(cfg.getParameter<std::string>("readoutMode")),
144  saveToDB_(cfg.getParameter<bool>("saveToDB")),
145  recordNameDBwrite_(cfg.getParameter<std::string>("recordNameDBwrite")),
146  outFileName_(cfg.getParameter<std::string>("treeFile")),
147  mergeFileNames_(cfg.getParameter<std::vector<std::string> >("mergeTreeFiles")),
148  moduleGroupSelCfg_(cfg.getParameter<edm::ParameterSet>("LorentzAngleModuleGroups"))
149 {
150 
151  // SiStripLatency::singleReadOutMode() returns
152  // 1: all in peak, 0: all in deco, -1: mixed state
153  // (in principle one could treat even mixed state APV by APV...)
154  if (readoutModeName_ == "peak") {
156  } else if (readoutModeName_ == "deconvolution") {
158  } else {
159  throw cms::Exception("BadConfig")
160  << "SiStripLorentzAngleCalibration:\n" << "Unknown mode '"
161  << readoutModeName_ << "', should be 'peak' or 'deconvolution' .\n";
162  }
163 
164 }
165 
166 //======================================================================
168 {
169  return parameters_.size();
170 }
171 
172 //======================================================================
173 void
175  const edm::EventSetup& setup) {
176 
177  // no action needed if the LA record didn't change
178  if (!(watchLorentzAngleRcd_.check(setup))) return;
179 
180  const auto runNumber = run.run();
182 
183  // avoid infinite loop due to wrap-around of unsigned variable 'i' including
184  // arrow from i to zero and a nice smiley ;)
185  for (unsigned int i = moduleGroupSelector_->numIovs(); i-->0 ;) {
186  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(i);
187  if (runNumber >= firstRunOfIOV) {
188  firstRun = firstRunOfIOV;
189  break;
190  }
191  }
192 
193  edm::ESHandle<SiStripLorentzAngle> lorentzAngleHandle;
194  const auto& lorentzAngleRcd = setup.get<SiStripLorentzAngleRcd>();
195  lorentzAngleRcd.get(readoutModeName_, lorentzAngleHandle);
197  cachedLorentzAngleInputs_.emplace(firstRun, SiStripLorentzAngle(*lorentzAngleHandle));
198  } else {
199  if (lorentzAngleRcd.validityInterval().first().eventID().run() > firstRun &&
200  lorentzAngleHandle->getLorentzAngles() // only bad if non-identical values
201  != cachedLorentzAngleInputs_[firstRun].getLorentzAngles()) { // (comparing maps)
202  // Maps are containers sorted by key, but comparison problems may arise from
203  // 'floating point comparison' problems (FIXME?)
204  throw cms::Exception("BadInput")
205  << "Trying to cache SiStripLorentzAngle payload for a run (" << runNumber
206  << ") in an IOV (" << firstRun << ") that was already cached.\n"
207  << "The following record in your input database tag has an IOV "
208  << "boundary that does not match your IOV definition:\n"
209  << " - SiStripLorentzAngleRcd '" << lorentzAngleRcd.key().name()
210  << "' (since "
211  << lorentzAngleRcd.validityInterval().first().eventID().run() << ")\n";
212  }
213  }
214 
217 }
218 
219 //======================================================================
220 unsigned int
221 SiStripLorentzAngleCalibration::derivatives(std::vector<ValuesIndexPair> &outDerivInds,
223  const TrajectoryStateOnSurface &tsos,
224  const edm::EventSetup &setup,
225  const EventInfo &eventInfo) const
226 {
227  outDerivInds.clear();
228 
230  setup.get<SiStripLatencyRcd>().get(latency);
231  const int16_t mode = latency->singleReadOutMode();
232  if (mode == readoutMode_) {
233  if (hit.det()) { // otherwise 'constraint hit' or whatever
234 
235  const int index = moduleGroupSelector_->getParameterIndexFromDetId(hit.det()->geographicalId(),
236  eventInfo.eventId().run());
237  if (index >= 0) { // otherwise not treated
239  setup.get<IdealMagneticFieldRecord>().get(magneticField);
240  const GlobalVector bField(magneticField->inTesla(hit.det()->surface().position()));
241  const LocalVector bFieldLocal(hit.det()->surface().toLocal(bField));
242  const double dZ = this->effectiveThickness(hit.det(), mode, setup);
243  // shift due to LA: dx = tan(LA) * dz/2 = mobility * B_y * dz/2,
244  // '-' since we have derivative of the residual r = hit - trk and mu is part of trk model
245  // (see GF's presentation in alignment meeting 25.10.2012,
246  // https://indico.cern.ch/conferenceDisplay.py?confId=174266#2012-10-25)
247  // Hmm! StripCPE::fillParams() defines, together with
248  // StripCPE::driftDirection(...):
249  // drift.x = -mobility * by * thickness (full drift from backside)
250  // So '-' already comes from that, not from mobility being part of
251  // track model...
252  // GM: sign convention is the same as for pixel LA, i.e. adopt it here, too
253  const double xDerivative = bFieldLocal.y() * dZ * -0.5; // parameter is mobility!
254  const double yDerivative = bFieldLocal.x() * dZ * 0.5; // parameter is mobility!
255  if (xDerivative || yDerivative) { // If field is zero, this is zero: do not return it
256  const Values derivs{xDerivative, yDerivative};
257  outDerivInds.push_back(ValuesIndexPair(derivs, index));
258  }
259  }
260  } else {
261  edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::derivatives1"
262  << "Hit without GeomDet, skip!";
263  }
264  } else if (mode != kDeconvolutionMode && mode != kPeakMode) {
265  // warn only if unknown/mixed mode
266  edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::derivatives2"
267  << "Readout mode is " << mode << ", but looking for "
268  << readoutMode_ << " (" << readoutModeName_ << ").";
269  }
270 
271  return outDerivInds.size();
272 }
273 
274 //======================================================================
276 {
277  if (index >= parameters_.size()) {
278  return false;
279  } else {
281  return true;
282  }
283 }
284 
285 //======================================================================
287 {
288  if (index >= paramUncertainties_.size()) {
289  return false;
290  } else {
292  return true;
293  }
294 }
295 
296 //======================================================================
298 {
299  return (index >= parameters_.size() ? 0. : parameters_[index]);
300 }
301 
302 //======================================================================
304 {
305  return (index >= paramUncertainties_.size() ? 0. : paramUncertainties_[index]);
306 }
307 
308 //======================================================================
310  AlignableMuon * /*aliMuon*/,
311  AlignableExtras * /*aliExtras*/)
312 {
313  //specify the sub-detectors for which the LA is determined
314  const std::vector<int> sdets = {SiStripDetId::TIB, SiStripDetId::TOB,
317  std::make_unique<TkModuleGroupSelector>(aliTracker, moduleGroupSelCfg_, sdets);
318 
319  parameters_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
320  paramUncertainties_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
321 
322  edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration" << "Created with name "
323  << this->name() << " for readout mode '" << readoutModeName_
324  << "',\n" << this->numParameters() << " parameters to be determined."
325  << "\nsaveToDB = " << saveToDB_
326  << "\n outFileName = " << outFileName_
327  << "\n N(merge files) = " << mergeFileNames_.size()
328  << "\n number of IOVs = " << moduleGroupSelector_->numIovs();
329 
330  if (!mergeFileNames_.empty()) {
331  edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration"
332  << "First file to merge: " << mergeFileNames_[0];
333  }
334 }
335 
336 
337 //======================================================================
339 {
340  // loginfo output
341  std::ostringstream out;
342  out << "Parameter results for readout mode '" << readoutModeName_ << "'\n";
343  for (unsigned int iPar = 0; iPar < parameters_.size(); ++iPar) {
344  out << iPar << ": " << parameters_[iPar] << " +- " << paramUncertainties_[iPar] << "\n";
345  }
346  edm::LogInfo("Alignment") << "@SUB=SiStripLorentzAngleCalibration::endOfJob" << out.str();
347 
348  std::map<unsigned int, TreeStruct> treeInfo; // map of TreeStruct for each detId
349 
350  // now write 'input' tree
351  const std::string treeName{this->name() + '_' + readoutModeName_ + '_'};
352  std::vector<const SiStripLorentzAngle*> inputs{};
353  inputs.reserve(moduleGroupSelector_->numIovs());
354  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
355  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(iIOV);
356  inputs.push_back(this->getLorentzAnglesInput(firstRunOfIOV)); // never NULL
357  this->writeTree(inputs.back(), treeInfo,
358  (treeName + "input_" + std::to_string(firstRunOfIOV)).c_str()); // empty treeInfo for input...
359 
360  if (inputs.back()->getLorentzAngles().empty()) {
361  edm::LogError("Alignment") << "@SUB=SiStripLorentzAngleCalibration::endOfJob"
362  << "Input Lorentz angle map is empty ('"
363  << readoutModeName_ << "' mode), skip writing output!";
364  return;
365  }
366  }
367 
368  const unsigned int nonZeroParamsOrErrors = // Any determined value?
369  count_if (parameters_.begin(), parameters_.end(), [](auto c){return c!=0.;})
370  + count_if(paramUncertainties_.begin(), paramUncertainties_.end(),
371  [](auto c){return c!=0.;});
372 
373  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
374  auto firstRunOfIOV = static_cast<cond::Time_t>(moduleGroupSelector_->firstRunOfIOV(iIOV));
376  // Loop on map of values from input and add (possible) parameter results
377  for (const auto& iterIdValue: inputs[iIOV]->getLorentzAngles()) {
378  // type of 'iterIdValue' is pair<unsigned int, float>
379  const auto detId = iterIdValue.first; // key of map is DetId
380  // Some code one could use to miscalibrate wrt input:
381  // double param = 0.;
382  // const DetId id(detId);
383  // if (id.subdetId() == 3) { // TIB
384  // param = (readoutMode_ == kPeakMode ? -0.003 : -0.002);
385  // } else if (id.subdetId() == 5) { // TOB
386  // param = (readoutMode_ == kPeakMode ? 0.005 : 0.004);
387  // }
388  const double param = this->getParameterForDetId(detId, firstRunOfIOV);
389  // put result in output, i.e. sum of input and determined parameter:
390  auto value = iterIdValue.second + static_cast<float>(param);
391  output.putLorentzAngle(detId, value);
392  const int paramIndex = moduleGroupSelector_->getParameterIndexFromDetId(detId,firstRunOfIOV);
393  treeInfo[detId] = TreeStruct(param, this->getParameterError(paramIndex), paramIndex);
394  }
395 
396  if (saveToDB_ || nonZeroParamsOrErrors != 0) { // Skip writing mille jobs...
397  this->writeTree(&output, treeInfo, (treeName + Form("result_%lld", firstRunOfIOV)).c_str());
398  }
399 
400  if (saveToDB_) { // If requested, write out to DB
402  if (dbService.isAvailable()) {
403  dbService->writeOne(&output, firstRunOfIOV, recordNameDBwrite_);
404  } else {
405  edm::LogError("BadConfig") << "@SUB=SiStripLorentzAngleCalibration::endOfJob"
406  << "No PoolDBOutputService available, but saveToDB true!";
407  }
408  }
409  } // end loop on IOVs
410 }
411 
412 //======================================================================
414  int16_t mode,
415  const edm::EventSetup &setup) const
416 {
417  if (!det) return 0.;
418  double dZ = det->surface().bounds().thickness(); // it is a float only...
419  const SiStripDetId id(det->geographicalId());
421  // FIXME: which one? DepRcd->get(handle) or Rcd->get(readoutModeName_, handle)??
422  // setup.get<SiStripBackPlaneCorrectionDepRcd>().get(backPlaneHandle); // get correct mode
423  setup.get<SiStripBackPlaneCorrectionRcd>().get(readoutModeName_, backPlaneHandle);
424  const double bpCor = backPlaneHandle->getBackPlaneCorrection(id); // it's a float...
425  // std::cout << "bpCor " << bpCor << " in subdet " << id.subdetId() << std::endl;
426  dZ *= (1. - bpCor);
427 
428  return dZ;
429 }
430 
431 //======================================================================
432 const SiStripLorentzAngle*
434 {
435  const auto& resolvedRun = run > 0 ? run : currentIOV_;
436  // For parallel processing in Millepede II, create SiStripLorentzAngle
437  // from info stored in files of parallel jobs and check that they are identical.
438  // If this job has run on events, still check that LA is identical to the ones
439  // from mergeFileNames_.
440  const std::string treeName{this->name()+"_"+readoutModeName_+"_input_"+
441  std::to_string(resolvedRun)};
442  for (const auto& iFile: mergeFileNames_) {
443  auto la = this->createFromTree(iFile.c_str(), treeName.c_str());
444  // siStripLorentzAngleInput_ could be non-null from previous file of this loop
445  // or from checkLorentzAngleInput(..) when running on data in this job as well
447  cachedLorentzAngleInputs_[resolvedRun] = la;
449  currentIOV_ = resolvedRun;
450  } else {
451  // FIXME: about comparison of maps see comments in checkLorentzAngleInput
452  if (!la.getLorentzAngles().empty() && // single job might not have got events
453  la.getLorentzAngles() != siStripLorentzAngleInput_->getLorentzAngles()) {
454  // Throw exception instead of error?
455  edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
456  << "Different input values from tree " << treeName
457  << " in file " << iFile << ".";
458 
459  }
460  }
461  }
462 
463  if (!siStripLorentzAngleInput_) { // no files nor ran on events
464  // [] operator default-constructs an empty SiStripLorentzAngle object in place:
466  currentIOV_ = resolvedRun;
467  edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
468  << "No input, create an empty one ('" << readoutModeName_ << "' mode)!";
469  } else if (siStripLorentzAngleInput_->getLorentzAngles().empty()) {
470  edm::LogError("NoInput") << "@SUB=SiStripLorentzAngleCalibration::getLorentzAnglesInput"
471  << "Empty result ('" << readoutModeName_ << "' mode)!";
472  }
473 
475 }
476 
477 //======================================================================
479  edm::RunNumber_t run) const
480 {
481  const int index = moduleGroupSelector_->getParameterIndexFromDetId(detId, run);
482 
483  return (index < 0 ? 0. : parameters_[index]);
484 }
485 
486 //======================================================================
488  const std::map<unsigned int, TreeStruct> &treeInfo,
489  const char *treeName) const
490 {
491  if (!lorentzAngle) return;
492 
493  TFile* file = TFile::Open(outFileName_.c_str(), "UPDATE");
494  if (!file) {
495  edm::LogError("BadConfig") << "@SUB=SiStripLorentzAngleCalibration::writeTree"
496  << "Could not open file '" << outFileName_ << "'.";
497  return;
498  }
499 
500  TTree *tree = new TTree(treeName, treeName);
501  unsigned int id = 0;
502  float value = 0.;
503  TreeStruct treeStruct;
504  tree->Branch("detId", &id, "detId/i");
505  tree->Branch("value", &value, "value/F");
506  tree->Branch("treeStruct", &treeStruct, TreeStruct::LeafList());
507 
508  for (auto iterIdValue = lorentzAngle->getLorentzAngles().begin();
509  iterIdValue != lorentzAngle->getLorentzAngles().end(); ++iterIdValue) {
510  // type of (*iterIdValue) is pair<unsigned int, float>
511  id = iterIdValue->first; // key of map is DetId
512  value = iterIdValue->second;
513  // type of (*treeStructIter) is pair<unsigned int, TreeStruct>
514  auto treeStructIter = treeInfo.find(id); // find info for this id
515  if (treeStructIter != treeInfo.end()) {
516  treeStruct = treeStructIter->second; // info from input map
517  } else { // if none found, fill at least parameter index (using 1st IOV...)
518  const cond::Time_t run1of1stIov = moduleGroupSelector_->firstRunOfIOV(0);
519  const int ind = moduleGroupSelector_->getParameterIndexFromDetId(id, run1of1stIov);
520  treeStruct = TreeStruct(ind);
521  }
522  tree->Fill();
523  }
524  tree->Write();
525  delete file; // tree vanishes with the file...
526 }
527 
528 //======================================================================
530 SiStripLorentzAngleCalibration::createFromTree(const char *fileName, const char *treeName) const
531 {
532  // Check for file existence on your own to work around
533  // https://hypernews.cern.ch/HyperNews/CMS/get/swDevelopment/2715.html:
534  TFile* file = nullptr;
535  FILE* testFile = fopen(fileName,"r");
536  if (testFile) {
537  fclose(testFile);
538  file = TFile::Open(fileName, "READ");
539  } // else not existing, see error below
540 
541  TTree *tree = nullptr;
542  if (file) file->GetObject(treeName, tree);
543 
545  if (tree) {
546  unsigned int id = 0;
547  float value = 0.;
548  tree->SetBranchAddress("detId", &id);
549  tree->SetBranchAddress("value", &value);
550 
551  const Long64_t nEntries = tree->GetEntries();
552  for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) {
553  tree->GetEntry(iEntry);
554  result.putLorentzAngle(id, value);
555  }
556  } else { // Warning only since could be parallel job on no events.
557  edm::LogWarning("Alignment") << "@SUB=SiStripLorentzAngleCalibration::createFromTree"
558  << "Could not get TTree '" << treeName << "' from file '"
559  << fileName << (file ? "'." : "' (file does not exist).");
560  }
561 
562  delete file; // tree will vanish with file
563  return result;
564 }
565 
566 
567 //======================================================================
568 //======================================================================
569 // Plugin definition
570 
572 
574  SiStripLorentzAngleCalibration, "SiStripLorentzAngleCalibration");
RunNumber_t run() const
Definition: EventID.h:39
const TimeTypeSpecs timeTypeSpecs[]
Definition: Time.cc:22
RunNumber_t run() const
Definition: RunBase.h:40
Time_t beginValue
Definition: Time.h:45
int16_t singleReadOutMode() const
const std::vector< std::string > mergeFileNames_
SiStripLorentzAngleCalibration(const edm::ParameterSet &cfg)
Constructor.
const std::string & name() const
name of this calibration
def setup(process, global_tag, zero_tesla=False)
Definition: GeneralSetup.py:2
const Bounds & bounds() const
Definition: Surface.h:120
std::map< align::RunNumber, SiStripLorentzAngle > cachedLorentzAngleInputs_
void writeTree(const SiStripLorentzAngle *lorentzAngle, const std::map< unsigned int, TreeStruct > &treeInfo, const char *treeName) const
const edm::EventID eventId() const
const Plane & surface() const
The nominal surface of the GeomDet.
Definition: GeomDet.h:42
bool setParameter(unsigned int index, double value) override
double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const
define event information passed to algorithms
edm::ESWatcher< SiStripLorentzAngleRcd > watchLorentzAngleRcd_
structure to store algorithm results in a TTree
Definition: TreeStruct.h:6
const std::map< unsigned int, float > & getLorentzAngles() const
unsigned long long Time_t
Definition: Time.h:16
~SiStripLorentzAngleCalibration() override=default
Destructor.
const GeomDet * det() const
LocalPoint toLocal(const GlobalPoint &gp) const
std::pair< Values, unsigned int > ValuesIndexPair
x- and y-values
void get(HolderT &iHolder) const
bool isAvailable() const
Definition: Service.h:46
DetId geographicalId() const
The label of this GeomDet.
Definition: GeomDet.h:79
void writeOne(T *payload, Time_t time, const std::string &recordName, bool withlogging=false)
Definition: value.py:1
SiStripLorentzAngle createFromTree(const char *fileName, const char *treeName) const
virtual GlobalVector inTesla(const GlobalPoint &gp) const =0
Field value ad specified global point, in Tesla.
double getParameterError(unsigned int index) const override
Detector identifier class for the strip tracker.
Definition: SiStripDetId.h:17
double getParameter(unsigned int index) const override
virtual float thickness() const =0
std::pair< double, double > Values
std::unique_ptr< TkModuleGroupSelector > moduleGroupSelector_
static const char * LeafList()
Definition: TreeStruct.h:17
double effectiveThickness(const GeomDet *det, int16_t mode, const edm::EventSetup &setup) const
in non-peak mode the effective thickness is reduced...
void beginRun(const edm::Run &, const edm::EventSetup &) override
Call at beginning of run:
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
const SiStripLorentzAngle * getLorentzAnglesInput(const align::RunNumber &=0)
HLT enums.
unsigned int numParameters() const override
How many parameters does this calibration define?
T get() const
Definition: EventSetup.h:62
bool setParameterError(unsigned int index, double error) override
void beginOfJob(AlignableTracker *tracker, AlignableMuon *muon, AlignableExtras *extras) override
firstRun
Definition: dataset.py:938
#define DEFINE_EDM_PLUGIN(factory, type, name)
unsigned int RunNumber_t
eventInfo
add run, event number and lumi section
Definition: tree.py:1
unsigned int derivatives(std::vector< ValuesIndexPair > &outDerivInds, const TransientTrackingRecHit &hit, const TrajectoryStateOnSurface &tsos, const edm::EventSetup &setup, const EventInfo &eventInfo) const override
Constructor of the full muon geometry.
Definition: AlignableMuon.h:37
latency
hardware algo
const PositionType & position() const
Definition: Run.h:44
cond::RealTimeType< cond::runnumber >::type RunNumber
Definition: Utilities.h:38