CMS 3D CMS Logo

SiPixelSCurveCalibrationAnalysis.cc
Go to the documentation of this file.
2 #include "TMath.h"
3 
4 #include <iostream>
5 #include <fstream>
6 
13 #include <sstream>
14 
15 //initialize static members
18 
19 
23 }
24 
26  std::ofstream myfile;
27  myfile.open (thresholdfilename_.c_str());
28  for(detIDHistogramMap::iterator thisDetIdHistoGrams= histograms_.begin(); thisDetIdHistoGrams != histograms_.end(); ++thisDetIdHistoGrams){
29  // loop over det id (det id = number (unsigned int) of pixel module
30  const MonitorElement *sigmahist = (*thisDetIdHistoGrams).second[kSigmas];
31  const MonitorElement *thresholdhist = (*thisDetIdHistoGrams).second[kThresholds];
32  uint32_t detid = (*thisDetIdHistoGrams).first;
33  std::string name = sigmahist->getTitle();
34  std::string rocname = name.substr(0,name.size()-7);
35  rocname+="_ROC";
36  int total_rows = sigmahist ->getNbinsY();
37  int total_columns = sigmahist->getNbinsX();
38  //loop over all rows on columns on all ROCs
39  for (int irow=0; irow<total_rows; ++irow){
40  for (int icol=0; icol<total_columns; ++icol){
41  float threshold_error = sigmahist->getBinContent(icol+1,irow+1); // +1 because root bins start at 1
42  if(writeZeroes_ ||(!writeZeroes_ && threshold_error>0)){
43  //changing from offline to online numbers
44  int realfedID=-1;
45  for(int fedid=0; fedid<=40; ++fedid){
47  if(converter.hasDetUnit(detid)){
48  realfedID=fedid;
49  break;
50  }
51  }
52  if (realfedID==-1){
53  std::cout<<"error: could not obtain real fed ID"<<std::endl;
54  }
55  sipixelobjects::DetectorIndex detector ={detid,irow,icol};
57  SiPixelFrameConverter formatter(theCablingMap_.product(),realfedID);
58  formatter.toCabling(cabling,detector);
59  // cabling should now contain cabling.roc and cabling.dcol and cabling.pxid
60  // however, the coordinates now need to be converted from dcl,pxid to the row,col coordinates used in the calibration info
62  loc.dcol = cabling.dcol;
63  loc.pxid = cabling.pxid;
64  // FIX to adhere to new cabling map. To be replaced with CalibTracker/SiPixelTools detid - > hardware id classes ASAP.
65  // const sipixelobjects::PixelFEDCabling *theFed= theCablingMap.product()->fed(realfedID);
66  // const sipixelobjects::PixelFEDLink * link = theFed->link(cabling.link);
67  // const sipixelobjects::PixelROC *theRoc = link->roc(cabling.roc);
68  sipixelobjects::LocalPixel locpixel(loc);
69  sipixelobjects::CablingPathToDetUnit path = {static_cast<unsigned int>(realfedID),
70  static_cast<unsigned int>(cabling.link),
71  static_cast<unsigned int>(cabling.roc)};
72  const sipixelobjects::PixelROC *theRoc = theCablingMap_->findItem(path);
73  // END of FIX
74  int newrow= locpixel.rocRow();
75  int newcol = locpixel.rocCol();
76  myfile<<rocname<<theRoc->idInDetUnit()<<" "<<newcol<<" "<<newrow<<" "<<thresholdhist->getBinContent(icol+1, irow+1)<<" "<<threshold_error; // +1 because root bins start at 1
77  myfile<<"\n";
78  }
79  }
80  }
81  }
82  myfile.close();
83 }
84 
85 //used for TMinuit fitting
86 void chi2toMinimize(int &npar, double* grad, double &fcnval, double* xval, int iflag)
87 {
89  //setup function parameters
90  for (int i = 0; i < npar; i++)
91  theFormula->SetParameter(i, xval[i]);
92  fcnval = 0;
93  //compute Chi2 of all points
94  const std::vector<short>* theVCalValues = SiPixelSCurveCalibrationAnalysis::getVcalValues();
95  for (uint32_t i = 0; i < theVCalValues->size(); i++)
96  {
97  float chi = (SiPixelSCurveCalibrationAnalysis::efficiencies_[i] - theFormula->Eval((*theVCalValues)[i]) );
99  fcnval += chi*chi;
100  }
101 }
102 
103 void
105 {
106  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Setting up calibration paramters.";
107  std::vector<uint32_t> anEmptyDefaultVectorOfUInts;
108  std::vector<uint32_t> detIDsToSaveVector_;
109  useDetectorHierarchyFolders_ = iConfig.getUntrackedParameter<bool>("useDetectorHierarchyFolders", true);
110  saveCurvesThatFlaggedBad_ = iConfig.getUntrackedParameter<bool>("saveCurvesThatFlaggedBad", false);
111  detIDsToSaveVector_ = iConfig.getUntrackedParameter<std::vector<uint32_t> >("detIDsToSave", anEmptyDefaultVectorOfUInts);
112  maxCurvesToSave_ = iConfig.getUntrackedParameter<uint32_t>("maxCurvesToSave", 1000);
113  write2dHistograms_ = iConfig.getUntrackedParameter<bool>("write2dHistograms", true);
114  write2dFitResult_ = iConfig.getUntrackedParameter<bool>("write2dFitResult", true);
115  printoutthresholds_ = iConfig.getUntrackedParameter<bool>("writeOutThresholdSummary",true);
116  thresholdfilename_ = iConfig.getUntrackedParameter<std::string>("thresholdOutputFileName","thresholds.txt");
117  minimumChi2prob_ = iConfig.getUntrackedParameter<double>("minimumChi2prob", 0);
118  minimumThreshold_ = iConfig.getUntrackedParameter<double>("minimumThreshold", -10);
119  maximumThreshold_ = iConfig.getUntrackedParameter<double>("maximumThreshold", 300);
120  minimumSigma_ = iConfig.getUntrackedParameter<double>("minimumSigma", 0);
121  maximumSigma_ = iConfig.getUntrackedParameter<double>("maximumSigma", 100);
122  minimumEffAsymptote_ = iConfig.getUntrackedParameter<double>("minimumEffAsymptote", 0);
123  maximumEffAsymptote_ = iConfig.getUntrackedParameter<double>("maximumEffAsymptote", 1000);
124  maximumSigmaBin_ = iConfig.getUntrackedParameter<double>("maximumSigmaBin", 10);
125  maximumThresholdBin_ = iConfig.getUntrackedParameter<double>("maximumThresholdBin", 255);
126 
127  writeZeroes_= iConfig.getUntrackedParameter<bool>("alsoWriteZeroThresholds", false);
128 
129  // convert the vector into a map for quicker lookups.
130  for(unsigned int i = 0; i < detIDsToSaveVector_.size(); i++)
131  detIDsToSave_.insert( std::make_pair(detIDsToSaveVector_[i], true) );
132 }
133 
135 {
136  //do nothing
137 }
138 
139 void SiPixelSCurveCalibrationAnalysis::buildACurveHistogram(const uint32_t& detid, const uint32_t& row, const uint32_t& col, sCurveErrorFlag errorFlag, const std::vector<float>& efficiencies, const std::vector<float>& errors)
140 {
142  {
143  edm::LogWarning("SiPixelSCurveCalibrationAnalysis") << "WARNING: Request to save curve for [detid](col/row): [" << detid << "](" << col << "/" << row << ") denied. Maximum number of saved curves (defined in .cfi) exceeded.";
144  return;
145  }
146  std::ostringstream rootName;
147  rootName << "SCurve_row_" << row << "_col_" << col;
148  std::ostringstream humanName;
149  humanName << translateDetIdToString(detid) << "_" << rootName.str() << "_ErrorFlag_" << (int)errorFlag;
150 
151  unsigned int numberOfVCalPoints = vCalPointsAsFloats_.size()-1; //minus one is necessary since the lower edge of the last bin must be added
152  if (efficiencies.size() != numberOfVCalPoints || errors.size() != numberOfVCalPoints)
153  {
154  edm::LogError("SiPixelSCurveCalibrationAnalysis") << "Error saving single curve histogram! Number of Vcal values (" << numberOfVCalPoints << ") does not match number of efficiency points or error points!";
155  return;
156  }
157  setDQMDirectory(detid);
158  float * vcalValuesToPassToCrappyRoot = &vCalPointsAsFloats_[0];
159  MonitorElement * aBadHisto = bookDQMHistogram1D(detid, rootName.str(), humanName.str(), numberOfVCalPoints, vcalValuesToPassToCrappyRoot); //ROOT only takes an input as array. :( HOORAY FOR CINT!
161  for(unsigned int iBin = 0; iBin < numberOfVCalPoints; ++iBin)
162  {
163  int rootBin = iBin + 1; //root bins start at 1
164  aBadHisto->setBinContent(rootBin, efficiencies[iBin]);
165  aBadHisto->setBinError(rootBin, errors[iBin]);
166  }
167 }
168 
170 {
171  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Calibration Settings: VCalLow: " << vCalValues_[0] << " VCalHigh: " << vCalValues_[vCalValues_.size()-1] << " nVCal: " << vCalValues_.size() << " nTriggers: " << nTriggers_;
174  {
175  //build the vCal values as a vector of floats if we want to save single curves
176  const std::vector<short>* theVCalValues = this->getVcalValues();
177  unsigned int numberOfVCalPoints = theVCalValues->size();
178  edm::LogWarning("SiPixelSCurveCalibrationAnalysis") << "WARNING: Option set to save indiviual S-Curves - max number: "
179  << maxCurvesToSave_ << " This can lead to large memory consumption! (Got " << numberOfVCalPoints << " VCal Points";
180  for(unsigned int i = 0; i < numberOfVCalPoints; i++)
181  {
182  vCalPointsAsFloats_.push_back( static_cast<float>((*theVCalValues)[i]) );
183  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Adding calibration Vcal: " << (*theVCalValues)[i];
184  }
185  // must add lower edge of last bin to the vector
186  vCalPointsAsFloats_.push_back( vCalPointsAsFloats_[numberOfVCalPoints-1] + 1 );
187  }
188 
189  fitFunction_ = new TF1("sCurve", "0.5*[2]*(1+TMath::Erf( (x-[0]) / ([1]*sqrt(2)) ) )", vCalValues_[0], vCalValues_[vCalValues_.size()-1]);
190 }
191 
192 bool
194 {
195  if(calibrationMode_=="SCurve")
196  return true;
197  else if(calibrationMode_=="unknown"){
198  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "calibration mode is: " << calibrationMode_ << ", continuing anyway..." ;
199  return true;
200  }
201  else{
202  // edm::LogDebug("SiPixelSCurveCalibrationAnalysis") << "unknown calibration mode for SCurves, should be \"SCurve\" and is \"" << calibrationMode_ << "\"";
203  }
204  return false;
205 }
206 
208 {
210  bool allZeroSoFar = true;
211  int turnOnBin = -1;
212  int saturationBin = -1;
213  for (uint32_t iVcalPt = 0; iVcalPt < eff.size(); iVcalPt++)
214  {
215  if (allZeroSoFar && eff[iVcalPt] != 0 ) {
216  turnOnBin = iVcalPt;
217  allZeroSoFar = false;
218  output = errNoTurnOn;
219  } else if (eff[iVcalPt] > 0.90)
220  {
221  saturationBin = iVcalPt;
222  short turnOnVcal = vCalValues_[turnOnBin];
223  short saturationVcal = vCalValues_[saturationBin];
224  short delta = saturationVcal - turnOnVcal;
225  sigma = delta * 0.682;
226  if (sigma < 1) //check to make sure sigma guess is larger than our X resolution. Hopefully prevents Minuit from getting stuck at boundary
227  sigma = 1;
228  threshold = turnOnVcal + (0.5 * delta);
229  return errOK;
230  }
231  }
232  return output;
233 }
234 
236 {
237  //check if nonsensical
238  if (threshold > vCalValues_[vCalValues_.size()-1] || threshold < vCalValues_[0] ||
239  sigma > vCalValues_[vCalValues_.size()-1] - vCalValues_[0] )
240  return errFitNonPhysical;
241 
242  if (threshold < minimumThreshold_ || threshold > maximumThreshold_ ||
243  sigma < minimumSigma_ || sigma > maximumSigma_ ||
244  amplitude < minimumEffAsymptote_ || amplitude > maximumEffAsymptote_)
245  return errFlaggedBadByUser;
246 
247  return errOK;
248 }
249 
250 void calculateEffAndError(int nADCResponse, int nTriggers, float& eff, float& error)
251 {
252  eff = (float)nADCResponse / (float)nTriggers;
253  double effForErrorCalculation = eff;
254  if (eff <= 0 || eff >= 1)
255  effForErrorCalculation = 0.5 / (double)nTriggers;
256  error = TMath::Sqrt(effForErrorCalculation*(1-effForErrorCalculation) / (double)nTriggers);
257 }
258 
259 //book histograms when new DetID is encountered in Event Record
261 {
262  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Found a new DetID (" << detid << ")! Checking to make sure it has not been added.";
263  //ensure that this DetID has not been added yet
264  sCurveHistogramHolder tempMap;
265  std::pair<detIDHistogramMap::iterator, bool> insertResult;
266  insertResult = histograms_.insert(std::make_pair(detid, tempMap));
267  if (insertResult.second) //indicates successful insertion
268  {
269  edm::LogInfo("SiPixelSCurveCalibrationAnalysisHistogramReport") << "Histogram Map.insert() returned true! Booking new histogrames for detID: " << detid;
270  // use detector hierarchy folders if desired
272  setDQMDirectory(detid);
273 
274  std::string detIdName = translateDetIdToString(detid);
275  if (write2dHistograms_){
276  MonitorElement * D2sigma = bookDQMHistoPlaquetteSummary2D(detid,"ScurveSigmas", detIdName + " Sigmas");
277  MonitorElement * D2thresh = bookDQMHistoPlaquetteSummary2D(detid,"ScurveThresholds", detIdName + " Thresholds");
278  MonitorElement * D2chi2 = bookDQMHistoPlaquetteSummary2D(detid,"ScurveChi2Prob",detIdName + " Chi2Prob");
279  insertResult.first->second.insert(std::make_pair(kSigmas, D2sigma));
280  insertResult.first->second.insert(std::make_pair(kThresholds, D2thresh));
281  insertResult.first->second.insert(std::make_pair(kChi2s, D2chi2));
282  }
283  if (write2dFitResult_){
284  MonitorElement * D2FitResult = bookDQMHistoPlaquetteSummary2D(detid,"ScurveFitResult", detIdName + " Fit Result");
285  insertResult.first->second.insert(std::make_pair(kFitResults, D2FitResult));
286  }
287  MonitorElement * D1sigma = bookDQMHistogram1D(detid,"ScurveSigmasSummary", detIdName + " Sigmas Summary", 100, 0, maximumSigmaBin_);
288  MonitorElement * D1thresh = bookDQMHistogram1D(detid,"ScurveThresholdSummary", detIdName + " Thresholds Summary", 255, 0, maximumThresholdBin_);
289  MonitorElement * D1chi2 = bookDQMHistogram1D(detid,"ScurveChi2ProbSummary", detIdName + " Chi2Prob Summary", 101, 0, 1.01);
290  MonitorElement * D1FitResult = bookDQMHistogram1D(detid,"ScurveFitResultSummary", detIdName + " Fit Result Summary", 10, -0.5, 9.5);
291  insertResult.first->second.insert(std::make_pair(kSigmaSummary, D1sigma));
292  insertResult.first->second.insert(std::make_pair(kThresholdSummary, D1thresh));
293  insertResult.first->second.insert(std::make_pair(kChi2Summary, D1chi2));
294  insertResult.first->second.insert(std::make_pair(kFitResultSummary, D1FitResult));
295  }
296 }
297 
298 bool SiPixelSCurveCalibrationAnalysis::doFits(uint32_t detid, std::vector<SiPixelCalibDigi>::const_iterator calibDigi)
299 {
300  sCurveErrorFlag errorFlag = errOK;
301  uint32_t nVCalPts = calibDigi->getnpoints();
302  //reset and fill static datamembers with vector of points and errors
303  efficiencies_.resize(0);
304  effErrors_.resize(0);
305  for (uint32_t iVcalPt = 0; iVcalPt < nVCalPts; iVcalPt++)
306  {
307  float eff;
308  float error;
309  calculateEffAndError(calibDigi->getnentries(iVcalPt), nTriggers_, eff, error);
310  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Eff: " << eff << " Error: " << error << " nEntries: " << calibDigi->getnentries(iVcalPt) << " nTriggers: " << nTriggers_ << " VCalPt " << vCalValues_[iVcalPt];
311  efficiencies_.push_back(eff);
312  effErrors_.push_back(error);
313  }
314 
315  //estimate the S-Curve parameters
316  float thresholdGuess = -1.0;
317  float sigmaGuess = -1.0;
318  errorFlag = estimateSCurveParameters(efficiencies_, thresholdGuess, sigmaGuess);
319 
320  // these -1.0 default values will only be filled if the curve is all zeroes, or doesn't turn on, WHICH INDICATES A SERIOUS PROBLEM
321  Double_t sigma = -1.0;
322  Double_t sigmaError = -1.0;
323  Double_t threshold = -1.0;
324  Double_t thresholdError = -1.0;
325  Double_t amplitude = -1.0;
326  Double_t amplitudeError = -1.0;
327  Double_t chi2 = -1.0;
328  //calculate NDF
329  Int_t nDOF = vCalValues_.size() - 3;
330  Double_t chi2probability = 0;
331 
332  if (errorFlag == errOK) //only do fit if curve is fittable
333  {
334  //set up minuit fit
335  TMinuit *gMinuit = new TMinuit(3);
336  gMinuit->SetPrintLevel(-1); //save ourselves from gigabytes of stdout
337  gMinuit->SetFCN(chi2toMinimize);
338 
339  //define threshold parameters - choose step size 1, max 300, min -50
340  gMinuit->DefineParameter(0, "Threshold", (Double_t)thresholdGuess, 1, -50, 300);
341  //sigma
342  gMinuit->DefineParameter(1, "Sigma", (Double_t)sigmaGuess, 0.1, 0, 255);
343  //amplitude
344  gMinuit->DefineParameter(2, "Amplitude", 1, 0.1, -0.001, 200);
345 
346  //Do Chi2 minimazation
347  gMinuit->Migrad();
348  gMinuit->GetParameter(0, threshold, thresholdError);
349  gMinuit->GetParameter(1, sigma, sigmaError);
350  gMinuit->GetParameter(2, amplitude, amplitudeError);
351 
352  //get Chi2
353  Double_t params[3] = {threshold, sigma, amplitude};
354  gMinuit->Eval(3, nullptr, chi2, params, 0);
355  //calculate Chi2 proability
356  if (nDOF <= 0)
357  chi2probability = 0;
358  else
359  chi2probability = TMath::Prob(chi2, nDOF);
360 
361  //check to make sure output makes sense (i.e. threshold > 0)
362  if (chi2probability > minimumChi2prob_)
363  errorFlag = fittedSCurveSanityCheck(threshold, sigma, amplitude);
364  else
365  errorFlag = errBadChi2Prob;
366 
367  edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Fit finished with errorFlag: " << errorFlag << " - threshold: " << threshold << " sigma: " << sigma << " chi2: " << chi2 << " nDOF: " << nDOF << " chi2Prob: " << chi2probability << " chi2MinUser: " << minimumChi2prob_;
368 
369  delete gMinuit;
370  }
371  //get row and column for this pixel
372  uint32_t row = calibDigi->row();
373  uint32_t col = calibDigi->col();
374 
375  //get iterator to histogram holder for this detid
376  detIDHistogramMap::iterator thisDetIdHistoGrams;
377  thisDetIdHistoGrams = histograms_.find(detid);
378  if (thisDetIdHistoGrams != histograms_.end())
379  {
380  edm::LogInfo("SiPixelSCurveCalibrationAnalysisHistogramReport") << "Filling histograms for [detid](col/row): [" << detid << "](" << col << "/" << row << ") ErrorFlag: " << errorFlag;
381  //always fill fit result
382  (*thisDetIdHistoGrams).second[kFitResultSummary]->Fill(errorFlag);
383  if (write2dFitResult_)
384  (*thisDetIdHistoGrams).second[kFitResults]->setBinContent(col+1, row+1, errorFlag); // +1 because root bins start at 1
385 
386  // fill sigma/threshold result
387  (*thisDetIdHistoGrams).second[kSigmaSummary]->Fill(sigma);
388  (*thisDetIdHistoGrams).second[kThresholdSummary]->Fill(threshold);
389  if (write2dHistograms_)
390  {
391  (*thisDetIdHistoGrams).second[kSigmas]->setBinContent(col+1, row+1, sigma); // +1 because root bins start at 1
392  (*thisDetIdHistoGrams).second[kThresholds]->setBinContent(col+1, row+1, threshold); // +1 because root bins start at 1
393  }
394  // fill chi2
395  (*thisDetIdHistoGrams).second[kChi2Summary]->Fill(chi2probability);
396  if (write2dHistograms_)
397  (*thisDetIdHistoGrams).second[kChi2s]->Fill(col, row, chi2probability);
398  }
399  // save individual curves, if requested
401  {
402  bool thisDetIDinList = false;
403  if (detIDsToSave_.find(detid) != detIDsToSave_.end()) //see if we want to save this histogram
404  thisDetIDinList = true;
405 
406  if (errorFlag != errOK || thisDetIDinList)
407  {
408  edm::LogError("SiPixelSCurveCalibrationAnalysis") << "Saving error histogram for [detid](col/row): [" << detid << "](" << col << "/" << row << ") ErrorFlag: " << errorFlag;
409  buildACurveHistogram(detid, row, col, errorFlag, efficiencies_, effErrors_);
410  }
411  }
412 
413  return true;
414 
415 }
dbl * delta
Definition: mlp_gen.cc:36
T getUntrackedParameter(std::string const &, T const &) const
void setBinContent(int binx, double content)
set content of bin (1-D)
void calculateEffAndError(int nADCResponse, int nTriggers, float &eff, float &error)
void calibrationSetup(const edm::EventSetup &iSetup) override
std::string translateDetIdToString(uint32_t detid)
MonitorElement * bookDQMHistoPlaquetteSummary2D(uint32_t detid, std::string name, std::string title)
identify pixel inside single ROC
Definition: LocalPixel.h:7
std::map< sCurveHistogramType, MonitorElement * > sCurveHistogramHolder
bool doFits(uint32_t detid, std::vector< SiPixelCalibDigi >::const_iterator ipix) override
std::string getTitle() const
get MonitorElement title
MonitorElement * bookDQMHistogram1D(uint32_t detid, std::string name, std::string title, int nchX, double lowX, double highX)
unsigned int idInDetUnit() const
id of this ROC in DetUnit etermined by token path
Definition: PixelROC.h:40
sCurveErrorFlag estimateSCurveParameters(const std::vector< float > &eff, float &threshold, float &sigma)
void setBinError(int binx, double error)
set uncertainty on content of bin (1-D)
double collumn and pixel ID in double collumn representation
Definition: LocalPixel.h:22
sCurveErrorFlag fittedSCurveSanityCheck(float threshold, float sigma, float amplitude)
int toCabling(sipixelobjects::ElectronicIndex &cabling, const sipixelobjects::DetectorIndex &detector) const
const sipixelobjects::PixelROC * findItem(const sipixelobjects::CablingPathToDetUnit &path) const final
int getNbinsY() const
get # of bins in Y-axis
void chi2toMinimize(int &npar, double *grad, double &fcnval, double *xval, int iflag)
double getBinContent(int binx) const
get content of bin (1-D)
col
Definition: cuy.py:1009
static const std::vector< short > * getVcalValues()
Definition: errors.py:1
int getNbinsX() const
get # of bins in X-axis
edm::ESHandle< SiPixelFedCablingMap > theCablingMap_
T const * product() const
Definition: ESHandle.h:86
void buildACurveHistogram(const uint32_t &detid, const uint32_t &row, const uint32_t &col, sCurveErrorFlag errorFlag, const std::vector< float > &efficiencies, const std::vector< float > &errors)