Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:59:37

0001 #include "CalibTracker/SiPixelSCurveCalibration/interface/SiPixelSCurveCalibrationAnalysis.h"
0002 #include "TMath.h"
0003 
0004 #include <fstream>
0005 #include <iostream>
0006 
0007 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0008 #include "CondFormats/SiPixelObjects/interface/DetectorIndex.h"
0009 #include "CondFormats/SiPixelObjects/interface/ElectronicIndex.h"
0010 #include "CondFormats/SiPixelObjects/interface/LocalPixel.h"
0011 #include "CondFormats/SiPixelObjects/interface/SiPixelFrameConverter.h"
0012 #include "DataFormats/SiPixelDigi/interface/SiPixelCalibDigiError.h"
0013 #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
0014 #include <sstream>
0015 
0016 // initialize static members
0017 std::vector<float> SiPixelSCurveCalibrationAnalysis::efficiencies_(0);
0018 std::vector<float> SiPixelSCurveCalibrationAnalysis::effErrors_(0);
0019 
0020 void SiPixelSCurveCalibrationAnalysis::calibrationEnd() {
0021   if (printoutthresholds_)
0022     makeThresholdSummary();
0023 }
0024 
0025 void SiPixelSCurveCalibrationAnalysis::makeThresholdSummary(void) {
0026   std::ofstream myfile;
0027   myfile.open(thresholdfilename_.c_str());
0028   for (detIDHistogramMap::iterator thisDetIdHistoGrams = histograms_.begin(); thisDetIdHistoGrams != histograms_.end();
0029        ++thisDetIdHistoGrams) {
0030     // loop over det id (det id = number (unsigned int) of pixel module
0031     const MonitorElement *sigmahist = (*thisDetIdHistoGrams).second[kSigmas];
0032     const MonitorElement *thresholdhist = (*thisDetIdHistoGrams).second[kThresholds];
0033     uint32_t detid = (*thisDetIdHistoGrams).first;
0034     std::string name = sigmahist->getTitle();
0035     std::string rocname = name.substr(0, name.size() - 7);
0036     rocname += "_ROC";
0037     int total_rows = sigmahist->getNbinsY();
0038     int total_columns = sigmahist->getNbinsX();
0039     // loop over all rows on columns on all ROCs
0040     for (int irow = 0; irow < total_rows; ++irow) {
0041       for (int icol = 0; icol < total_columns; ++icol) {
0042         float threshold_error = sigmahist->getBinContent(icol + 1, irow + 1);  // +1 because root bins start at 1
0043         if (writeZeroes_ || (!writeZeroes_ && threshold_error > 0)) {
0044           // changing from offline to online numbers
0045           int realfedID = -1;
0046           for (int fedid = 0; fedid <= 40; ++fedid) {
0047             SiPixelFrameConverter converter(theCablingMap_.product(), fedid);
0048             if (converter.hasDetUnit(detid)) {
0049               realfedID = fedid;
0050               break;
0051             }
0052           }
0053           if (realfedID == -1) {
0054             std::cout << "error: could not obtain real fed ID" << std::endl;
0055           }
0056           sipixelobjects::DetectorIndex detector = {detid, irow, icol};
0057           sipixelobjects::ElectronicIndex cabling;
0058           SiPixelFrameConverter formatter(theCablingMap_.product(), realfedID);
0059           formatter.toCabling(cabling, detector);
0060           // cabling should now contain cabling.roc and cabling.dcol  and
0061           // cabling.pxid however, the coordinates now need to be converted from
0062           // dcl,pxid to the row,col coordinates used in the calibration info
0063           sipixelobjects::LocalPixel::DcolPxid loc;
0064           loc.dcol = cabling.dcol;
0065           loc.pxid = cabling.pxid;
0066           // FIX to adhere to new cabling map. To be replaced with
0067           // CalibTracker/SiPixelTools detid - > hardware id classes ASAP.
0068           //        const sipixelobjects::PixelFEDCabling *theFed=
0069           //        theCablingMap.product()->fed(realfedID); const
0070           //        sipixelobjects::PixelFEDLink * link =
0071           //        theFed->link(cabling.link); const sipixelobjects::PixelROC
0072           //        *theRoc = link->roc(cabling.roc);
0073           sipixelobjects::LocalPixel locpixel(loc);
0074           sipixelobjects::CablingPathToDetUnit path = {static_cast<unsigned int>(realfedID),
0075                                                        static_cast<unsigned int>(cabling.link),
0076                                                        static_cast<unsigned int>(cabling.roc)};
0077           const sipixelobjects::PixelROC *theRoc = theCablingMap_->findItem(path);
0078           // END of FIX
0079           int newrow = locpixel.rocRow();
0080           int newcol = locpixel.rocCol();
0081           myfile << rocname << theRoc->idInDetUnit() << " " << newcol << " " << newrow << " "
0082                  << thresholdhist->getBinContent(icol + 1, irow + 1) << " "
0083                  << threshold_error;  // +1 because root bins start at 1
0084           myfile << "\n";
0085         }
0086       }
0087     }
0088   }
0089   myfile.close();
0090 }
0091 
0092 // used for TMinuit fitting
0093 void chi2toMinimize(int &npar, double *grad, double &fcnval, double *xval, int iflag) {
0094   TF1 *theFormula = SiPixelSCurveCalibrationAnalysis::fitFunction_;
0095   // setup function parameters
0096   for (int i = 0; i < npar; i++)
0097     theFormula->SetParameter(i, xval[i]);
0098   fcnval = 0;
0099   // compute Chi2 of all points
0100   const std::vector<short> *theVCalValues = SiPixelSCurveCalibrationAnalysis::getVcalValues();
0101   for (uint32_t i = 0; i < theVCalValues->size(); i++) {
0102     float chi = (SiPixelSCurveCalibrationAnalysis::efficiencies_[i] - theFormula->Eval((*theVCalValues)[i]));
0103     chi /= SiPixelSCurveCalibrationAnalysis::effErrors_[i];
0104     fcnval += chi * chi;
0105   }
0106 }
0107 
0108 void SiPixelSCurveCalibrationAnalysis::doSetup(const edm::ParameterSet &iConfig) {
0109   edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Setting up calibration paramters.";
0110   std::vector<uint32_t> anEmptyDefaultVectorOfUInts;
0111   std::vector<uint32_t> detIDsToSaveVector_;
0112   useDetectorHierarchyFolders_ = iConfig.getUntrackedParameter<bool>("useDetectorHierarchyFolders", true);
0113   saveCurvesThatFlaggedBad_ = iConfig.getUntrackedParameter<bool>("saveCurvesThatFlaggedBad", false);
0114   detIDsToSaveVector_ =
0115       iConfig.getUntrackedParameter<std::vector<uint32_t>>("detIDsToSave", anEmptyDefaultVectorOfUInts);
0116   maxCurvesToSave_ = iConfig.getUntrackedParameter<uint32_t>("maxCurvesToSave", 1000);
0117   write2dHistograms_ = iConfig.getUntrackedParameter<bool>("write2dHistograms", true);
0118   write2dFitResult_ = iConfig.getUntrackedParameter<bool>("write2dFitResult", true);
0119   printoutthresholds_ = iConfig.getUntrackedParameter<bool>("writeOutThresholdSummary", true);
0120   thresholdfilename_ = iConfig.getUntrackedParameter<std::string>("thresholdOutputFileName", "thresholds.txt");
0121   minimumChi2prob_ = iConfig.getUntrackedParameter<double>("minimumChi2prob", 0);
0122   minimumThreshold_ = iConfig.getUntrackedParameter<double>("minimumThreshold", -10);
0123   maximumThreshold_ = iConfig.getUntrackedParameter<double>("maximumThreshold", 300);
0124   minimumSigma_ = iConfig.getUntrackedParameter<double>("minimumSigma", 0);
0125   maximumSigma_ = iConfig.getUntrackedParameter<double>("maximumSigma", 100);
0126   minimumEffAsymptote_ = iConfig.getUntrackedParameter<double>("minimumEffAsymptote", 0);
0127   maximumEffAsymptote_ = iConfig.getUntrackedParameter<double>("maximumEffAsymptote", 1000);
0128   maximumSigmaBin_ = iConfig.getUntrackedParameter<double>("maximumSigmaBin", 10);
0129   maximumThresholdBin_ = iConfig.getUntrackedParameter<double>("maximumThresholdBin", 255);
0130 
0131   writeZeroes_ = iConfig.getUntrackedParameter<bool>("alsoWriteZeroThresholds", false);
0132 
0133   // convert the vector into a map for quicker lookups.
0134   for (unsigned int i = 0; i < detIDsToSaveVector_.size(); i++)
0135     detIDsToSave_.insert(std::make_pair(detIDsToSaveVector_[i], true));
0136 }
0137 
0138 SiPixelSCurveCalibrationAnalysis::~SiPixelSCurveCalibrationAnalysis() {
0139   // do nothing
0140 }
0141 
0142 void SiPixelSCurveCalibrationAnalysis::buildACurveHistogram(const uint32_t &detid,
0143                                                             const uint32_t &row,
0144                                                             const uint32_t &col,
0145                                                             sCurveErrorFlag errorFlag,
0146                                                             const std::vector<float> &efficiencies,
0147                                                             const std::vector<float> &errors) {
0148   if (curvesSavedCounter_ > maxCurvesToSave_) {
0149     edm::LogWarning("SiPixelSCurveCalibrationAnalysis")
0150         << "WARNING: Request to save curve for [detid](col/row):  [" << detid << "](" << col << "/" << row
0151         << ") denied. Maximum number of saved curves (defined in .cfi) "
0152            "exceeded.";
0153     return;
0154   }
0155   std::ostringstream rootName;
0156   rootName << "SCurve_row_" << row << "_col_" << col;
0157   std::ostringstream humanName;
0158   humanName << translateDetIdToString(detid) << "_" << rootName.str() << "_ErrorFlag_" << (int)errorFlag;
0159 
0160   unsigned int numberOfVCalPoints = vCalPointsAsFloats_.size() - 1;  // minus one is necessary since the lower
0161                                                                      // edge of the last bin must be added
0162   if (efficiencies.size() != numberOfVCalPoints || errors.size() != numberOfVCalPoints) {
0163     edm::LogError("SiPixelSCurveCalibrationAnalysis")
0164         << "Error saving single curve histogram!  Number of Vcal values (" << numberOfVCalPoints
0165         << ") does not match number of efficiency points or error points!";
0166     return;
0167   }
0168   setDQMDirectory(detid);
0169   float *vcalValuesToPassToCrappyRoot = &vCalPointsAsFloats_[0];
0170   MonitorElement *aBadHisto =
0171       bookDQMHistogram1D(detid,
0172                          rootName.str(),
0173                          humanName.str(),
0174                          numberOfVCalPoints,
0175                          vcalValuesToPassToCrappyRoot);  // ROOT only takes an input as array. :(
0176                                                          // HOORAY FOR CINT!
0177   curvesSavedCounter_++;
0178   for (unsigned int iBin = 0; iBin < numberOfVCalPoints; ++iBin) {
0179     int rootBin = iBin + 1;  // root bins start at 1
0180     aBadHisto->setBinContent(rootBin, efficiencies[iBin]);
0181     aBadHisto->setBinError(rootBin, errors[iBin]);
0182   }
0183 }
0184 
0185 void SiPixelSCurveCalibrationAnalysis::calibrationSetup(const edm::EventSetup &iSetup) {
0186   edm::LogInfo("SiPixelSCurveCalibrationAnalysis")
0187       << "Calibration Settings: VCalLow: " << vCalValues_[0] << "  VCalHigh: " << vCalValues_[vCalValues_.size() - 1]
0188       << " nVCal: " << vCalValues_.size() << "  nTriggers: " << nTriggers_;
0189   curvesSavedCounter_ = 0;
0190   if (saveCurvesThatFlaggedBad_) {
0191     // build the vCal values as a vector of floats if we want to save single
0192     // curves
0193     const std::vector<short> *theVCalValues = this->getVcalValues();
0194     unsigned int numberOfVCalPoints = theVCalValues->size();
0195     edm::LogWarning("SiPixelSCurveCalibrationAnalysis")
0196         << "WARNING: Option set to save indiviual S-Curves - max number: " << maxCurvesToSave_
0197         << " This can lead to large memory consumption! (Got " << numberOfVCalPoints << " VCal Points";
0198     for (unsigned int i = 0; i < numberOfVCalPoints; i++) {
0199       vCalPointsAsFloats_.push_back(static_cast<float>((*theVCalValues)[i]));
0200       edm::LogInfo("SiPixelSCurveCalibrationAnalysis") << "Adding calibration Vcal: " << (*theVCalValues)[i];
0201     }
0202     // must add lower edge of last bin to the vector
0203     vCalPointsAsFloats_.push_back(vCalPointsAsFloats_[numberOfVCalPoints - 1] + 1);
0204   }
0205 
0206   fitFunction_ = new TF1("sCurve",
0207                          "0.5*[2]*(1+TMath::Erf( (x-[0]) / ([1]*sqrt(2)) ) )",
0208                          vCalValues_[0],
0209                          vCalValues_[vCalValues_.size() - 1]);
0210 }
0211 
0212 bool SiPixelSCurveCalibrationAnalysis::checkCorrectCalibrationType() {
0213   if (calibrationMode_ == "SCurve")
0214     return true;
0215   else if (calibrationMode_ == "unknown") {
0216     edm::LogInfo("SiPixelSCurveCalibrationAnalysis")
0217         << "calibration mode is: " << calibrationMode_ << ", continuing anyway...";
0218     return true;
0219   } else {
0220     //    edm::LogDebug("SiPixelSCurveCalibrationAnalysis") << "unknown
0221     //    calibration mode for SCurves, should be \"SCurve\" and is \"" <<
0222     //    calibrationMode_ << "\"";
0223   }
0224   return false;
0225 }
0226 
0227 sCurveErrorFlag SiPixelSCurveCalibrationAnalysis::estimateSCurveParameters(const std::vector<float> &eff,
0228                                                                            float &threshold,
0229                                                                            float &sigma) {
0230   sCurveErrorFlag output = errAllZeros;
0231   bool allZeroSoFar = true;
0232   int turnOnBin = -1;
0233   int saturationBin = -1;
0234   for (uint32_t iVcalPt = 0; iVcalPt < eff.size(); iVcalPt++) {
0235     if (allZeroSoFar && eff[iVcalPt] != 0) {
0236       turnOnBin = iVcalPt;
0237       allZeroSoFar = false;
0238       output = errNoTurnOn;
0239     } else if (eff[iVcalPt] > 0.90) {
0240       saturationBin = iVcalPt;
0241       short turnOnVcal = vCalValues_[turnOnBin];
0242       short saturationVcal = vCalValues_[saturationBin];
0243       short delta = saturationVcal - turnOnVcal;
0244       sigma = delta * 0.682;
0245       if (sigma < 1)  // check to make sure sigma guess is larger than our X resolution.
0246                       // Hopefully prevents Minuit from getting stuck at boundary
0247         sigma = 1;
0248       threshold = turnOnVcal + (0.5 * delta);
0249       return errOK;
0250     }
0251   }
0252   return output;
0253 }
0254 
0255 sCurveErrorFlag SiPixelSCurveCalibrationAnalysis::fittedSCurveSanityCheck(float threshold,
0256                                                                           float sigma,
0257                                                                           float amplitude) {
0258   // check if nonsensical
0259   if (threshold > vCalValues_[vCalValues_.size() - 1] || threshold < vCalValues_[0] ||
0260       sigma > vCalValues_[vCalValues_.size() - 1] - vCalValues_[0])
0261     return errFitNonPhysical;
0262 
0263   if (threshold < minimumThreshold_ || threshold > maximumThreshold_ || sigma < minimumSigma_ ||
0264       sigma > maximumSigma_ || amplitude < minimumEffAsymptote_ || amplitude > maximumEffAsymptote_)
0265     return errFlaggedBadByUser;
0266 
0267   return errOK;
0268 }
0269 
0270 void calculateEffAndError(int nADCResponse, int nTriggers, float &eff, float &error) {
0271   eff = (float)nADCResponse / (float)nTriggers;
0272   double effForErrorCalculation = eff;
0273   if (eff <= 0 || eff >= 1)
0274     effForErrorCalculation = 0.5 / (double)nTriggers;
0275   error = TMath::Sqrt(effForErrorCalculation * (1 - effForErrorCalculation) / (double)nTriggers);
0276 }
0277 
0278 // book histograms when new DetID is encountered in Event Record
0279 void SiPixelSCurveCalibrationAnalysis::newDetID(uint32_t detid) {
0280   edm::LogInfo("SiPixelSCurveCalibrationAnalysis")
0281       << "Found a new DetID (" << detid << ")!  Checking to make sure it has not been added.";
0282   // ensure that this DetID has not been added yet
0283   sCurveHistogramHolder tempMap;
0284   std::pair<detIDHistogramMap::iterator, bool> insertResult;
0285   insertResult = histograms_.insert(std::make_pair(detid, tempMap));
0286   if (insertResult.second)  // indicates successful insertion
0287   {
0288     edm::LogInfo("SiPixelSCurveCalibrationAnalysisHistogramReport")
0289         << "Histogram Map.insert() returned true!  Booking new histogrames for "
0290            "detID: "
0291         << detid;
0292     // use detector hierarchy folders if desired
0293     if (useDetectorHierarchyFolders_)
0294       setDQMDirectory(detid);
0295 
0296     std::string detIdName = translateDetIdToString(detid);
0297     if (write2dHistograms_) {
0298       MonitorElement *D2sigma = bookDQMHistoPlaquetteSummary2D(detid, "ScurveSigmas", detIdName + " Sigmas");
0299       MonitorElement *D2thresh = bookDQMHistoPlaquetteSummary2D(detid, "ScurveThresholds", detIdName + " Thresholds");
0300       MonitorElement *D2chi2 = bookDQMHistoPlaquetteSummary2D(detid, "ScurveChi2Prob", detIdName + " Chi2Prob");
0301       insertResult.first->second.insert(std::make_pair(kSigmas, D2sigma));
0302       insertResult.first->second.insert(std::make_pair(kThresholds, D2thresh));
0303       insertResult.first->second.insert(std::make_pair(kChi2s, D2chi2));
0304     }
0305     if (write2dFitResult_) {
0306       MonitorElement *D2FitResult = bookDQMHistoPlaquetteSummary2D(detid, "ScurveFitResult", detIdName + " Fit Result");
0307       insertResult.first->second.insert(std::make_pair(kFitResults, D2FitResult));
0308     }
0309     MonitorElement *D1sigma =
0310         bookDQMHistogram1D(detid, "ScurveSigmasSummary", detIdName + " Sigmas Summary", 100, 0, maximumSigmaBin_);
0311     MonitorElement *D1thresh = bookDQMHistogram1D(
0312         detid, "ScurveThresholdSummary", detIdName + " Thresholds Summary", 255, 0, maximumThresholdBin_);
0313     MonitorElement *D1chi2 =
0314         bookDQMHistogram1D(detid, "ScurveChi2ProbSummary", detIdName + " Chi2Prob Summary", 101, 0, 1.01);
0315     MonitorElement *D1FitResult =
0316         bookDQMHistogram1D(detid, "ScurveFitResultSummary", detIdName + " Fit Result Summary", 10, -0.5, 9.5);
0317     insertResult.first->second.insert(std::make_pair(kSigmaSummary, D1sigma));
0318     insertResult.first->second.insert(std::make_pair(kThresholdSummary, D1thresh));
0319     insertResult.first->second.insert(std::make_pair(kChi2Summary, D1chi2));
0320     insertResult.first->second.insert(std::make_pair(kFitResultSummary, D1FitResult));
0321   }
0322 }
0323 
0324 bool SiPixelSCurveCalibrationAnalysis::doFits(uint32_t detid, std::vector<SiPixelCalibDigi>::const_iterator calibDigi) {
0325   sCurveErrorFlag errorFlag = errOK;
0326   uint32_t nVCalPts = calibDigi->getnpoints();
0327   // reset and fill static datamembers with vector of points and errors
0328   efficiencies_.resize(0);
0329   effErrors_.resize(0);
0330   for (uint32_t iVcalPt = 0; iVcalPt < nVCalPts; iVcalPt++) {
0331     float eff;
0332     float error;
0333     calculateEffAndError(calibDigi->getnentries(iVcalPt), nTriggers_, eff, error);
0334     edm::LogInfo("SiPixelSCurveCalibrationAnalysis")
0335         << "Eff: " << eff << " Error:  " << error << "  nEntries: " << calibDigi->getnentries(iVcalPt)
0336         << "  nTriggers: " << nTriggers_ << " VCalPt " << vCalValues_[iVcalPt];
0337     efficiencies_.push_back(eff);
0338     effErrors_.push_back(error);
0339   }
0340 
0341   // estimate the S-Curve parameters
0342   float thresholdGuess = -1.0;
0343   float sigmaGuess = -1.0;
0344   errorFlag = estimateSCurveParameters(efficiencies_, thresholdGuess, sigmaGuess);
0345 
0346   // these -1.0 default values will only be filled if the curve is all zeroes,
0347   // or doesn't turn on, WHICH INDICATES A SERIOUS PROBLEM
0348   Double_t sigma = -1.0;
0349   Double_t sigmaError = -1.0;
0350   Double_t threshold = -1.0;
0351   Double_t thresholdError = -1.0;
0352   Double_t amplitude = -1.0;
0353   Double_t amplitudeError = -1.0;
0354   Double_t chi2 = -1.0;
0355   // calculate NDF
0356   Int_t nDOF = vCalValues_.size() - 3;
0357   Double_t chi2probability = 0;
0358 
0359   if (errorFlag == errOK)  // only do fit if curve is fittable
0360   {
0361     // set up minuit fit
0362     TMinuit *gMinuit = new TMinuit(3);
0363     gMinuit->SetPrintLevel(-1);  // save ourselves from gigabytes of stdout
0364     gMinuit->SetFCN(chi2toMinimize);
0365 
0366     // define threshold parameters - choose step size 1, max 300, min -50
0367     gMinuit->DefineParameter(0, "Threshold", (Double_t)thresholdGuess, 1, -50, 300);
0368     // sigma
0369     gMinuit->DefineParameter(1, "Sigma", (Double_t)sigmaGuess, 0.1, 0, 255);
0370     // amplitude
0371     gMinuit->DefineParameter(2, "Amplitude", 1, 0.1, -0.001, 200);
0372 
0373     // Do Chi2 minimazation
0374     gMinuit->Migrad();
0375     gMinuit->GetParameter(0, threshold, thresholdError);
0376     gMinuit->GetParameter(1, sigma, sigmaError);
0377     gMinuit->GetParameter(2, amplitude, amplitudeError);
0378 
0379     // get Chi2
0380     Double_t params[3] = {threshold, sigma, amplitude};
0381     gMinuit->Eval(3, nullptr, chi2, params, 0);
0382     // calculate Chi2 proability
0383     if (nDOF <= 0)
0384       chi2probability = 0;
0385     else
0386       chi2probability = TMath::Prob(chi2, nDOF);
0387 
0388     // check to make sure output makes sense (i.e. threshold > 0)
0389     if (chi2probability > minimumChi2prob_)
0390       errorFlag = fittedSCurveSanityCheck(threshold, sigma, amplitude);
0391     else
0392       errorFlag = errBadChi2Prob;
0393 
0394     edm::LogInfo("SiPixelSCurveCalibrationAnalysis")
0395         << "Fit finished with errorFlag: " << errorFlag << " - threshold: " << threshold << "  sigma: " << sigma
0396         << "  chi2: " << chi2 << "  nDOF: " << nDOF << " chi2Prob: " << chi2probability
0397         << " chi2MinUser: " << minimumChi2prob_;
0398 
0399     delete gMinuit;
0400   }
0401   // get row and column for this pixel
0402   uint32_t row = calibDigi->row();
0403   uint32_t col = calibDigi->col();
0404 
0405   // get iterator to histogram holder for this detid
0406   detIDHistogramMap::iterator thisDetIdHistoGrams;
0407   thisDetIdHistoGrams = histograms_.find(detid);
0408   if (thisDetIdHistoGrams != histograms_.end()) {
0409     edm::LogInfo("SiPixelSCurveCalibrationAnalysisHistogramReport")
0410         << "Filling histograms for [detid](col/row):  [" << detid << "](" << col << "/" << row
0411         << ") ErrorFlag: " << errorFlag;
0412     // always fill fit result
0413     (*thisDetIdHistoGrams).second[kFitResultSummary]->Fill(errorFlag);
0414     if (write2dFitResult_)
0415       (*thisDetIdHistoGrams)
0416           .second[kFitResults]
0417           ->setBinContent(col + 1,
0418                           row + 1,
0419                           errorFlag);  // +1 because root bins start at 1
0420 
0421     // fill sigma/threshold result
0422     (*thisDetIdHistoGrams).second[kSigmaSummary]->Fill(sigma);
0423     (*thisDetIdHistoGrams).second[kThresholdSummary]->Fill(threshold);
0424     if (write2dHistograms_) {
0425       (*thisDetIdHistoGrams)
0426           .second[kSigmas]
0427           ->setBinContent(col + 1,
0428                           row + 1,
0429                           sigma);  // +1 because root bins start at 1
0430       (*thisDetIdHistoGrams)
0431           .second[kThresholds]
0432           ->setBinContent(col + 1,
0433                           row + 1,
0434                           threshold);  // +1 because root bins start at 1
0435     }
0436     // fill chi2
0437     (*thisDetIdHistoGrams).second[kChi2Summary]->Fill(chi2probability);
0438     if (write2dHistograms_)
0439       (*thisDetIdHistoGrams).second[kChi2s]->Fill(col, row, chi2probability);
0440   }
0441   // save individual curves, if requested
0442   if (saveCurvesThatFlaggedBad_) {
0443     bool thisDetIDinList = false;
0444     if (detIDsToSave_.find(detid) != detIDsToSave_.end())  // see if we want to save this histogram
0445       thisDetIDinList = true;
0446 
0447     if (errorFlag != errOK || thisDetIDinList) {
0448       edm::LogError("SiPixelSCurveCalibrationAnalysis") << "Saving error histogram for [detid](col/row):  [" << detid
0449                                                         << "](" << col << "/" << row << ") ErrorFlag: " << errorFlag;
0450       buildACurveHistogram(detid, row, col, errorFlag, efficiencies_, effErrors_);
0451     }
0452   }
0453 
0454   return true;
0455 }