CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/DQM/HcalMonitorTasks/src/HcalNoiseMonitor.cc

Go to the documentation of this file.
00001 #include <cmath>
00002 #include <fstream>
00003 #include <algorithm>
00004 
00005 #include "DQM/HcalMonitorTasks/interface/HcalNoiseMonitor.h"
00006 
00007 #include "DataFormats/FEDRawData/interface/FEDNumbering.h"
00008 #include "DataFormats/FEDRawData/interface/FEDTrailer.h"
00009 #include "DataFormats/FEDRawData/interface/FEDHeader.h"
00010 #include "EventFilter/HcalRawToDigi/interface/HcalDCCHeader.h"
00011 
00012 #include "DataFormats/HcalDetId/interface/HcalDetId.h"
00013 #include "DataFormats/HcalRecHit/interface/HcalRecHitCollections.h"
00014 #include "DataFormats/HcalRecHit/interface/HBHERecHit.h"
00015 #include "DataFormats/HcalDigi/interface/HcalDigiCollections.h"
00016 
00017 #include "CalibFormats/HcalObjects/interface/HcalCoderDb.h"
00018 #include "CalibFormats/HcalObjects/interface/HcalCalibrations.h"
00019 #include "CalibFormats/HcalObjects/interface/HcalDbService.h"
00020 #include "CalibFormats/HcalObjects/interface/HcalDbRecord.h"
00021 
00022 #include "RecoMET/METAlgorithms/interface/HcalNoiseRBXArray.h"
00023 #include "CalibCalorimetry/HcalAlgos/interface/HcalPulseShapes.h"
00024 #include "RecoLocalCalo/HcalRecAlgos/interface/HcalCaloFlagLabels.h"
00025 
00026 #include "FWCore/Common/interface/TriggerNames.h"
00027 
00028 HcalNoiseMonitor::HcalNoiseMonitor(const edm::ParameterSet& ps)
00029 {
00030    Online_                = ps.getUntrackedParameter<bool>("online",false);
00031    mergeRuns_             = ps.getUntrackedParameter<bool>("mergeRuns",false);
00032    enableCleanup_         = ps.getUntrackedParameter<bool>("enableCleanup",false);
00033    debug_                 = ps.getUntrackedParameter<int>("debug",0);
00034    prefixME_              = ps.getUntrackedParameter<std::string>("subSystemFolder","Hcal/");
00035    if(prefixME_.substr(prefixME_.size()-1,prefixME_.size())!="/")
00036       prefixME_.append("/");
00037    subdir_                = ps.getUntrackedParameter<std::string>("TaskFolder","NoiseMonitor_Hcal");
00038    if(subdir_.size()>0 && subdir_.substr(subdir_.size()-1,subdir_.size())!="/")
00039       subdir_.append("/");
00040    subdir_=prefixME_+subdir_;
00041    AllowedCalibTypes_     = ps.getUntrackedParameter<std::vector<int> > ("AllowedCalibTypes");
00042    skipOutOfOrderLS_      = ps.getUntrackedParameter<bool>("skipOutOfOrderLS",false);
00043    NLumiBlocks_           = ps.getUntrackedParameter<int>("NLumiBlocks",4000);
00044    makeDiagnostics_       = ps.getUntrackedParameter<bool>("makeDiagnostics",false);
00045 
00046    triggers_=ps.getUntrackedParameter<std::vector<std::string> >("nzsHLTnames");
00047       //["HLT_HcalPhiSym","HLT_HcalNoise_8E29]
00048    period_=ps.getUntrackedParameter<int>("NoiseeventPeriod",4096); //4096
00049    rawdataLabel_          = ps.getUntrackedParameter<edm::InputTag>("RawDataLabel");
00050    hltresultsLabel_       = ps.getUntrackedParameter<edm::InputTag>("HLTResultsLabel");
00051    hbheDigiLabel_         = ps.getUntrackedParameter<edm::InputTag>("hbheDigiLabel");
00052    hbheRechitLabel_       = ps.getUntrackedParameter<edm::InputTag>("hbheRechitLabel");
00053    noiseLabel_            = ps.getUntrackedParameter<edm::InputTag>("noiseLabel");
00054 
00055    mTrianglePeakTS        = 4;   // for now...
00056 
00057    mE2E10MinEnergy        = ps.getUntrackedParameter<double>("E2E10MinEnergy");
00058    mMinE2E10              = ps.getUntrackedParameter<double>("MinE2E10");
00059    mMaxE2E10              = ps.getUntrackedParameter<double>("MaxE2E10");
00060    mMaxHPDHitCount        = ps.getUntrackedParameter<int>("MaxHPDHitCount");
00061    mMaxHPDNoOtherHitCount = ps.getUntrackedParameter<int>("MaxHPDNoOtherHitCount");
00062    mMaxADCZeros           = ps.getUntrackedParameter<int>("MaxADCZeros");
00063    mTotalZeroMinEnergy    = ps.getUntrackedParameter<double>("TotalZeroMinEnergy");
00064    setupDone_ = false;
00065 }
00066 
00067 HcalNoiseMonitor::~HcalNoiseMonitor() {}
00068 
00069 void HcalNoiseMonitor::reset()
00070 {
00071 }
00072 
00073 void HcalNoiseMonitor::cleanup()
00074 {
00075    if(dbe_)
00076    {
00077       dbe_->setCurrentFolder(subdir_);
00078       dbe_->removeContents();
00079    }
00080 }
00081 
00082 void HcalNoiseMonitor::beginRun(const edm::Run& run, const edm::EventSetup& c)
00083 {
00084    if(debug_ > 1)
00085       std::cout <<"HcalNoiseMonitor::beginRun"<< std::endl;
00086 
00087    HcalBaseDQMonitor::beginRun(run,c);
00088 
00089    if(tevt_ == 0)
00090       setup();
00091 
00092    if(mergeRuns_ == false)
00093       reset();
00094 
00095    return;
00096 }
00097 
00098 
00099 void HcalNoiseMonitor::setup()
00100 {
00101    if (setupDone_)
00102      return;
00103    setupDone_ = true;
00104    HcalBaseDQMonitor::setup();
00105 
00106    if(debug_ > 1)
00107       std::cout << "<HcalNoiseMonitor::setup> Creating histograms" << std::endl;
00108 
00109    if(dbe_)
00110    {
00111       dbe_->setCurrentFolder(subdir_);
00112 
00113       // Fit-based
00114       dbe_->setCurrentFolder(subdir_ + "DoubleChi2/");
00115 
00116       hNominalChi2 = dbe_->book1D("Nominal_fit_chi2", "Nominal fit chi2, total charge > 20 fC", 100, 0, 200);
00117       hNominalChi2->setAxisTitle("Nominal fit #chi^{2}", 1);
00118 
00119       hLinearChi2 = dbe_->book1D("Linear_fit_chi2", "Linear fit chi2, total charge > 20 fC", 100, 0, 200);
00120       hLinearChi2->setAxisTitle("Linear fit #chi^{2}", 1);
00121       
00122       hLinearTestStatistics = dbe_->book1D("Lambda_linear", "#Lambda_{linear}, total charge > 20 fC", 100, -10, 10);
00123       hLinearTestStatistics->setAxisTitle("#Lambda_{linear}", 1);
00124 
00125       hRMS8OverMax = dbe_->book1D("RMS8_over_Max", "RMS8/max, total charge > 20 fC", 100, 0, 2);
00126       hRMS8OverMax->setAxisTitle("RMS8/max", 1);
00127 
00128       hRMS8OverMaxTestStatistics = dbe_->book1D("Lambda_RMS8_over_max", "#Lambda_{RMS8/Max}, total charge > 20 fC",
00129          100, -30, 10);
00130       hRMS8OverMaxTestStatistics->setAxisTitle("#Lambda_{RMS8/Max}", 1);
00131 
00132       hLambdaLinearVsTotalCharge = dbe_->book2D("Lambda_linear_vs_total_charge", "#Lambda_{Linear}",
00133          50, -5, 5, 25, 0, 500);
00134       hLambdaLinearVsTotalCharge->setAxisTitle("#Lambda_{linear}", 1);
00135       hLambdaLinearVsTotalCharge->setAxisTitle("Total charge", 2);
00136 
00137       hLambdaRMS8MaxVsTotalCharge = dbe_->book2D("Lambda_RMS8Max_vs_total_charge", "#Lambda_{RMS8/Max}",
00138          50, -15, 5, 25, 0, 500);
00139       hLambdaRMS8MaxVsTotalCharge->setAxisTitle("#Lambda_{RMS8/Max}", 1);
00140       hLambdaRMS8MaxVsTotalCharge->setAxisTitle("Total charge", 2);
00141 
00142       hTriangleLeftSlopeVsTS4 = dbe_->book2D("Triangle_fit_left_slope",
00143          "Triangle fit left distance vs. TS4", 50, 0, 10, 25, 0, 500);
00144       hTriangleLeftSlopeVsTS4->setAxisTitle("Left slope", 1);
00145       hTriangleLeftSlopeVsTS4->setAxisTitle("Peak time slice", 2);
00146 
00147       hTriangleRightSlopeVsTS4 = dbe_->book2D("Triangle_fit_right_slope",
00148          "Triangle fit right distance vs. peak time slice", 50, 0, 10, 25, 0, 500);
00149       hTriangleRightSlopeVsTS4->setAxisTitle("Left slope", 1);
00150       hTriangleRightSlopeVsTS4->setAxisTitle("Peak time slice", 2);
00151 
00152       SetupEtaPhiHists(hFailLinearEtaPhi, "Fail_linear_Eta_Phi_Map", "");
00153       SetupEtaPhiHists(hFailRMSMaxEtaPhi, "Fail_RMS8Max_Eta_Phi_Map", "");
00154       SetupEtaPhiHists(hFailTriangleEtaPhi, "Fail_triangle_Eta_Phi_Map", "");
00155 
00156       // High-level isolation filter
00157       dbe_->setCurrentFolder(subdir_ + "IsolationVariable/");
00158 
00159       SetupEtaPhiHists(hFailIsolationEtaPhi, "Fail_isolation_Eta_Phi_Map", "");
00160       
00161       // TS4 vs. TS5 variable
00162       dbe_->setCurrentFolder(subdir_ + "TS4TS5Variable/");
00163       
00164       hTS4TS5RelativeDifference = dbe_->book1D("TS4_TS5_relative_difference",
00165          "(TS4-TS5)/(TS4+TS5), total charge > 20 fC", 100, -1, 1);
00166       hTS4TS5RelativeDifference->setAxisTitle("(TS4 - TS5) / (TS4 + TS5)", 1);
00167 
00168       hTS4TS5RelativeDifferenceVsCharge = dbe_->book2D("TS4_TS5_relative_difference_charge",
00169          "(TS4-TS5)/(TS4+TS5) vs. Charge", 25, 0, 400, 75, -1, 1);
00170       hTS4TS5RelativeDifferenceVsCharge->setAxisTitle("Charge", 1);
00171       hTS4TS5RelativeDifferenceVsCharge->setAxisTitle("(TS4 - TS5) / (TS4 + TS5)", 2);
00172 
00173       // Noise summary object
00174       dbe_->setCurrentFolder(subdir_ + "NoiseMonitoring/");
00175    
00176       hMaxZeros = dbe_->book1D("Max_Zeros", "Max zeros", 15, -0.5, 14.5);
00177       
00178       hTotalZeros = dbe_->book1D("Total_Zeros", "Total zeros", 15, -0.5, 14.5);
00179       
00180       hE2OverE10Digi = dbe_->book1D("E2OverE10Digi", "E2/E10 of the highest digi in an HPD", 100, 0, 2);
00181       
00182       hE2OverE10Digi5 = dbe_->book1D("E2OverE10Digi5", "E2/E10 of the highest 5 digi in an HPD", 100, 0, 2);
00183       
00184       hE2OverE10RBX = dbe_->book1D("E2OverE10RBX", "E2/E10 of RBX", 100, 0, 2);
00185       
00186       hHPDHitCount = dbe_->book1D("HPDHitCount", "HPD hit count (1.5 GeV)", 19, -0.5, 18.5);
00187       
00188       hRBXHitCount = dbe_->book1D("RBXHitCount", "Number of hits in RBX", 74, -0.5, 73.5);
00189 
00190       hHcalNoiseCategory = dbe_->book1D("Hcal_noise_category", "Hcal noise category", 10, 0.5, 10.5);
00191       hHcalNoiseCategory->setBinLabel(1, "RBX noise", 1);
00192       hHcalNoiseCategory->setBinLabel(2, "RBX pedestal flatter", 1);
00193       hHcalNoiseCategory->setBinLabel(3, "RBX pedestal sharper", 1);
00194       hHcalNoiseCategory->setBinLabel(4, "RBX flash large hit count", 1);
00195       hHcalNoiseCategory->setBinLabel(5, "RBX flash small hit count", 1);
00196       hHcalNoiseCategory->setBinLabel(7, "HPD discharge", 1);
00197       hHcalNoiseCategory->setBinLabel(8, "HPD ion feedback", 1);
00198 
00199       hBadZeroRBX = dbe_->book1D("BadZeroRBX", "RBX with bad ADC zero counts", 72, 0.5, 72.5);
00200       hBadCountHPD = dbe_->book1D("BadCountHPD", "HPD with bad hit counts", 72 * 4, 0.5, 72 * 4 + 0.5);
00201       hBadNoOtherCountHPD = dbe_->book1D("BadNoOtherCountHPD", "HPD with bad \"no other\" hit counts", 72 * 4, 0.5, 72 * 4 + 0.5);
00202       hBadE2E10RBX = dbe_->book1D("BadE2E10RBX", "RBX with bad E2/E10 value", 72, 0.5, 72.5);
00203    }
00204 
00205    ReadHcalPulse();
00206 
00207    return;
00208 }
00209 
00210 
00211 void HcalNoiseMonitor::analyze(edm::Event const &iEvent, edm::EventSetup const &iSetup)
00212 {
00213    edm::Handle<HBHEDigiCollection> hHBHEDigis;
00214    iEvent.getByLabel(edm::InputTag(hbheDigiLabel_),hHBHEDigis);
00215 
00216    edm::ESHandle<HcalDbService> hConditions;
00217    iSetup.get<HcalDbRecord>().get(hConditions);
00218 
00219    edm::Handle<HBHERecHitCollection> hRecHits;
00220    iEvent.getByLabel(edm::InputTag(hbheRechitLabel_), hRecHits);
00221 
00222    edm::Handle<reco::HcalNoiseRBXCollection> hRBXCollection;
00223    iEvent.getByLabel(edm::InputTag(noiseLabel_),hRBXCollection);
00224 
00225    HcalBaseDQMonitor::analyze(iEvent, iSetup);
00226 
00227    if(dbe_ == NULL)
00228    {
00229       if(debug_ > 0)
00230          std::cout << "HcalNoiseMonitor::processEvent DQMStore not instantiated!!!"<< std::endl;
00231       return;
00232    }
00233 
00234    // loop over digis
00235    for(HBHEDigiCollection::const_iterator iter = hHBHEDigis->begin(); iter != hHBHEDigis->end(); iter++)
00236    {
00237       HcalDetId id = iter->id();
00238       const HcalCalibrations &Calibrations = hConditions->getHcalCalibrations(id);
00239       const HcalQIECoder *ChannelCoder = hConditions->getHcalCoder(id);
00240       const HcalQIEShape *Shape = hConditions->getHcalShape(ChannelCoder);
00241       HcalCoderDb Coder(*ChannelCoder, *Shape);
00242       CaloSamples Tool;
00243       Coder.adc2fC(*iter, Tool);
00244 
00245       // int ieta = id.ieta();
00246       // int iphi = id.iphi();
00247       // int depth = id.depth();
00248 
00249       double Charge[10] = {0};
00250       for(int i = 0; i < iter->size(); i++)
00251          Charge[i] = Tool[i] - Calibrations.pedestal(iter->sample(i).capid());
00252 
00253       double TotalCharge = 0;
00254       for(int i = 0; i < 10; i++)
00255          TotalCharge = TotalCharge + Charge[i];
00256 
00257       if(TotalCharge > 20)
00258       {
00259          double NominalChi2 = 10000000;
00260          NominalChi2 = PerformNominalFit(Charge);
00261          
00262          double LinearChi2 = PerformLinearFit(Charge);
00263          double RMS8Max = CalculateRMS8Max(Charge);
00264          TriangleFitResult TriangleResult = PerformTriangleFit(Charge);
00265       
00266          double TS4LeftSlope = 100000;
00267          double TS4RightSlope = 100000;
00268          
00269          if(TriangleResult.LeftSlope > 1e-5)
00270             TS4LeftSlope = Charge[4] / fabs(TriangleResult.LeftSlope);
00271          if(TriangleResult.RightSlope < -1e-5)
00272             TS4RightSlope = Charge[4] / fabs(TriangleResult.RightSlope);
00273 
00274          if(TS4LeftSlope < -1000 || TS4LeftSlope > 1000)
00275             TS4LeftSlope = 1000;
00276          if(TS4RightSlope < -1000 || TS4RightSlope > 1000)
00277             TS4RightSlope = 1000;
00278 
00279          hNominalChi2->Fill(NominalChi2);
00280          hLinearChi2->Fill(LinearChi2);
00281          hLinearTestStatistics->Fill(log(LinearChi2) - log(NominalChi2));
00282          hRMS8OverMax->Fill(RMS8Max);
00283          hRMS8OverMaxTestStatistics->Fill(log(RMS8Max) - log(NominalChi2));
00284 
00285          hLambdaLinearVsTotalCharge->Fill(log(LinearChi2) - log(NominalChi2), TotalCharge);
00286          hLambdaRMS8MaxVsTotalCharge->Fill(log(RMS8Max) - log(NominalChi2), TotalCharge);
00287          hTriangleLeftSlopeVsTS4->Fill(TS4LeftSlope, Charge[4]);
00288          hTriangleRightSlopeVsTS4->Fill(TS4RightSlope, Charge[4]);
00289       }
00290 
00291       if(Charge[4] + Charge[5] > 1e-5)
00292       {
00293          hTS4TS5RelativeDifference->Fill((Charge[4] - Charge[5]) / (Charge[4] + Charge[5]));
00294          hTS4TS5RelativeDifferenceVsCharge->Fill(TotalCharge, (Charge[4] - Charge[5]) / (Charge[4] + Charge[5]));
00295       }
00296    }
00297 
00298    // loop over rechits - noise bits (fit-based, isolation)
00299    for(HBHERecHitCollection::const_iterator iter = hRecHits->begin(); iter != hRecHits->end(); iter++)
00300    {
00301       HcalDetId id = iter->id();
00302 
00303       int ieta = id.ieta();
00304       int iphi = id.iphi();
00305       int depth = id.depth();
00306 
00307       if(iter->flagField(HcalCaloFlagLabels::HBHEFlatNoise) == 1)
00308          hFailLinearEtaPhi.depth[depth-1]->Fill(ieta, iphi);
00309 
00310       if(iter->flagField(HcalCaloFlagLabels::HBHESpikeNoise) == 1)
00311          hFailRMSMaxEtaPhi.depth[depth-1]->Fill(ieta, iphi);
00312       
00313       if(iter->flagField(HcalCaloFlagLabels::HBHETriangleNoise) == 1)
00314          hFailTriangleEtaPhi.depth[depth-1]->Fill(ieta, iphi);
00315 
00316       if(iter->flagField(HcalCaloFlagLabels::HBHEIsolatedNoise) == 1)
00317          hFailIsolationEtaPhi.depth[depth-1]->Fill(ieta, iphi);
00318    }
00319 
00320    // Code analagous to Yifei's
00321    for(reco::HcalNoiseRBXCollection::const_iterator rbx = hRBXCollection->begin();
00322       rbx != hRBXCollection->end(); rbx++)
00323    {
00324       const reco::HcalNoiseRBX RBX = *rbx;
00325 
00326       int NumberRBXHits = RBX.numRecHits(1.5);
00327       double RBXEnergy = RBX.recHitEnergy(1.5);
00328       double RBXE2 = RBX.allChargeHighest2TS();
00329       double RBXE10 = RBX.allChargeTotal();
00330 
00331       std::vector<reco::HcalNoiseHPD> HPDs = RBX.HPDs();
00332       
00333       int RBXID = RBX.idnumber();
00334 
00335       if(RBXEnergy > mTotalZeroMinEnergy && RBX.totalZeros() >= mMaxADCZeros)
00336          hBadZeroRBX->Fill(RBXID);
00337       if(RBXEnergy > mE2E10MinEnergy && RBXE10 > 1e-5 && (RBXE2 / RBXE10 > mMaxE2E10 || RBXE2 / RBXE10 < mMinE2E10))
00338          hBadE2E10RBX->Fill(RBXID);
00339       for(std::vector<reco::HcalNoiseHPD>::const_iterator hpd = HPDs.begin(); hpd != HPDs.end(); hpd++)
00340       {
00341          reco::HcalNoiseHPD HPD = *hpd;
00342          int HPDHitCount = HPD.numRecHits(1.5);
00343          if(HPDHitCount >= mMaxHPDHitCount)
00344             hBadCountHPD->Fill(HPD.idnumber());
00345          if(HPDHitCount == NumberRBXHits && HPDHitCount >= mMaxHPDNoOtherHitCount)
00346             hBadNoOtherCountHPD->Fill(HPD.idnumber());
00347       }
00348       
00349       if(NumberRBXHits == 0 || RBXEnergy <= 10)
00350          continue;
00351 
00352       hRBXHitCount->Fill(NumberRBXHits);
00353 
00354       hMaxZeros->Fill(RBX.maxZeros());
00355       hTotalZeros->Fill(RBX.totalZeros());
00356    
00357       double HighestHPDEnergy = 0;
00358       int HighestHPDHits = 0;
00359 
00360       for(std::vector<reco::HcalNoiseHPD>::const_iterator hpd = HPDs.begin(); hpd != HPDs.end(); hpd++)
00361       {
00362          reco::HcalNoiseHPD HPD = *hpd;
00363 
00364          if(HPD.recHitEnergy(1.5) > HighestHPDEnergy)
00365          {
00366             HighestHPDEnergy = HPD.recHitEnergy(1.5);
00367             HighestHPDHits = HPD.numRecHits(1.5);
00368          }
00369 
00370          if(HPD.numRecHits(5) < 1)
00371             continue;
00372 
00373          if(HPD.bigChargeTotal() > 1e-5)
00374             hE2OverE10Digi->Fill(HPD.bigChargeHighest2TS() / HPD.bigChargeTotal());
00375          if(HPD.big5ChargeTotal() > 1e-5)
00376             hE2OverE10Digi5->Fill(HPD.big5ChargeHighest2TS() / HPD.big5ChargeTotal());
00377 
00378          hHPDHitCount->Fill(HPD.numRecHits(1.5));
00379       }
00380 
00381       int NoiseCategory = 0;
00382       bool IsRBXNoise = false;
00383       //      bool IsHPDNoise = false;
00384       //      bool IsHPDIonFeedback = false;
00385       //      bool IsHPDDischarge = false;
00386 
00387       if(RBXEnergy > 1e-5 && HighestHPDEnergy / RBXEnergy > 0.98)
00388       {
00389         //         IsHPDNoise = true;
00390 
00391          if(HighestHPDHits >= 9)
00392          {
00393            //            IsHPDDischarge = true;
00394             NoiseCategory = 7;
00395          }
00396          else
00397          {
00398            //            IsHPDIonFeedback = true;
00399             NoiseCategory = 8;
00400          }
00401       }
00402       else
00403       {
00404          IsRBXNoise = true;
00405          NoiseCategory = 1;
00406 
00407          if(RBXE10 > 1e-5)
00408          {
00409             if(RBXE2 / RBXE10 < 0.33)
00410                NoiseCategory = 2;
00411             else if(RBXE2 / RBXE10 < 0.8)
00412                NoiseCategory = 3;
00413             else if(RBXE2 / RBXE10 > 0.8 && NumberRBXHits > 10)
00414                NoiseCategory = 4;
00415             else if(RBXE2 / RBXE10 > 0.8 && NumberRBXHits < 10)  // [hic]
00416                NoiseCategory = 5;
00417          }
00418       }
00419 
00420       hHcalNoiseCategory->Fill(NoiseCategory);
00421 
00422       if(IsRBXNoise == true && RBXE10 > 1e-5)
00423          hE2OverE10RBX->Fill(RBXE2 / RBXE10);
00424    }
00425 
00426    return;
00427 }
00428 
00429 double HcalNoiseMonitor::PerformNominalFit(double Charge[10])
00430 {
00431    //
00432    // Performs a fit to the ideal pulse shape.  Returns best chi2
00433    //
00434    // A scan over different timing offset (for the ideal pulse) is carried out,
00435    //    and for each offset setting a one-parameter fit is performed
00436    //
00437 
00438    int DigiSize = 10;
00439 
00440    double MinimumChi2 = 100000;
00441 
00442    double F = 0;
00443 
00444    double SumF2 = 0;
00445    double SumTF = 0;
00446    double SumT2 = 0;
00447 
00448    for(int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i++)
00449    {
00450       if(CumulativeIdealPulse[i+250] - CumulativeIdealPulse[i] < 1e-5)
00451          continue;
00452 
00453       SumF2 = 0;
00454       SumTF = 0;
00455       SumT2 = 0;
00456 
00457       for(int j = 0; j < DigiSize; j++)
00458       {
00459          // get ideal pulse component for this time slice....
00460          F = CumulativeIdealPulse[i+j*25+25] - CumulativeIdealPulse[i+j*25];
00461 
00462          double Error2 = Charge[j];
00463          if(Error2 < 1)
00464             Error2 = 1;
00465 
00466          // ...and increment various summations
00467          SumF2 += F * F / Error2;
00468          SumTF += F * Charge[j] / Error2;
00469          SumT2 += Charge[j] * Charge[j] / Error2;
00470       }
00471 
00472       /* chi2= sum((Charge[j]-aF)^2/|Charge[j]|
00473          ( |Charge[j]| = assumed sigma^2 for Charge[j]; a bit wonky for Charge[j]<1 )
00474          chi2 = sum(|Charge[j]|) - 2*sum(aF*Charge[j]/|Charge[j]|) +sum( a^2*F^2/|Charge[j]|)
00475          chi2 minimimized when d(chi2)/da = 0:
00476          a = sum(F*Charge[j])/sum(F^2)
00477          ...
00478          chi2= sum(|Q[j]|) - sum(Q[j]/|Q[j]|*F)*sum(Q[j]/|Q[j]|*F)/sum(F^2/|Q[j]|), where Q = Charge
00479          chi2 = SumT2 - SumTF*SumTF/SumF2
00480       */
00481       
00482       double Chi2 = SumT2 - SumTF * SumTF / SumF2;
00483 
00484       if(Chi2 < MinimumChi2)
00485          MinimumChi2 = Chi2;
00486    }
00487 
00488    // safety protection in case of perfect fit - don't want the log(...) to explode
00489    if(MinimumChi2 < 1e-5)
00490       MinimumChi2 = 1e-5;
00491 
00492    return MinimumChi2;
00493 }
00494 
00495 double HcalNoiseMonitor::PerformDualNominalFit(double Charge[10])
00496 {
00497    //
00498    // Perform dual nominal fit and returns the chi2
00499    //
00500    // In this function we do a scan over possible "distance" (number of time slices between two components)
00501    //    and overall offset for the two components; first coarse, then finer
00502    // All the fitting is done in the DualNominalFitSingleTry function
00503    //                  
00504    
00505    double OverallMinimumChi2 = 1000000;
00506 
00507    int AvailableDistance[] = {-100, -75, -50, 50, 75, 100};
00508 
00509    // loop over possible pulse distances between two components
00510    for(int k = 0; k < 6; k++)
00511    {
00512       double SingleMinimumChi2 = 1000000;
00513       int MinOffset = 0;
00514 
00515       // scan coarsely through different offsets and find the minimum
00516       for(int i = 0; i + 250 < (int)CumulativeIdealPulse.size(); i += 10)
00517       {
00518          double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k]);
00519 
00520          if(Chi2 < SingleMinimumChi2)
00521          {
00522             SingleMinimumChi2 = Chi2;
00523             MinOffset = i;
00524          }
00525       }
00526 
00527       // around the minimum, scan finer for better a better minimum
00528       for(int i = MinOffset - 15; i + 250 < (int)CumulativeIdealPulse.size() && i < MinOffset + 15; i++)
00529       {
00530          double Chi2 = DualNominalFitSingleTry(Charge, i, AvailableDistance[k]);
00531          if(Chi2 < SingleMinimumChi2)
00532             SingleMinimumChi2 = Chi2;
00533       }
00534 
00535       // update overall minimum chi2
00536       if(SingleMinimumChi2 < OverallMinimumChi2)
00537          OverallMinimumChi2 = SingleMinimumChi2;
00538    }
00539 
00540    return OverallMinimumChi2;
00541 }
00542 
00543 double HcalNoiseMonitor::DualNominalFitSingleTry(double Charge[10], int Offset, int Distance)
00544 {
00545    //
00546    // Does a fit to dual signal pulse hypothesis given offset and distance of the two target pulses
00547    //
00548    // The only parameters to fit here are the two pulse heights of in-time and out-of-time components
00549    //    since offset is given
00550    // The calculation here is based from writing down the Chi2 formula and minimize against the two parameters,
00551    //    ie., Chi2 = Sum{((T[i] - a1 * F1[i] - a2 * F2[i]) / (Sigma[i]))^2}, where T[i] is the input pulse shape,
00552    //    and F1[i], F2[i] are the two ideal pulse components
00553    //
00554 
00555    int DigiSize = 10;
00556 
00557    if(Offset < 0 || Offset + 250 >= (int)CumulativeIdealPulse.size())
00558       return 1000000;
00559    if(CumulativeIdealPulse[Offset+250] - CumulativeIdealPulse[Offset] < 1e-5)
00560       return 1000000;
00561 
00562    static std::vector<double> F1;
00563    static std::vector<double> F2;
00564 
00565    F1.resize(DigiSize);
00566    F2.resize(DigiSize);
00567 
00568    double SumF1F1 = 0;
00569    double SumF1F2 = 0;
00570    double SumF2F2 = 0;
00571    double SumTF1 = 0;
00572    double SumTF2 = 0;
00573 
00574    double Error = 0;
00575 
00576    for(int j = 0; j < DigiSize; j++)
00577    {
00578       // this is the TS value for in-time component - no problem we can do a subtraction directly
00579       F1[j] = CumulativeIdealPulse[Offset+j*25+25] - CumulativeIdealPulse[Offset+j*25];
00580 
00581       // However for the out-of-time component the index might go out-of-bound.
00582       // Let's protect against this.
00583 
00584       int OffsetTemp = Offset + j * 25 + Distance;
00585       
00586       double C1 = 0;   // lower-indexed value in the cumulative pulse shape
00587       double C2 = 0;   // higher-indexed value in the cumulative pulse shape
00588       
00589       if(OffsetTemp + 25 < (int)CumulativeIdealPulse.size() && OffsetTemp + 25 >= 0)
00590          C1 = CumulativeIdealPulse[OffsetTemp+25];
00591       if(OffsetTemp + 25 >= (int)CumulativeIdealPulse.size())
00592          C1 = CumulativeIdealPulse[CumulativeIdealPulse.size()-1];
00593       if(OffsetTemp < (int)CumulativeIdealPulse.size() && OffsetTemp >= 0)
00594          C2 = CumulativeIdealPulse[OffsetTemp];
00595       if(OffsetTemp >= (int)CumulativeIdealPulse.size())
00596          C2 = CumulativeIdealPulse[CumulativeIdealPulse.size()-1];
00597       F2[j] = C1 - C2;
00598 
00599       Error = Charge[j];
00600       if(Error < 1)
00601          Error = 1;
00602 
00603       SumF1F1 += F1[j] * F1[j] / Error;
00604       SumF1F2 += F1[j] * F2[j] / Error; 
00605       SumF2F2 += F2[j] * F2[j] / Error;
00606       SumTF1  += F1[j] * Charge[j] / Error; 
00607       SumTF2  += F2[j] * Charge[j] / Error; 
00608    }
00609 
00610    double Height = (SumF1F2 * SumTF2 - SumF2F2 * SumTF1) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
00611    double Height2 = (SumF1F2 * SumTF1 - SumF1F1 * SumTF2) / (SumF1F2 * SumF1F2 - SumF1F1 * SumF2F2);
00612 
00613    double Chi2 = 0;
00614    for(int j = 0; j < DigiSize; j++)
00615    {
00616       double Error = Charge[j];
00617       if(Error < 1)
00618          Error = 1;
00619 
00620       double Residual = Height * F1[j] + Height2 * F2[j] - Charge[j];  
00621       Chi2 += Residual * Residual / Error;                             
00622    } 
00623 
00624    // Safety protection in case of zero
00625    if(Chi2 < 1e-5)
00626       Chi2 = 1e-5;
00627 
00628    return Chi2;
00629 }
00630 
00631 double HcalNoiseMonitor::PerformLinearFit(double Charge[10])
00632 {
00633    //
00634    // Performs a straight-line fit over all time slices, and returns the chi2 value
00635    //
00636    // The calculation here is based from writing down the formula for chi2 and minimize
00637    //    with respect to the parameters in the fit, ie., slope and intercept of the straight line
00638    // By doing two differentiation, we will get two equations, and the best parameters are determined by these
00639    //
00640 
00641    int DigiSize = 10;
00642 
00643    double SumTS2OverTi = 0;
00644    double SumTSOverTi = 0;
00645    double SumOverTi = 0;
00646    double SumTiTS = 0;
00647    double SumTi = 0;
00648 
00649    double Error2 = 0;
00650    for(int i = 0; i < DigiSize; i++)
00651    {
00652       Error2 = Charge[i];
00653       if(Charge[i] < 1)
00654          Error2 = 1;
00655 
00656       SumTS2OverTi += 1.* i * i / Error2;
00657       SumTSOverTi  += 1.* i / Error2;
00658       SumOverTi    += 1. / Error2;
00659       SumTiTS      += Charge[i] * i / Error2;
00660       SumTi        += Charge[i] / Error2;
00661    }
00662 
00663    double CM1 = SumTS2OverTi;   // Coefficient in front of slope in equation 1
00664    double CM2 = SumTSOverTi;   // Coefficient in front of slope in equation 2
00665    double CD1 = SumTSOverTi;   // Coefficient in front of intercept in equation 1
00666    double CD2 = SumOverTi;   // Coefficient in front of intercept in equation 2
00667    double C1 = SumTiTS;   // Constant coefficient in equation 1
00668    double C2 = SumTi;   // Constant coefficient in equation 2
00669 
00670    double Slope = (C1 * CD2 - C2 * CD1) / (CM1 * CD2 - CM2 * CD1);
00671    double Intercept = (C1 * CM2 - C2 * CM1) / (CD1 * CM2 - CD2 * CM1);
00672 
00673    // now that the best parameters are found, calculate chi2 from those
00674    double Chi2 = 0;
00675    for(int i = 0; i < DigiSize; i++)
00676    {
00677       double Deviation = Slope * i + Intercept - Charge[i];
00678       double Error2 = Charge[i];
00679       if(Charge[i] < 1)
00680          Error2 = 1;
00681       Chi2 += Deviation * Deviation / Error2;  
00682    }
00683 
00684    // safety protection in case of perfect fit
00685    if(Chi2 < 1e-5)
00686       Chi2 = 1e-5;
00687 
00688    return Chi2;
00689 }
00690 
00691 double HcalNoiseMonitor::CalculateRMS8Max(double Charge[10])
00692 {
00693    //
00694    // CalculateRMS8Max
00695    //
00696    // returns "RMS" divided by the largest charge in the time slices
00697    //    "RMS" is calculated using all but the two largest time slices.
00698    //    The "RMS" is not quite the actual RMS (see note below), but the value is only
00699    //    used for determining max values, and is not quoted as the actual RMS anywhere.
00700    //
00701 
00702    int DigiSize = 10;
00703 
00704    // Copy Charge vector again, since we are passing references around
00705    std::vector<double> TempCharge(Charge, Charge + 10);
00706 
00707    // Sort TempCharge vector from smallest to largest charge
00708    sort(TempCharge.begin(), TempCharge.end());
00709 
00710    double Total = 0;
00711    double Total2 = 0;
00712    for(int i = 0; i < DigiSize - 2; i++)
00713    {
00714       Total = Total + TempCharge[i];
00715       Total2 = Total2 + TempCharge[i] * TempCharge[i];
00716    }
00717 
00718    // This isn't quite the RMS (both Total2 and Total*Total need to be
00719    // divided by an extra (DigiSize-2) within the sqrt to get the RMS.)
00720    // We're only using this value for relative comparisons, though; we
00721    // aren't explicitly interpreting it as the RMS.  It might be nice
00722    // to either change the calculation or rename the variable in the future, though.
00723 
00724    double RMS = sqrt(Total2 - Total * Total / (DigiSize - 2));
00725 
00726    double RMS8Max = 99999;
00727    if(TempCharge[DigiSize-1] > 1e-5)
00728       RMS8Max = RMS / TempCharge[DigiSize-1];
00729    if(RMS8Max < 1e-5)   // protection against zero
00730       RMS8Max = 1e-5;
00731 
00732    return RMS8Max;
00733 }
00734 
00735 TriangleFitResult HcalNoiseMonitor::PerformTriangleFit(double Charge[10])
00736 {
00737    //
00738    // Perform a "triangle fit", and extract the slopes
00739    //
00740    // Left-hand side and right-hand side are not correlated to each other - do them separately
00741    //
00742 
00743    TriangleFitResult result;
00744    result.Chi2 = 0;
00745    result.LeftSlope = 0;
00746    result.RightSlope = 0;
00747 
00748    int DigiSize = 10;
00749 
00750    // right side, starting from TS4
00751    double MinimumRightChi2 = 1000000;
00752    double Numerator = 0;
00753    double Denominator = 0;
00754 
00755    for(int iTS = mTrianglePeakTS + 2; iTS <= DigiSize; iTS++)   // the place where first TS center in flat line
00756    {
00757       // fit a straight line to the triangle part
00758       Numerator = 0;
00759       Denominator = 0;
00760 
00761       for(int i = mTrianglePeakTS + 1; i < iTS; i++)
00762       {
00763          Numerator += (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
00764          Denominator += (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
00765       }
00766 
00767       double BestSlope = Numerator / Denominator;
00768       if(BestSlope > 0)
00769          BestSlope = 0;
00770 
00771       // check if the slope is reasonable
00772       if(iTS != DigiSize)
00773       {
00774          if(BestSlope > -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS))
00775             BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - mTrianglePeakTS);
00776          if(BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS))
00777             BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
00778       }
00779       else
00780       {
00781          if(BestSlope < -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS)) 
00782             BestSlope = -1 * Charge[mTrianglePeakTS] / (iTS - 1 - mTrianglePeakTS);
00783       }
00784 
00785       // calculate partial chi2
00786 
00787       // The shape I'm fitting is more like a tent than a triangle.
00788       // After the end of triangle edge assume a flat line
00789 
00790       double Chi2 = 0;
00791       for(int i = mTrianglePeakTS + 1; i < iTS; i++)
00792          Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope)
00793             * (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
00794       for(int i = iTS; i < DigiSize; i++)    // Assumes fit line = 0 for iTS > fit
00795          Chi2 += Charge[i] * Charge[i];
00796 
00797       if(Chi2 < MinimumRightChi2)
00798       {
00799          MinimumRightChi2 = Chi2;
00800          result.RightSlope = BestSlope;
00801       }
00802    }   // end of right-hand side loop
00803 
00804    // left side
00805    double MinimumLeftChi2 = 1000000;
00806 
00807    for(int iTS = 0; iTS < (int)mTrianglePeakTS; iTS++)   // the first time after linear fit ends
00808    {
00809       // fit a straight line to the triangle part
00810       Numerator = 0;
00811       Denominator = 0;
00812       for(int i = iTS; i < (int)mTrianglePeakTS; i++)
00813       {
00814          Numerator = Numerator + (i - mTrianglePeakTS) * (Charge[i] - Charge[mTrianglePeakTS]);
00815          Denominator = Denominator + (i - mTrianglePeakTS) * (i - mTrianglePeakTS);
00816       }
00817 
00818       double BestSlope = Numerator / Denominator;
00819       if(BestSlope < 0)
00820          BestSlope = 0;
00821 
00822       // check slope
00823       if(iTS != 0)
00824       {
00825          if(BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
00826             BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
00827          if(BestSlope < Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS))
00828             BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS + 1 - iTS);
00829       }
00830       else
00831       {
00832          if(BestSlope > Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS))
00833             BestSlope = Charge[mTrianglePeakTS] / (mTrianglePeakTS - iTS);
00834       }
00835 
00836       // calculate minimum chi2
00837       double Chi2 = 0;
00838       for(int i = 0; i < iTS; i++)
00839          Chi2 += Charge[i] * Charge[i];
00840       for(int i = iTS; i < (int)mTrianglePeakTS; i++)
00841          Chi2 += (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope)
00842             * (Charge[mTrianglePeakTS] - Charge[i] + (i - mTrianglePeakTS) * BestSlope);
00843 
00844       if(MinimumLeftChi2 > Chi2)
00845       {
00846          MinimumLeftChi2 = Chi2;
00847          result.LeftSlope = BestSlope;
00848       }
00849    }   // end of left-hand side loop
00850 
00851    result.Chi2 = MinimumLeftChi2 + MinimumRightChi2;
00852 
00853    return result;
00854 }
00855 
00856 void HcalNoiseMonitor::ReadHcalPulse()
00857 {
00858    std::vector<double> PulseShape;
00859 
00860    HcalPulseShapes Shapes;
00861    HcalPulseShapes::Shape HPDShape = Shapes.hbShape();
00862 
00863    PulseShape.reserve(350);
00864    for(int i = 0; i < 200; i++)
00865       PulseShape.push_back(HPDShape.at(i));
00866    PulseShape.insert(PulseShape.begin(), 150, 0);   // Safety margin of a lot of zeros in the beginning
00867 
00868    CumulativeIdealPulse.reserve(350);
00869    CumulativeIdealPulse.clear();
00870    CumulativeIdealPulse.push_back(0);
00871    for(unsigned int i = 1; i < PulseShape.size(); i++)
00872       CumulativeIdealPulse.push_back(CumulativeIdealPulse[i-1] + PulseShape[i]);
00873 }
00874 
00875 DEFINE_FWK_MODULE(HcalNoiseMonitor);
00876