CMS 3D CMS Logo

SiPixelLorentzAngleCalibration.cc
Go to the documentation of this file.
1 
16 // include 'locally':
17 #include "TreeStruct.h"
18 
22 
25 
30 
34 
40 
41 #include "TTree.h"
42 #include "TFile.h"
43 #include "TString.h"
44 
45 #include <vector>
46 #include <map>
47 #include <sstream>
48 #include <list>
49 #include <utility>
50 #include <set>
51 #include <memory>
52 #include <functional>
53 
55 public:
58 
60  ~SiPixelLorentzAngleCalibration() 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 
91 
93  void beginRun(const edm::Run &, const edm::EventSetup &) override;
94 
97  void endOfJob() override;
98 
99 private:
104 
107  double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const;
108 
109  void writeTree(const SiPixelLorentzAngle *lorentzAngle,
110  const std::map<unsigned int, TreeStruct> &treeInfo,
111  const char *treeName) const;
112  SiPixelLorentzAngle createFromTree(const char *fileName, const char *treeName) const;
113 
114  const bool saveToDB_;
117  const std::vector<std::string> mergeFileNames_;
122 
123  // const AlignableTracker *alignableTracker_;
124  std::map<align::RunNumber, SiPixelLorentzAngle> cachedLorentzAngleInputs_;
127  std::vector<double> parameters_;
128  std::vector<double> paramUncertainties_;
129 
130  std::unique_ptr<TkModuleGroupSelector> moduleGroupSelector_;
132 };
133 
134 //======================================================================
135 //======================================================================
136 //======================================================================
137 
140  saveToDB_(cfg.getParameter<bool>("saveToDB")),
141  recordNameDBwrite_(cfg.getParameter<std::string>("recordNameDBwrite")),
142  outFileName_(cfg.getParameter<std::string>("treeFile")),
143  mergeFileNames_(cfg.getParameter<std::vector<std::string> >("mergeTreeFiles")),
144  lorentzAngleLabel_(cfg.getParameter<std::string>("lorentzAngleLabel")),
145  lorentzAngleToken_(iC.esConsumes<edm::Transition::BeginRun>(edm::ESInputTag("", lorentzAngleLabel_))),
146  magFieldToken_(iC.esConsumes()),
147  moduleGroupSelCfg_(cfg.getParameter<edm::ParameterSet>("LorentzAngleModuleGroups")) {}
148 
149 //======================================================================
150 unsigned int SiPixelLorentzAngleCalibration::numParameters() const { return parameters_.size(); }
151 
152 //======================================================================
154  // no action needed if the LA record didn't change
156  return;
157 
158  const auto runNumber = run.run();
160 
161  // avoid infinite loop due to wrap-around of unsigned variable 'i' including
162  // arrow from i to zero and a nice smiley ;)
163  for (unsigned int i = moduleGroupSelector_->numIovs(); i-- > 0;) {
164  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(i);
165  if (runNumber >= firstRunOfIOV) {
166  firstRun = firstRunOfIOV;
167  break;
168  }
169  }
170 
171  const SiPixelLorentzAngle *lorentzAngleHandle = &setup.getData(lorentzAngleToken_);
172  const auto &lorentzAngleRcd = setup.get<SiPixelLorentzAngleRcd>();
173 
175  cachedLorentzAngleInputs_.emplace(firstRun, SiPixelLorentzAngle(*lorentzAngleHandle));
176  } else {
177  if (lorentzAngleRcd.validityInterval().first().eventID().run() > firstRun &&
178  lorentzAngleHandle->getLorentzAngles() // only bad if non-identical values
179  != cachedLorentzAngleInputs_[firstRun].getLorentzAngles()) { // (comparing maps)
180  // Maps are containers sorted by key, but comparison problems may arise from
181  // 'floating point comparison' problems (FIXME?)
182  throw cms::Exception("BadInput") << "Trying to cache SiPixelLorentzAngle payload for a run (" << runNumber
183  << ") in an IOV (" << firstRun << ") that was already cached.\n"
184  << "The following record in your input database tag has an IOV "
185  << "boundary that does not match your IOV definition:\n"
186  << " - SiPixelLorentzAngleRcd '" << lorentzAngleRcd.key().name() << "' (since "
187  << lorentzAngleRcd.validityInterval().first().eventID().run() << ")\n";
188  }
189  }
190 
193 }
194 
195 //======================================================================
196 unsigned int SiPixelLorentzAngleCalibration::derivatives(std::vector<ValuesIndexPair> &outDerivInds,
198  const TrajectoryStateOnSurface &tsos,
199  const edm::EventSetup &setup,
200  const EventInfo &eventInfo) const {
201  outDerivInds.clear();
202 
203  if (hit.det()) { // otherwise 'constraint hit' or whatever
204 
205  const int index =
206  moduleGroupSelector_->getParameterIndexFromDetId(hit.det()->geographicalId(), eventInfo.eventId().run());
207  if (index >= 0) { // otherwise not treated
208 
209  const MagneticField *magneticField = &setup.getData(magFieldToken_);
210  const GlobalVector bField(magneticField->inTesla(hit.det()->surface().position()));
211  const LocalVector bFieldLocal(hit.det()->surface().toLocal(bField));
212  const double dZ = hit.det()->surface().bounds().thickness(); // it is a float only...
213  // shift due to LA: dx = tan(LA) * dz/2 = mobility * B_y * dz/2,
214  // shift due to LA: dy = - mobility * B_x * dz/2,
215  // '-' since we have derivative of the residual r = trk -hit
216  const double xDerivative = bFieldLocal.y() * dZ * -0.5; // parameter is mobility!
217  const double yDerivative = bFieldLocal.x() * dZ * 0.5; // parameter is mobility!
218  if (xDerivative || yDerivative) { // If field is zero, this is zero: do not return it
219  const Values derivs{xDerivative, yDerivative};
220  outDerivInds.push_back(ValuesIndexPair(derivs, index));
221  }
222  }
223  } else {
224  edm::LogWarning("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::derivatives2"
225  << "Hit without GeomDet, skip!";
226  }
227 
228  return outDerivInds.size();
229 }
230 
231 //======================================================================
233  if (index >= parameters_.size()) {
234  return false;
235  } else {
237  return true;
238  }
239 }
240 
241 //======================================================================
243  if (index >= paramUncertainties_.size()) {
244  return false;
245  } else {
247  return true;
248  }
249 }
250 
251 //======================================================================
253  return (index >= parameters_.size() ? 0. : parameters_[index]);
254 }
255 
256 //======================================================================
258  return (index >= paramUncertainties_.size() ? 0. : paramUncertainties_[index]);
259 }
260 
261 //======================================================================
263  AlignableMuon * /*aliMuon*/,
264  AlignableExtras * /*aliExtras*/) {
265  //specify the sub-detectors for which the LA is determined
266  const std::vector<int> sdets = {PixelSubdetector::PixelBarrel, PixelSubdetector::PixelEndcap};
267 
268  moduleGroupSelector_ = std::make_unique<TkModuleGroupSelector>(aliTracker, moduleGroupSelCfg_, sdets);
269 
270  parameters_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
271  paramUncertainties_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
272 
273  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration"
274  << "Created with name " << this->name() << "',\n"
275  << this->numParameters() << " parameters to be determined,"
276  << "\n saveToDB = " << saveToDB_ << "\n outFileName = " << outFileName_
277  << "\n N(merge files) = " << mergeFileNames_.size()
278  << "\n number of IOVs = " << moduleGroupSelector_->numIovs();
279 
280  if (!mergeFileNames_.empty()) {
281  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration"
282  << "First file to merge: " << mergeFileNames_[0];
283  }
284 }
285 
286 //======================================================================
288  // loginfo output
289  std::ostringstream out;
290  out << "Parameter results\n";
291  for (unsigned int iPar = 0; iPar < parameters_.size(); ++iPar) {
292  out << iPar << ": " << parameters_[iPar] << " +- " << paramUncertainties_[iPar] << "\n";
293  }
294  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob" << out.str();
295 
296  std::map<unsigned int, TreeStruct> treeInfo; // map of TreeStruct for each detId
297 
298  // now write 'input' tree(s)
299  const std::string treeName{this->name() + '_'};
300  std::vector<const SiPixelLorentzAngle *> inputs{};
301  inputs.reserve(moduleGroupSelector_->numIovs());
302  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
303  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(iIOV);
304  inputs.push_back(this->getLorentzAnglesInput(firstRunOfIOV)); // never NULL
305  this->writeTree(inputs.back(),
306  treeInfo,
307  (treeName + "input_" + std::to_string(firstRunOfIOV)).c_str()); // empty treeInfo for input...
308 
309  if (inputs.back()->getLorentzAngles().empty()) {
310  edm::LogError("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob"
311  << "Input Lorentz angle map is empty, skip writing output!";
312  return;
313  }
314  }
315 
316  const unsigned int nonZeroParamsOrErrors = // Any determined value?
317  count_if(parameters_.begin(), parameters_.end(), [](auto c) { return c != 0.; }) +
318  count_if(paramUncertainties_.begin(), paramUncertainties_.end(), [](auto c) { return c != 0.; });
319 
320  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
321  auto firstRunOfIOV = static_cast<cond::Time_t>(moduleGroupSelector_->firstRunOfIOV(iIOV));
323  // Loop on map of values from input and add (possible) parameter results
324  for (const auto &iterIdValue : inputs[iIOV]->getLorentzAngles()) {
325  // type of 'iterIdValue' is pair<unsigned int, float>
326  const auto detId = iterIdValue.first; // key of map is DetId
327  const auto param = this->getParameterForDetId(detId, firstRunOfIOV);
328  // put result in output, i.e. sum of input and determined parameter, but the nasty
329  // putLorentzAngle(..) takes float by reference - not even const reference:
330  auto value = iterIdValue.second + static_cast<float>(param);
331  output.putLorentzAngle(detId, value);
332  const int paramIndex = moduleGroupSelector_->getParameterIndexFromDetId(detId, firstRunOfIOV);
333  treeInfo[detId] = TreeStruct(param, this->getParameterError(paramIndex), paramIndex);
334  }
335 
336  if (saveToDB_ || nonZeroParamsOrErrors != 0) { // Skip writing mille jobs...
337  this->writeTree(&output, treeInfo, (treeName + Form("result_%lld", firstRunOfIOV)).c_str());
338  }
339 
340  if (saveToDB_) { // If requested, write out to DB
342  if (dbService.isAvailable()) {
343  dbService->writeOneIOV(output, firstRunOfIOV, recordNameDBwrite_);
344  } else {
345  edm::LogError("BadConfig") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob"
346  << "No PoolDBOutputService available, but saveToDB true!";
347  }
348  }
349  } // end loop on IOVs
350 }
351 
352 //======================================================================
354  const auto &resolvedRun = run > 0 ? run : currentIOV_;
355  // For parallel processing in Millepede II, create SiPixelLorentzAngle
356  // from info stored in files of parallel jobs and check that they are identical.
357  // If this job has run on data, still check that LA is identical to the ones
358  // from mergeFileNames_.
359  const std::string treeName{this->name() + "_input_" + std::to_string(resolvedRun)};
360  for (const auto &iFile : mergeFileNames_) {
361  auto la = this->createFromTree(iFile.c_str(), treeName.c_str());
362  // siPixelLorentzAngleInput_ could be non-null from previous file of this loop
363  // or from checkLorentzAngleInput(..) when running on data in this job as well
365  cachedLorentzAngleInputs_[resolvedRun] = la;
367  currentIOV_ = resolvedRun;
368  } else {
369  // FIXME: about comparison of maps see comments in checkLorentzAngleInput
370  if (!la.getLorentzAngles().empty() && // single job might not have got events
371  la.getLorentzAngles() != siPixelLorentzAngleInput_->getLorentzAngles()) {
372  // Throw exception instead of error?
373  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
374  << "Different input values from tree " << treeName << " in file " << iFile << ".";
375  }
376  }
377  }
378 
379  if (!siPixelLorentzAngleInput_) { // no files nor ran on events
380  // [] operator default-constructs an empty SiPixelLorentzAngle object in place:
382  currentIOV_ = resolvedRun;
383  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
384  << "No input, create an empty one!";
385  } else if (siPixelLorentzAngleInput_->getLorentzAngles().empty()) {
386  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
387  << "Empty result!";
388  }
389 
391 }
392 
393 //======================================================================
395  const int index = moduleGroupSelector_->getParameterIndexFromDetId(detId, run);
396  return (index < 0 ? 0. : parameters_[index]);
397 }
398 
399 //======================================================================
401  const std::map<unsigned int, TreeStruct> &treeInfo,
402  const char *treeName) const {
403  if (!lorentzAngle)
404  return;
405 
406  TFile *file = TFile::Open(outFileName_.c_str(), "UPDATE");
407  if (!file) {
408  edm::LogError("BadConfig") << "@SUB=SiPixelLorentzAngleCalibration::writeTree"
409  << "Could not open file '" << outFileName_ << "'.";
410  return;
411  }
412 
413  TTree *tree = new TTree(treeName, treeName);
414  unsigned int id = 0;
415  float value = 0.;
416  TreeStruct treeStruct;
417  tree->Branch("detId", &id, "detId/i");
418  tree->Branch("value", &value, "value/F");
419  tree->Branch("treeStruct", &treeStruct, TreeStruct::LeafList());
420 
421  for (auto iterIdValue = lorentzAngle->getLorentzAngles().begin();
422  iterIdValue != lorentzAngle->getLorentzAngles().end();
423  ++iterIdValue) {
424  // type of (*iterIdValue) is pair<unsigned int, float>
425  id = iterIdValue->first; // key of map is DetId
426  value = iterIdValue->second;
427  // type of (*treeStructIter) is pair<unsigned int, TreeStruct>
428  auto treeStructIter = treeInfo.find(id); // find info for this id
429  if (treeStructIter != treeInfo.end()) {
430  treeStruct = treeStructIter->second; // info from input map
431  } else { // if none found, fill at least parameter index (using 1st IOV...)
432  const cond::Time_t run1of1stIov = moduleGroupSelector_->firstRunOfIOV(0);
433  const int ind = moduleGroupSelector_->getParameterIndexFromDetId(id, run1of1stIov);
434  treeStruct = TreeStruct(ind);
435  }
436  tree->Fill();
437  }
438  tree->Write();
439  delete file; // tree vanishes with the file... (?)
440 }
441 
442 //======================================================================
444  // Check for file existence on your own to work around
445  // https://hypernews.cern.ch/HyperNews/CMS/get/swDevelopment/2715.html:
446  TFile *file = nullptr;
447  FILE *testFile = fopen(fileName, "r");
448  if (testFile) {
449  fclose(testFile);
450  file = TFile::Open(fileName, "READ");
451  } // else not existing, see error below
452 
453  TTree *tree = nullptr;
454  if (file)
455  file->GetObject(treeName, tree);
456 
458  if (tree) {
459  unsigned int id = 0;
460  float value = 0.;
461  tree->SetBranchAddress("detId", &id);
462  tree->SetBranchAddress("value", &value);
463 
464  const Long64_t nEntries = tree->GetEntries();
465  for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) {
466  tree->GetEntry(iEntry);
467  result.putLorentzAngle(id, value);
468  }
469  } else { // Warning only since could be parallel job on no events.
470  edm::LogWarning("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::createFromTree"
471  << "Could not get TTree '" << treeName << "' from file '" << fileName
472  << (file ? "'." : "' (file does not exist).");
473  }
474 
475  delete file; // tree will vanish with file
476  return result;
477 }
478 
479 //======================================================================
480 //======================================================================
481 // Plugin definition
482 
484 
const TimeTypeSpecs timeTypeSpecs[]
Definition: Time.cc:16
bool setParameterError(unsigned int index, double error) override
SiPixelLorentzAngleCalibration(const edm::ParameterSet &cfg, edm::ConsumesCollector &iC)
Constructor.
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
Time_t beginValue
Definition: Time.h:41
bool setParameter(unsigned int index, double value) override
unsigned int numParameters() const override
How many parameters does this calibration define?
SiPixelLorentzAngle createFromTree(const char *fileName, const char *treeName) const
void beginRun(const edm::Run &, const edm::EventSetup &) override
Call at beginning of run:
const std::map< unsigned int, float > & getLorentzAngles() const
double getParameter(unsigned int index) const override
Log< level::Error, false > LogError
const edm::ESGetToken< MagneticField, IdealMagneticFieldRecord > magFieldToken_
std::unique_ptr< TkModuleGroupSelector > moduleGroupSelector_
unsigned int derivatives(std::vector< ValuesIndexPair > &outDerivInds, const TransientTrackingRecHit &hit, const TrajectoryStateOnSurface &tsos, const edm::EventSetup &setup, const EventInfo &eventInfo) const override
static std::string to_string(const XMLCh *ch)
define event information passed to algorithms
structure to store algorithm results in a TTree
Definition: TreeStruct.h:6
edm::ESWatcher< SiPixelLorentzAngleRcd > watchLorentzAngleRcd_
std::map< align::RunNumber, SiPixelLorentzAngle > cachedLorentzAngleInputs_
unsigned long long Time_t
Definition: Time.h:14
std::pair< Values, unsigned int > ValuesIndexPair
x- and y-values
double getParameterError(unsigned int index) const override
void beginOfJob(AlignableTracker *tracker, AlignableMuon *muon, AlignableExtras *extras) override
Call at beginning of job:
const SiPixelLorentzAngle * getLorentzAnglesInput(const align::RunNumber &=0)
Hash writeOneIOV(const T &payload, Time_t time, const std::string &recordName)
Transition
Definition: Transition.h:12
Definition: value.py:1
std::pair< double, double > Values
Log< level::Info, false > LogInfo
double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const
~SiPixelLorentzAngleCalibration() override=default
Destructor.
static const char * LeafList()
Definition: TreeStruct.h:16
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
const edm::ESGetToken< SiPixelLorentzAngle, SiPixelLorentzAngleRcd > lorentzAngleToken_
HLT enums.
const std::vector< std::string > mergeFileNames_
#define DEFINE_EDM_PLUGIN(factory, type, name)
bool isAvailable() const
Definition: Service.h:40
Definition: output.py:1
unsigned int RunNumber_t
eventInfo
add run, event number and lumi section
Definition: tree.py:1
Log< level::Warning, false > LogWarning
Constructor of the full muon geometry.
Definition: AlignableMuon.h:38
const std::string & name() const
name of this calibration
void writeTree(const SiPixelLorentzAngle *lorentzAngle, const std::map< unsigned int, TreeStruct > &treeInfo, const char *treeName) const
Definition: Run.h:45
cond::RealTimeType< cond::runnumber >::type RunNumber
Definition: Utilities.h:37