CMS 3D CMS Logo

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