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 {
56 public:
59 
61  ~SiPixelLorentzAngleCalibration() override = default;
62 
64  unsigned int numParameters() const override;
65 
68  unsigned int derivatives(std::vector<ValuesIndexPair> &outDerivInds,
70  const TrajectoryStateOnSurface &tsos,
71  const edm::EventSetup &setup,
72  const EventInfo &eventInfo) const override;
73 
76  bool setParameter(unsigned int index, double value) override;
77 
80  bool setParameterError(unsigned int index, double error) override;
81 
84  double getParameter(unsigned int index) const override;
85 
88  double getParameterError(unsigned int index) const override;
89 
93  AlignableExtras *extras) override;
94 
96  void beginRun(const edm::Run&, const edm::EventSetup&) override;
97 
100  void endOfJob() override;
101 
102 private:
107 
110  double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const;
111 
112  void writeTree(const SiPixelLorentzAngle *lorentzAngle,
113  const std::map<unsigned int,TreeStruct>& treeInfo,
114  const char *treeName) const;
115  SiPixelLorentzAngle createFromTree(const char *fileName, const char *treeName) const;
116 
117  const bool saveToDB_;
120  const std::vector<std::string> mergeFileNames_;
122 
124 
125  // const AlignableTracker *alignableTracker_;
126  std::map<align::RunNumber, SiPixelLorentzAngle> cachedLorentzAngleInputs_;
129  std::vector<double> parameters_;
130  std::vector<double> paramUncertainties_;
131 
132  std::unique_ptr<TkModuleGroupSelector> moduleGroupSelector_;
134 };
135 
136 //======================================================================
137 //======================================================================
138 //======================================================================
139 
142  saveToDB_(cfg.getParameter<bool>("saveToDB")),
143  recordNameDBwrite_(cfg.getParameter<std::string>("recordNameDBwrite")),
144  outFileName_(cfg.getParameter<std::string>("treeFile")),
145  mergeFileNames_(cfg.getParameter<std::vector<std::string> >("mergeTreeFiles")),
146  lorentzAngleLabel_(cfg.getParameter<std::string>("lorentzAngleLabel")),
147  moduleGroupSelCfg_(cfg.getParameter<edm::ParameterSet>("LorentzAngleModuleGroups"))
148 {
149 
150 }
151 
152 //======================================================================
154 {
155  return parameters_.size();
156 }
157 
158 //======================================================================
159 void
161  const edm::EventSetup& setup) {
162 
163  // no action needed if the LA record didn't change
164  if (!(watchLorentzAngleRcd_.check(setup))) return;
165 
166  const auto runNumber = run.run();
168 
169  // avoid infinite loop due to wrap-around of unsigned variable 'i' including
170  // arrow from i to zero and a nice smiley ;)
171  for (unsigned int i = moduleGroupSelector_->numIovs(); i-->0 ;) {
172  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(i);
173  if (runNumber >= firstRunOfIOV) {
174  firstRun = firstRunOfIOV;
175  break;
176  }
177  }
178 
179  edm::ESHandle<SiPixelLorentzAngle> lorentzAngleHandle;
180  const auto& lorentzAngleRcd = setup.get<SiPixelLorentzAngleRcd>();
181  lorentzAngleRcd.get(lorentzAngleLabel_, lorentzAngleHandle);
183  cachedLorentzAngleInputs_.emplace(firstRun, SiPixelLorentzAngle(*lorentzAngleHandle));
184  } else {
185  if (lorentzAngleRcd.validityInterval().first().eventID().run() > firstRun &&
186  lorentzAngleHandle->getLorentzAngles() // only bad if non-identical values
187  != cachedLorentzAngleInputs_[firstRun].getLorentzAngles()) { // (comparing maps)
188  // Maps are containers sorted by key, but comparison problems may arise from
189  // 'floating point comparison' problems (FIXME?)
190  throw cms::Exception("BadInput")
191  << "Trying to cache SiPixelLorentzAngle payload for a run (" << runNumber
192  << ") in an IOV (" << firstRun << ") that was already cached.\n"
193  << "The following record in your input database tag has an IOV "
194  << "boundary that does not match your IOV definition:\n"
195  << " - SiPixelLorentzAngleRcd '" << lorentzAngleRcd.key().name()
196  << "' (since "
197  << lorentzAngleRcd.validityInterval().first().eventID().run() << ")\n";
198  }
199  }
200 
203 }
204 
205 //======================================================================
206 unsigned int
207 SiPixelLorentzAngleCalibration::derivatives(std::vector<ValuesIndexPair> &outDerivInds,
209  const TrajectoryStateOnSurface &tsos,
210  const edm::EventSetup &setup,
211  const EventInfo &eventInfo) const
212 {
213  outDerivInds.clear();
214 
215  if (hit.det()) { // otherwise 'constraint hit' or whatever
216 
217  const int index = moduleGroupSelector_->getParameterIndexFromDetId(hit.det()->geographicalId(),
218  eventInfo.eventId().run());
219  if (index >= 0) { // otherwise not treated
221  setup.get<IdealMagneticFieldRecord>().get(magneticField);
222  const GlobalVector bField(magneticField->inTesla(hit.det()->surface().position()));
223  const LocalVector bFieldLocal(hit.det()->surface().toLocal(bField));
224  const double dZ = hit.det()->surface().bounds().thickness(); // it is a float only...
225  // shift due to LA: dx = tan(LA) * dz/2 = mobility * B_y * dz/2,
226  // shift due to LA: dy = - mobility * B_x * dz/2,
227  // '-' since we have derivative of the residual r = trk -hit
228  const double xDerivative = bFieldLocal.y() * dZ * -0.5; // parameter is mobility!
229  const double yDerivative = bFieldLocal.x() * dZ * 0.5; // parameter is mobility!
230  if (xDerivative || yDerivative) { // If field is zero, this is zero: do not return it
231  const Values derivs{xDerivative, yDerivative};
232  outDerivInds.push_back(ValuesIndexPair(derivs, index));
233  }
234  }
235  } else {
236  edm::LogWarning("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::derivatives2"
237  << "Hit without GeomDet, skip!";
238  }
239 
240  return outDerivInds.size();
241 }
242 
243 //======================================================================
245 {
246  if (index >= parameters_.size()) {
247  return false;
248  } else {
250  return true;
251  }
252 }
253 
254 //======================================================================
256 {
257  if (index >= paramUncertainties_.size()) {
258  return false;
259  } else {
261  return true;
262  }
263 }
264 
265 //======================================================================
267 {
268  return (index >= parameters_.size() ? 0. : parameters_[index]);
269 }
270 
271 //======================================================================
273 {
274  return (index >= paramUncertainties_.size() ? 0. : paramUncertainties_[index]);
275 }
276 
277 
278 
279 
280 //======================================================================
282  AlignableMuon * /*aliMuon*/,
283  AlignableExtras * /*aliExtras*/)
284 {
285  //specify the sub-detectors for which the LA is determined
286  const std::vector<int> sdets = {PixelSubdetector::PixelBarrel, PixelSubdetector::PixelEndcap};
287 
289  std::make_unique<TkModuleGroupSelector>(aliTracker, moduleGroupSelCfg_, sdets);
290 
291  parameters_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
292  paramUncertainties_.resize(moduleGroupSelector_->getNumberOfParameters(), 0.);
293 
294  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration" << "Created with name "
295  << this->name() << "',\n" << this->numParameters() << " parameters to be determined,"
296  << "\n saveToDB = " << saveToDB_
297  << "\n outFileName = " << outFileName_
298  << "\n N(merge files) = " << mergeFileNames_.size()
299  << "\n number of IOVs = " << moduleGroupSelector_->numIovs();
300 
301  if (!mergeFileNames_.empty()) {
302  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration"
303  << "First file to merge: " << mergeFileNames_[0];
304  }
305 }
306 
307 
308 //======================================================================
310 {
311  // loginfo output
312  std::ostringstream out;
313  out << "Parameter results\n";
314  for (unsigned int iPar = 0; iPar < parameters_.size(); ++iPar) {
315  out << iPar << ": " << parameters_[iPar] << " +- " << paramUncertainties_[iPar] << "\n";
316  }
317  edm::LogInfo("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob" << out.str();
318 
319  std::map<unsigned int, TreeStruct> treeInfo; // map of TreeStruct for each detId
320 
321  // now write 'input' tree(s)
322  const std::string treeName{this->name() + '_'};
323  std::vector<const SiPixelLorentzAngle*> inputs{};
324  inputs.reserve(moduleGroupSelector_->numIovs());
325  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
326  const auto firstRunOfIOV = moduleGroupSelector_->firstRunOfIOV(iIOV);
327  inputs.push_back(this->getLorentzAnglesInput(firstRunOfIOV)); // never NULL
328  this->writeTree(inputs.back(), treeInfo,
329  (treeName + "input_" + std::to_string(firstRunOfIOV)).c_str()); // empty treeInfo for input...
330 
331  if (inputs.back()->getLorentzAngles().empty()) {
332  edm::LogError("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob"
333  << "Input Lorentz angle map is empty, skip writing output!";
334  return;
335  }
336  }
337 
338  const unsigned int nonZeroParamsOrErrors = // Any determined value?
339  count_if (parameters_.begin(), parameters_.end(), std::bind2nd(std::not_equal_to<double>(),0.))
340  + count_if(paramUncertainties_.begin(), paramUncertainties_.end(),
341  std::bind2nd(std::not_equal_to<double>(), 0.));
342 
343  for (unsigned int iIOV = 0; iIOV < moduleGroupSelector_->numIovs(); ++iIOV) {
344  auto firstRunOfIOV = static_cast<cond::Time_t>(moduleGroupSelector_->firstRunOfIOV(iIOV));
346  // Loop on map of values from input and add (possible) parameter results
347  for (const auto& iterIdValue: inputs[iIOV]->getLorentzAngles()) {
348  // type of 'iterIdValue' is pair<unsigned int, float>
349  const auto detId = iterIdValue.first; // key of map is DetId
350  const auto param = this->getParameterForDetId(detId, firstRunOfIOV);
351  // put result in output, i.e. sum of input and determined parameter, but the nasty
352  // putLorentzAngle(..) takes float by reference - not even const reference:
353  auto value = iterIdValue.second + static_cast<float>(param);
354  output.putLorentzAngle(detId, value);
355  const int paramIndex = moduleGroupSelector_->getParameterIndexFromDetId(detId,firstRunOfIOV);
356  treeInfo[detId] = TreeStruct(param, this->getParameterError(paramIndex), paramIndex);
357  }
358 
359  if (saveToDB_ || nonZeroParamsOrErrors != 0) { // Skip writing mille jobs...
360  this->writeTree(&output, treeInfo, (treeName + Form("result_%lld", firstRunOfIOV)).c_str());
361  }
362 
363  if (saveToDB_) { // If requested, write out to DB
365  if (dbService.isAvailable()) {
366  dbService->writeOne(&output, firstRunOfIOV, recordNameDBwrite_);
367  } else {
368  edm::LogError("BadConfig") << "@SUB=SiPixelLorentzAngleCalibration::endOfJob"
369  << "No PoolDBOutputService available, but saveToDB true!";
370  }
371  }
372  } // end loop on IOVs
373 
374 }
375 
376 //======================================================================
377 const SiPixelLorentzAngle*
379 {
380  const auto& resolvedRun = run > 0 ? run : currentIOV_;
381  // For parallel processing in Millepede II, create SiPixelLorentzAngle
382  // from info stored in files of parallel jobs and check that they are identical.
383  // If this job has run on data, still check that LA is identical to the ones
384  // from mergeFileNames_.
385  const std::string treeName{this->name()+"_input_"+std::to_string(resolvedRun)};
386  for (const auto& iFile: mergeFileNames_) {
387  auto la = this->createFromTree(iFile.c_str(), treeName.c_str());
388  // siPixelLorentzAngleInput_ could be non-null from previous file of this loop
389  // or from checkLorentzAngleInput(..) when running on data in this job as well
391  cachedLorentzAngleInputs_[resolvedRun] = la;
393  currentIOV_ = resolvedRun;
394  } else {
395  // FIXME: about comparison of maps see comments in checkLorentzAngleInput
396  if (!la.getLorentzAngles().empty() && // single job might not have got events
397  la.getLorentzAngles() != siPixelLorentzAngleInput_->getLorentzAngles()) {
398  // Throw exception instead of error?
399  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
400  << "Different input values from tree " << treeName
401  << " in file " << iFile << ".";
402 
403  }
404  }
405  }
406 
407  if (!siPixelLorentzAngleInput_) { // no files nor ran on events
408  // [] operator default-constructs an empty SiPixelLorentzAngle object in place:
410  currentIOV_ = resolvedRun;
411  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
412  << "No input, create an empty one!";
413  } else if (siPixelLorentzAngleInput_->getLorentzAngles().empty()) {
414  edm::LogError("NoInput") << "@SUB=SiPixelLorentzAngleCalibration::getLorentzAnglesInput"
415  << "Empty result!";
416  }
417 
419 }
420 
421 //======================================================================
423  edm::RunNumber_t run) const
424 {
425  const int index = moduleGroupSelector_->getParameterIndexFromDetId(detId, run);
426  return (index < 0 ? 0. : parameters_[index]);
427 }
428 
429 //======================================================================
431  const std::map<unsigned int,TreeStruct> &treeInfo,
432  const char *treeName) const
433 {
434  if (!lorentzAngle) return;
435 
436  TFile* file = TFile::Open(outFileName_.c_str(), "UPDATE");
437  if (!file) {
438  edm::LogError("BadConfig") << "@SUB=SiPixelLorentzAngleCalibration::writeTree"
439  << "Could not open file '" << outFileName_ << "'.";
440  return;
441  }
442 
443  TTree *tree = new TTree(treeName, treeName);
444  unsigned int id = 0;
445  float value = 0.;
446  TreeStruct treeStruct;
447  tree->Branch("detId", &id, "detId/i");
448  tree->Branch("value", &value, "value/F");
449  tree->Branch("treeStruct", &treeStruct, TreeStruct::LeafList());
450 
451  for (auto iterIdValue = lorentzAngle->getLorentzAngles().begin();
452  iterIdValue != lorentzAngle->getLorentzAngles().end(); ++iterIdValue) {
453  // type of (*iterIdValue) is pair<unsigned int, float>
454  id = iterIdValue->first; // key of map is DetId
455  value = iterIdValue->second;
456  // type of (*treeStructIter) is pair<unsigned int, TreeStruct>
457  auto treeStructIter = treeInfo.find(id); // find info for this id
458  if (treeStructIter != treeInfo.end()) {
459  treeStruct = treeStructIter->second; // info from input map
460  } else { // if none found, fill at least parameter index (using 1st IOV...)
461  const cond::Time_t run1of1stIov = moduleGroupSelector_->firstRunOfIOV(0);
462  const int ind = moduleGroupSelector_->getParameterIndexFromDetId(id, run1of1stIov);
463  treeStruct = TreeStruct(ind);
464  }
465  tree->Fill();
466  }
467  tree->Write();
468  delete file; // tree vanishes with the file... (?)
469 
470 }
471 
472 //======================================================================
474 SiPixelLorentzAngleCalibration::createFromTree(const char *fileName, const char *treeName) const
475 {
476  // Check for file existence on your own to work around
477  // https://hypernews.cern.ch/HyperNews/CMS/get/swDevelopment/2715.html:
478  TFile* file = nullptr;
479  FILE* testFile = fopen(fileName,"r");
480  if (testFile) {
481  fclose(testFile);
482  file = TFile::Open(fileName, "READ");
483  } // else not existing, see error below
484 
485  TTree *tree = nullptr;
486  if (file) file->GetObject(treeName, tree);
487 
489  if (tree) {
490  unsigned int id = 0;
491  float value = 0.;
492  tree->SetBranchAddress("detId", &id);
493  tree->SetBranchAddress("value", &value);
494 
495  const Long64_t nEntries = tree->GetEntries();
496  for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) {
497  tree->GetEntry(iEntry);
498  result.putLorentzAngle(id, value);
499  }
500  } else { // Warning only since could be parallel job on no events.
501  edm::LogWarning("Alignment") << "@SUB=SiPixelLorentzAngleCalibration::createFromTree"
502  << "Could not get TTree '" << treeName << "' from file '"
503  << fileName << (file ? "'." : "' (file does not exist).");
504  }
505 
506  delete file; // tree will vanish with file
507  return result;
508 }
509 
510 
511 //======================================================================
512 //======================================================================
513 // Plugin definition
514 
516 
518  SiPixelLorentzAngleCalibration, "SiPixelLorentzAngleCalibration");
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:1
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
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 get(HolderT &iHolder) const
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: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
virtual GlobalVector inTesla(const GlobalPoint &gp) const =0
Field value ad specified global point, in Tesla.
double getParameterError(unsigned int index) const override
double getParameterForDetId(unsigned int detId, edm::RunNumber_t run) const
virtual float thickness() const =0
std::pair< double, double > Values
const T & get() const
Definition: EventSetup.h:59
~SiPixelLorentzAngleCalibration() override=default
Destructor.
static const char * LeafList()
Definition: TreeStruct.h:17
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
HLT enums.
const std::vector< std::string > mergeFileNames_
firstRun
Definition: dataset.py:933
#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:43
cond::RealTimeType< cond::runnumber >::type RunNumber
Definition: Utilities.h:38