CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_10_patch2/src/DQM/EcalBarrelMonitorTasks/src/EBSelectiveReadoutTask.cc

Go to the documentation of this file.
00001 /*
00002  * \file EBSelectiveReadoutTask.cc
00003  *
00004  * $Date: 2012/04/27 13:46:03 $
00005  * $Revision: 1.58 $
00006  * \author P. Gras
00007  * \author E. Di Marco
00008  *
00009 */
00010 
00011 #include <iostream>
00012 #include <fstream>
00013 #include <vector>
00014 #include <math.h>
00015 #include <cassert>
00016 
00017 #include "FWCore/ServiceRegistry/interface/Service.h"
00018 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00019 #include "FWCore/Framework/interface/ESHandle.h"
00020 
00021 #include "DQMServices/Core/interface/MonitorElement.h"
00022 
00023 #include "DQMServices/Core/interface/DQMStore.h"
00024 
00025 #include "DataFormats/EcalDetId/interface/EBDetId.h"
00026 #include "DataFormats/EcalDetId/interface/EcalTrigTowerDetId.h"
00027 
00028 #include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
00029 #include "DataFormats/EcalRawData/interface/EcalRawDataCollections.h"
00030 #include "DataFormats/EcalDigi/interface/EcalDigiCollections.h"
00031 
00032 #include "CondFormats/EcalObjects/interface/EcalChannelStatus.h"
00033 #include "CondFormats/DataRecord/interface/EcalChannelStatusRcd.h"
00034 
00035 #include "DQM/EcalCommon/interface/Numbers.h"
00036 
00037 #include "DQM/EcalBarrelMonitorTasks/interface/EBSelectiveReadoutTask.h"
00038 
00039 
00040 #include "CondFormats/EcalObjects/interface/EcalSRSettings.h"
00041 #include "CondFormats/DataRecord/interface/EcalSRSettingsRcd.h"
00042 
00043 
00044 EBSelectiveReadoutTask::EBSelectiveReadoutTask(const edm::ParameterSet& ps){
00045 
00046   init_ = false;
00047 
00048   dqmStore_ = edm::Service<DQMStore>().operator->();
00049 
00050   prefixME_ = ps.getUntrackedParameter<std::string>("prefixME", "");
00051 
00052   enableCleanup_ = ps.getUntrackedParameter<bool>("enableCleanup", false);
00053 
00054   mergeRuns_ = ps.getUntrackedParameter<bool>("mergeRuns", false);
00055 
00056   // parameters...
00057   EBDigiCollection_ = ps.getParameter<edm::InputTag>("EBDigiCollection");
00058   EBUnsuppressedDigiCollection_ = ps.getParameter<edm::InputTag>("EBUsuppressedDigiCollection");
00059   EBSRFlagCollection_ = ps.getParameter<edm::InputTag>("EBSRFlagCollection");
00060   EcalTrigPrimDigiCollection_ = ps.getParameter<edm::InputTag>("EcalTrigPrimDigiCollection");
00061   FEDRawDataCollection_ = ps.getParameter<edm::InputTag>("FEDRawDataCollection");
00062   firstFIRSample_ = ps.getParameter<int>("ecalDccZs1stSample");
00063 
00064   useCondDb_ = ps.getParameter<bool>("configFromCondDB");
00065 
00066   if(!useCondDb_) configFirWeights(ps.getParameter<std::vector<double> >("dccWeights"));
00067 
00068 
00069   // histograms...
00070   EBTowerSize_ = 0;
00071   EBTTFMismatch_ = 0;
00072   EBDccEventSize_ = 0;
00073   EBDccEventSizeMap_ = 0;
00074   EBReadoutUnitForcedBitMap_ = 0;
00075   EBFullReadoutSRFlagMap_ = 0;
00076   EBFullReadoutSRFlagCount_ = 0;
00077   EBZeroSuppression1SRFlagMap_ = 0;
00078   EBHighInterestTriggerTowerFlagMap_ = 0;
00079   EBMediumInterestTriggerTowerFlagMap_ = 0;
00080   EBLowInterestTriggerTowerFlagMap_ = 0;
00081   EBTTFlags_ = 0;
00082   EBCompleteZSMap_ = 0;
00083   EBCompleteZSCount_ = 0;
00084   EBDroppedFRMap_ = 0;
00085   EBDroppedFRCount_ = 0;
00086   EBEventSize_ = 0;
00087   EBHighInterestPayload_ = 0;
00088   EBLowInterestPayload_ = 0;
00089   EBHighInterestZsFIR_ = 0;
00090   EBLowInterestZsFIR_ = 0;
00091 
00092   // initialize variable binning for DCC size...
00093   float ZSthreshold = 0.608; // kBytes of 1 TT fully readout
00094   float zeroBinSize = ZSthreshold / 20.;
00095   for(int i=0; i<20; i++) ybins[i] = i*zeroBinSize;
00096   for(int i=20; i<89; i++) ybins[i] = ZSthreshold * (i-19);
00097   for(int i=0; i<=36; i++) xbins[i] = i+1;
00098 
00099 }
00100 
00101 EBSelectiveReadoutTask::~EBSelectiveReadoutTask() {
00102 
00103 }
00104 
00105 void EBSelectiveReadoutTask::beginJob(void) {
00106 
00107   ievt_ = 0;
00108 
00109   if ( dqmStore_ ) {
00110     dqmStore_->setCurrentFolder(prefixME_ + "/EBSelectiveReadoutTask");
00111     dqmStore_->rmdir(prefixME_ + "/EBSelectiveReadoutTask");
00112   }
00113 
00114 }
00115 
00116 void EBSelectiveReadoutTask::beginRun(const edm::Run& r, const edm::EventSetup& c) {
00117 
00118   Numbers::initGeometry(c, false);
00119 
00120   if ( ! mergeRuns_ ) this->reset();
00121 
00122   for(int ietindex = 0; ietindex < 34; ietindex++ ) {
00123     for(int iptindex = 0; iptindex < 72; iptindex++ ) {
00124       nEvtFullReadout[iptindex][ietindex] = 0;
00125       nEvtZS1Readout[iptindex][ietindex] = 0;
00126       nEvtZSReadout[iptindex][ietindex] = 0;
00127       nEvtCompleteReadoutIfZS[iptindex][ietindex] = 0;
00128       nEvtDroppedReadoutIfFR[iptindex][ietindex] = 0;
00129       nEvtRUForced[iptindex][ietindex] = 0;
00130       nEvtAnyReadout[iptindex][ietindex] = 0;
00131       nEvtHighInterest[iptindex][ietindex] = 0;
00132       nEvtMediumInterest[iptindex][ietindex] = 0;
00133       nEvtLowInterest[iptindex][ietindex] = 0;
00134       nEvtAnyInterest[iptindex][ietindex] = 0;
00135     }
00136   }
00137 
00138   //getting selective readout configuration
00139   if(useCondDb_) {
00140     edm::ESHandle<EcalSRSettings> hSr;
00141     c.get<EcalSRSettingsRcd>().get(hSr);
00142     settings_ = hSr.product();
00143     std::vector<double> wsFromDB;
00144 
00145     std::vector<std::vector<float> > dccs = settings_->dccNormalizedWeights_;
00146     int nws = dccs.size();
00147     if(nws == 1) {
00148       for(std::vector<float>::const_iterator it = dccs[0].begin(); it != dccs[0].end(); it++) {
00149         wsFromDB.push_back(*it);
00150       }
00151     }
00152     else edm::LogWarning("EBSelectiveReadoutTask") << "DCC weight set is not exactly 1.";
00153 
00154     configFirWeights(wsFromDB);
00155   }
00156 
00157 }
00158 
00159 void EBSelectiveReadoutTask::endRun(const edm::Run& r, const edm::EventSetup& c) {
00160 
00161 }
00162 
00163 void EBSelectiveReadoutTask::reset(void) {
00164 
00165   if ( EBTowerSize_ ) EBTowerSize_->Reset();
00166 
00167   if ( EBTTFMismatch_ ) EBTTFMismatch_->Reset();
00168 
00169   if ( EBDccEventSize_ ) EBDccEventSize_->Reset();
00170 
00171   if ( EBDccEventSizeMap_ ) EBDccEventSizeMap_->Reset();
00172 
00173   if ( EBReadoutUnitForcedBitMap_ ) EBReadoutUnitForcedBitMap_->Reset();
00174 
00175   if ( EBFullReadoutSRFlagMap_ ) EBFullReadoutSRFlagMap_->Reset();
00176 
00177   if ( EBFullReadoutSRFlagCount_ ) EBFullReadoutSRFlagCount_->Reset();
00178 
00179   if ( EBZeroSuppression1SRFlagMap_ ) EBZeroSuppression1SRFlagMap_->Reset(); 
00180 
00181   if ( EBHighInterestTriggerTowerFlagMap_ ) EBHighInterestTriggerTowerFlagMap_->Reset();
00182 
00183   if ( EBMediumInterestTriggerTowerFlagMap_ ) EBMediumInterestTriggerTowerFlagMap_->Reset();
00184 
00185   if ( EBLowInterestTriggerTowerFlagMap_ ) EBLowInterestTriggerTowerFlagMap_->Reset();
00186   
00187   if ( EBTTFlags_ ) EBTTFlags_->Reset();
00188 
00189   if ( EBCompleteZSMap_ ) EBCompleteZSMap_->Reset();
00190   
00191   if ( EBCompleteZSCount_ ) EBCompleteZSCount_->Reset();
00192 
00193   if ( EBDroppedFRMap_ ) EBDroppedFRMap_->Reset();
00194 
00195   if ( EBDroppedFRCount_ ) EBDroppedFRCount_->Reset();
00196 
00197   if ( EBEventSize_ ) EBEventSize_->Reset();
00198 
00199   if ( EBHighInterestPayload_ ) EBHighInterestPayload_->Reset();
00200 
00201   if ( EBLowInterestPayload_ ) EBLowInterestPayload_->Reset();
00202 
00203   if ( EBHighInterestZsFIR_ ) EBHighInterestZsFIR_->Reset();
00204 
00205   if ( EBLowInterestZsFIR_ ) EBLowInterestZsFIR_->Reset();
00206 
00207 }
00208 
00209 void EBSelectiveReadoutTask::setup(void) {
00210 
00211   init_ = true;
00212 
00213   std::string name;
00214 
00215   if ( dqmStore_ ) {
00216 
00217     dqmStore_->setCurrentFolder(prefixME_ + "/EBSelectiveReadoutTask");
00218 
00219     name = "EBSRT tower event size";
00220     EBTowerSize_ = dqmStore_->bookProfile2D(name, name, 72, 0, 72, 34, -17, 17, 100, 0, 200, "s");
00221     EBTowerSize_->setAxisTitle("jphi", 1);
00222     EBTowerSize_->setAxisTitle("jeta", 2);
00223 
00224     name = "EBSRT TT flag mismatch";
00225     EBTTFMismatch_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00226     EBTTFMismatch_->setAxisTitle("jphi", 1);
00227     EBTTFMismatch_->setAxisTitle("jeta", 2);
00228 
00229     name = "EBSRT DCC event size";
00230     EBDccEventSize_ = dqmStore_->bookProfile(name, name, 36, 1, 37, 100, 0., 200., "s");
00231     EBDccEventSize_->setAxisTitle("event size (kB)", 2);
00232     for (int i = 0; i < 36; i++) {
00233       EBDccEventSize_->setBinLabel(i+1, Numbers::sEB(i+1), 1);
00234     }
00235 
00236     name = "EBSRT event size vs DCC";
00237     EBDccEventSizeMap_ = dqmStore_->book2D(name, name, 36, xbins, 88, ybins);
00238     EBDccEventSizeMap_->setAxisTitle("event size (kB)", 2);
00239     for (int i = 0; i < 36; i++) {
00240       EBDccEventSizeMap_->setBinLabel(i+1, Numbers::sEB(i+1), 1);
00241     }
00242 
00243     name = "EBSRT readout unit with SR forced";
00244     EBReadoutUnitForcedBitMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00245     EBReadoutUnitForcedBitMap_->setAxisTitle("jphi", 1);
00246     EBReadoutUnitForcedBitMap_->setAxisTitle("jeta", 2);
00247     EBReadoutUnitForcedBitMap_->setAxisTitle("rate", 3);
00248 
00249     name = "EBSRT full readout SR Flags";
00250     EBFullReadoutSRFlagMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00251     EBFullReadoutSRFlagMap_->setAxisTitle("jphi", 1);
00252     EBFullReadoutSRFlagMap_->setAxisTitle("jeta", 2);
00253     EBFullReadoutSRFlagMap_->setAxisTitle("rate", 3);
00254 
00255     name = "EBSRT full readout SR Flags Number";
00256     EBFullReadoutSRFlagCount_ = dqmStore_->book1D(name, name, 200, 0., 200.);
00257     EBFullReadoutSRFlagCount_->setAxisTitle("Readout Units number", 1);
00258 
00259     name = "EBSRT zero suppression 1 SR Flags";
00260     EBZeroSuppression1SRFlagMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00261     EBZeroSuppression1SRFlagMap_->setAxisTitle("jphi", 1);
00262     EBZeroSuppression1SRFlagMap_->setAxisTitle("jeta", 2);
00263     EBZeroSuppression1SRFlagMap_->setAxisTitle("rate", 3);
00264 
00265     name = "EBSRT high interest TT Flags";
00266     EBHighInterestTriggerTowerFlagMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00267     EBHighInterestTriggerTowerFlagMap_->setAxisTitle("jphi", 1);
00268     EBHighInterestTriggerTowerFlagMap_->setAxisTitle("jeta", 2);
00269     EBHighInterestTriggerTowerFlagMap_->setAxisTitle("rate", 3);
00270 
00271     name = "EBSRT medium interest TT Flags";
00272     EBMediumInterestTriggerTowerFlagMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00273     EBMediumInterestTriggerTowerFlagMap_->setAxisTitle("jphi", 1);
00274     EBMediumInterestTriggerTowerFlagMap_->setAxisTitle("jeta", 2);
00275     EBMediumInterestTriggerTowerFlagMap_->setAxisTitle("rate", 3);
00276 
00277     name = "EBSRT low interest TT Flags";
00278     EBLowInterestTriggerTowerFlagMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00279     EBLowInterestTriggerTowerFlagMap_->setAxisTitle("jphi", 1);
00280     EBLowInterestTriggerTowerFlagMap_->setAxisTitle("jeta", 2);
00281     EBLowInterestTriggerTowerFlagMap_->setAxisTitle("rate", 3);
00282 
00283     name = "EBSRT TT Flags";
00284     EBTTFlags_ = dqmStore_->book1D(name, name, 8, 0., 8.);
00285     EBTTFlags_->setAxisTitle("TT Flag value", 1);
00286 
00287     name = "EBSRT ZS Flagged Fully Readout";
00288     EBCompleteZSMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00289     EBCompleteZSMap_->setAxisTitle("jphi", 1);
00290     EBCompleteZSMap_->setAxisTitle("jeta", 2);
00291     EBCompleteZSMap_->setAxisTitle("rate", 3);
00292 
00293     name = "EBSRT ZS Flagged Fully Readout Number";
00294     EBCompleteZSCount_ = dqmStore_->book1D(name, name, 20, 0., 20.);
00295     EBCompleteZSCount_->setAxisTitle("Readout Units number", 1);
00296 
00297     name = "EBSRT FR Flagged Dropped Readout";
00298     EBDroppedFRMap_ = dqmStore_->book2D(name, name, 72, 0, 72, 34, -17, 17);
00299     EBDroppedFRMap_->setAxisTitle("jphi", 1);
00300     EBDroppedFRMap_->setAxisTitle("jeta", 2);
00301     EBDroppedFRMap_->setAxisTitle("rate", 3);
00302 
00303     name = "EBSRT FR Flagged Dropped Readout Number";
00304     EBDroppedFRCount_ = dqmStore_->book1D(name, name, 20, 0., 20.);
00305     EBDroppedFRCount_->setAxisTitle("Readout Units number", 1);
00306 
00307     name = "EBSRT event size";
00308     EBEventSize_ = dqmStore_->book1D(name, name, 100, 0, 200);
00309     EBEventSize_->setAxisTitle("event size (kB)",1);
00310 
00311     name = "EBSRT high interest payload";
00312     EBHighInterestPayload_ =  dqmStore_->book1D(name, name, 100, 0, 200);
00313     EBHighInterestPayload_->setAxisTitle("event size (kB)",1);
00314 
00315     name = "EBSRT low interest payload";
00316     EBLowInterestPayload_ =  dqmStore_->book1D(name, name, 100, 0, 200);
00317     EBLowInterestPayload_->setAxisTitle("event size (kB)",1);
00318 
00319     name = "EBSRT high interest ZS filter output";
00320     EBHighInterestZsFIR_ = dqmStore_->book1D(name, name, 60, -30, 30);
00321     EBHighInterestZsFIR_->setAxisTitle("ADC counts*4",1);
00322 
00323     name = "EBSRT low interest ZS filter output";
00324     EBLowInterestZsFIR_ = dqmStore_->book1D(name, name, 60, -30, 30);
00325     EBLowInterestZsFIR_->setAxisTitle("ADC counts*4",1);
00326 
00327   }
00328 
00329 }
00330 
00331 void EBSelectiveReadoutTask::cleanup(void){
00332 
00333   if ( ! init_ ) return;
00334 
00335   if ( dqmStore_ ) {
00336 
00337     dqmStore_->setCurrentFolder(prefixME_ + "/EBSelectiveReadoutTask");
00338 
00339     if ( EBTowerSize_ ) dqmStore_->removeElement( EBTowerSize_->getName() );
00340     EBTowerSize_ = 0;
00341 
00342     if ( EBTTFMismatch_ ) dqmStore_->removeElement( EBTTFMismatch_->getName() );
00343     EBTTFMismatch_ = 0;
00344 
00345     if ( EBDccEventSize_ ) dqmStore_->removeElement( EBDccEventSize_->getName() );
00346     EBDccEventSize_ = 0;
00347 
00348     if ( EBDccEventSizeMap_ ) dqmStore_->removeElement( EBDccEventSizeMap_->getName() );
00349     EBDccEventSizeMap_ = 0;
00350 
00351     if ( EBReadoutUnitForcedBitMap_ ) dqmStore_->removeElement( EBReadoutUnitForcedBitMap_->getName() );
00352     EBReadoutUnitForcedBitMap_ = 0;
00353 
00354     if ( EBFullReadoutSRFlagMap_ ) dqmStore_->removeElement( EBFullReadoutSRFlagMap_->getName() );
00355     EBFullReadoutSRFlagMap_ = 0;
00356 
00357     if ( EBFullReadoutSRFlagCount_ ) dqmStore_->removeElement( EBFullReadoutSRFlagCount_->getName() );
00358     EBFullReadoutSRFlagCount_ = 0;
00359 
00360     if ( EBFullReadoutSRFlagCount_ ) dqmStore_->removeElement( EBFullReadoutSRFlagCount_->getName() );
00361     EBFullReadoutSRFlagCount_ = 0;
00362 
00363     if ( EBHighInterestTriggerTowerFlagMap_ ) dqmStore_->removeElement( EBHighInterestTriggerTowerFlagMap_->getName() );
00364     EBHighInterestTriggerTowerFlagMap_ = 0;
00365 
00366     if ( EBMediumInterestTriggerTowerFlagMap_ ) dqmStore_->removeElement( EBMediumInterestTriggerTowerFlagMap_->getName() );
00367     EBMediumInterestTriggerTowerFlagMap_ = 0;
00368 
00369     if ( EBLowInterestTriggerTowerFlagMap_ ) dqmStore_->removeElement( EBLowInterestTriggerTowerFlagMap_->getName() );
00370     EBLowInterestTriggerTowerFlagMap_ = 0;
00371 
00372     if ( EBTTFlags_ ) dqmStore_->removeElement( EBTTFlags_->getName() );
00373     EBTTFlags_ = 0;
00374 
00375     if ( EBCompleteZSMap_ ) dqmStore_->removeElement( EBCompleteZSMap_->getName() );
00376     EBCompleteZSMap_ = 0;
00377 
00378     if ( EBCompleteZSCount_ ) dqmStore_->removeElement( EBCompleteZSCount_->getName() );
00379     EBCompleteZSCount_ = 0;
00380 
00381     if ( EBDroppedFRMap_ ) dqmStore_->removeElement( EBDroppedFRMap_->getName() );
00382     EBDroppedFRMap_ = 0;
00383 
00384     if ( EBDroppedFRCount_ ) dqmStore_->removeElement( EBDroppedFRCount_->getName() );
00385     EBDroppedFRCount_ = 0;
00386 
00387     if ( EBEventSize_ ) dqmStore_->removeElement( EBEventSize_->getName() );
00388     EBEventSize_ = 0;
00389 
00390     if ( EBHighInterestPayload_ ) dqmStore_->removeElement( EBHighInterestPayload_->getName() );
00391     EBHighInterestPayload_ = 0;
00392 
00393     if ( EBLowInterestPayload_ ) dqmStore_->removeElement( EBLowInterestPayload_->getName() );
00394     EBLowInterestPayload_ = 0;
00395 
00396     if ( EBHighInterestZsFIR_ ) dqmStore_->removeElement( EBHighInterestZsFIR_->getName() );
00397     EBHighInterestZsFIR_ = 0;
00398 
00399     if ( EBLowInterestZsFIR_ ) dqmStore_->removeElement( EBLowInterestZsFIR_->getName() );
00400     EBLowInterestZsFIR_ = 0;
00401 
00402   }
00403 
00404   init_ = false;
00405 
00406 }
00407 
00408 void EBSelectiveReadoutTask::endJob(void){
00409 
00410   edm::LogInfo("EBSelectiveReadoutTask") << "analyzed " << ievt_ << " events";
00411 
00412   if ( enableCleanup_ ) this->cleanup();
00413 
00414 }
00415 
00416 void EBSelectiveReadoutTask::analyze(const edm::Event& e, const edm::EventSetup& c){
00417 
00418   if ( ! init_ ) this->setup();
00419 
00420   ievt_++;
00421 
00422   edm::Handle<FEDRawDataCollection> raw;
00423   if ( e.getByLabel(FEDRawDataCollection_, raw) ) {
00424 
00425     for ( int iDcc = 0; iDcc < nEBDcc; ++iDcc ) {
00426 
00427       EBDccEventSize_->Fill(iDcc+1, ((double)raw->FEDData(610+iDcc).size())/kByte );
00428       EBDccEventSizeMap_->Fill(iDcc+1, ((double)raw->FEDData(610+iDcc).size())/kByte);
00429 
00430     }
00431 
00432   } else {
00433     edm::LogWarning("EBSelectiveReadoutTask") << FEDRawDataCollection_ << " not available";
00434   }
00435 
00436   // Selective Readout Flags
00437   int nFRO, nCompleteZS, nDroppedFRO;
00438   nFRO = 0;
00439   nCompleteZS = 0;
00440   nDroppedFRO = 0;
00441   edm::Handle<EBSrFlagCollection> ebSrFlags;
00442   if ( e.getByLabel(EBSRFlagCollection_,ebSrFlags) ) {
00443 
00444     // Data Volume
00445     double aLowInterest=0;
00446     double aHighInterest=0;
00447     double aAnyInterest=0;
00448 
00449     edm::Handle<EBDigiCollection> ebDigis;
00450     if ( e.getByLabel(EBDigiCollection_ , ebDigis) ) {
00451 
00452       anaDigiInit();
00453 
00454       // channel status
00455       edm::ESHandle<EcalChannelStatus> pChannelStatus;
00456       c.get<EcalChannelStatusRcd>().get(pChannelStatus);
00457       const EcalChannelStatus* chStatus = pChannelStatus.product();  
00458 
00459       for (unsigned int digis=0; digis<ebDigis->size(); ++digis){
00460         EBDataFrame ebdf = (*ebDigis)[digis];
00461         EBDetId id = ebdf.id();
00462         EcalChannelStatusMap::const_iterator chit;
00463         chit = chStatus->getMap().find(id.rawId());
00464         uint16_t statusCode = 0;
00465         if( chit != chStatus->getMap().end() ) {
00466           EcalChannelStatusCode ch_code = (*chit);
00467           statusCode = ch_code.getStatusCode();
00468         }
00469         anaDigi(ebdf, *ebSrFlags, statusCode);
00470       }
00471 
00472       //low interest channels:
00473       aLowInterest = nEbLI_*bytesPerCrystal/kByte;
00474       EBLowInterestPayload_->Fill(aLowInterest);
00475 
00476       //low interest channels:
00477       aHighInterest = nEbHI_*bytesPerCrystal/kByte;
00478       EBHighInterestPayload_->Fill(aHighInterest);
00479 
00480       //any-interest channels:
00481       aAnyInterest = getEbEventSize(nEb_)/kByte;
00482       EBEventSize_->Fill(aAnyInterest);
00483 
00484       //event size by tower:
00485       for(int ietindex = 0; ietindex < 34; ietindex++ ) {
00486         for(int iptindex = 0; iptindex < 72; iptindex++ ) {
00487 
00488           float xiet = (ietindex < 17) ? ietindex + 0.5 : (16-ietindex) + 0.5;
00489           float xipt = iptindex + 0.5;
00490 
00491           double towerSize =  nCryTower[iptindex][ietindex] * bytesPerCrystal;
00492           EBTowerSize_->Fill(xipt, xiet, towerSize);
00493 
00494         }
00495       }
00496     } else {
00497       edm::LogWarning("EBSelectiveReadoutTask") << EBDigiCollection_ << " not available";
00498     }
00499 
00500     // initialize dcchs_ to mask disabled towers
00501     std::map< int, std::vector<short> > towersStatus;
00502     edm::Handle<EcalRawDataCollection> dcchs;
00503 
00504     if( e.getByLabel(FEDRawDataCollection_, dcchs) ) {
00505       for ( EcalRawDataCollection::const_iterator dcchItr = dcchs->begin(); dcchItr != dcchs->end(); ++dcchItr ) {
00506         if ( Numbers::subDet( *dcchItr ) != EcalBarrel ) continue;
00507         int ism = Numbers::iSM( *dcchItr, EcalBarrel );
00508         towersStatus.insert(std::make_pair(ism, dcchItr->getFEStatus()));
00509       }
00510     }
00511 
00512     for ( EBSrFlagCollection::const_iterator it = ebSrFlags->begin(); it != ebSrFlags->end(); ++it ) {
00513 
00514       EcalTrigTowerDetId id = it->id();
00515 
00516       if ( Numbers::subDet( id ) != EcalBarrel ) continue;
00517 
00518       int iet = id.ieta();
00519       int ietindex = (iet>0) ? iet - 1 : 16 + std::abs(iet);
00520       // phi_tower: change the range from global to SM-local
00521       // phi==0 is in the middle of a SM
00522       int ipt = id.iphi() + 2;
00523       if ( ipt > 72 ) ipt = ipt - 72;
00524       int iptindex = ipt - 1;
00525       int ism = Numbers::iSM( id );
00526       int itt = Numbers::iTT( id );
00527 
00528       nEvtAnyReadout[iptindex][ietindex]++;
00529 
00530       int flag = it->value() & ~EcalSrFlag::SRF_FORCED_MASK;
00531 
00532       int status=0;
00533       if( towersStatus[ism].size() > 0 ) status = (towersStatus[ism])[itt];
00534 
00535       if(flag == EcalSrFlag::SRF_FULL) {
00536         nEvtFullReadout[iptindex][ietindex]++;
00537         nFRO++;
00538         if(nPerRu_[ism-1][itt-1] == 0) {
00539           if(status != 1) nEvtDroppedReadoutIfFR[iptindex][ietindex]++;
00540           nDroppedFRO++;
00541         }
00542       }
00543 
00544       if(flag == EcalSrFlag::SRF_ZS1) nEvtZS1Readout[iptindex][ietindex]++;
00545 
00546       if(it->value() & EcalSrFlag::SRF_FORCED_MASK) nEvtRUForced[iptindex][ietindex]++;
00547 
00548       if(flag == EcalSrFlag::SRF_ZS1 || flag == EcalSrFlag::SRF_ZS2) {
00549         nEvtZSReadout[iptindex][ietindex]++;
00550         if(nPerRu_[ism-1][itt-1] == getCrystalCount()) {
00551           if(status != 1) nEvtCompleteReadoutIfZS[iptindex][ietindex]++;
00552           nCompleteZS++;
00553         }
00554       }
00555 
00556     }
00557   } else {
00558     edm::LogWarning("EBSelectiveReadoutTask") << EBSRFlagCollection_ << " not available";
00559   }
00560 
00561   for(int ietindex = 0; ietindex < 34; ietindex++ ) {
00562     for(int iptindex = 0; iptindex < 72; iptindex++ ) {
00563 
00564       if(nEvtAnyReadout[iptindex][ietindex]) {
00565 
00566         float xiet = (ietindex < 17) ? ietindex + 0.5 : (16-ietindex) + 0.5;
00567         float xipt = iptindex + 0.5;
00568 
00569         float fraction = float(nEvtFullReadout[iptindex][ietindex]) / float(nEvtAnyReadout[iptindex][ietindex]);
00570         float error = sqrt(fraction*(1-fraction)/float(nEvtAnyReadout[iptindex][ietindex]));
00571 
00572         TH2F *h2d = EBFullReadoutSRFlagMap_->getTH2F();
00573 
00574         int binet=0, binpt=0;
00575 
00576         if ( h2d ) {
00577           binpt = h2d->GetXaxis()->FindBin(xipt);
00578           binet = h2d->GetYaxis()->FindBin(xiet);
00579         }
00580 
00581         EBFullReadoutSRFlagMap_->setBinContent(binpt, binet, fraction);
00582         EBFullReadoutSRFlagMap_->setBinError(binpt, binet, error);
00583 
00584 
00585         fraction = float(nEvtZS1Readout[iptindex][ietindex]) / float(nEvtAnyReadout[iptindex][ietindex]);
00586         error = sqrt(fraction*(1-fraction)/float(nEvtAnyReadout[iptindex][ietindex]));
00587 
00588         h2d = EBZeroSuppression1SRFlagMap_->getTH2F();
00589 
00590         if ( h2d ) {
00591           binpt = h2d->GetXaxis()->FindBin(xipt);
00592           binet = h2d->GetYaxis()->FindBin(xiet);
00593         }
00594 
00595         EBZeroSuppression1SRFlagMap_->setBinContent(binpt, binet, fraction);
00596         EBZeroSuppression1SRFlagMap_->setBinError(binpt, binet, error);
00597 
00598 
00599         fraction = float(nEvtRUForced[iptindex][ietindex]) / float(nEvtAnyReadout[iptindex][ietindex]);
00600         error = sqrt(fraction*(1-fraction)/float(nEvtAnyReadout[iptindex][ietindex]));
00601 
00602         h2d = EBReadoutUnitForcedBitMap_->getTH2F();
00603 
00604         if ( h2d ) {
00605           binpt = h2d->GetXaxis()->FindBin(xipt);
00606           binet = h2d->GetYaxis()->FindBin(xiet);
00607         }
00608 
00609         EBReadoutUnitForcedBitMap_->setBinContent(binpt, binet, fraction);
00610         EBReadoutUnitForcedBitMap_->setBinError(binpt, binet, error);
00611 
00612         if( nEvtZSReadout[iptindex][ietindex] ) {
00613           fraction = float(nEvtCompleteReadoutIfZS[iptindex][ietindex]) / float(nEvtZSReadout[iptindex][ietindex]);
00614           error = sqrt(fraction*(1-fraction)/float(nEvtAnyReadout[iptindex][ietindex]));
00615 
00616           h2d = EBCompleteZSMap_->getTH2F();
00617           
00618           if ( h2d ) {
00619             binpt = h2d->GetXaxis()->FindBin(xipt);
00620             binet = h2d->GetYaxis()->FindBin(xiet);
00621           }
00622           
00623           EBCompleteZSMap_->setBinContent(binpt, binet, fraction);
00624           EBCompleteZSMap_->setBinError(binpt, binet, error);
00625         }
00626 
00627         if( nEvtFullReadout[iptindex][ietindex] ) {
00628           fraction = float(nEvtDroppedReadoutIfFR[iptindex][ietindex]) / float(nEvtFullReadout[iptindex][ietindex]);
00629           error = sqrt(fraction*(1-fraction)/float(nEvtAnyReadout[iptindex][ietindex]));
00630           
00631           h2d = EBDroppedFRMap_->getTH2F();
00632           
00633           if ( h2d ) {
00634             binpt = h2d->GetXaxis()->FindBin(xipt);
00635             binet = h2d->GetYaxis()->FindBin(xiet);
00636           }
00637           
00638           EBDroppedFRMap_->setBinContent(binpt, binet, fraction);
00639           EBDroppedFRMap_->setBinError(binpt, binet, error);
00640         }
00641       }
00642 
00643     }
00644   }
00645 
00646   EBFullReadoutSRFlagCount_->Fill( nFRO );
00647   EBCompleteZSCount_->Fill( nCompleteZS );
00648   EBDroppedFRCount_->Fill( nDroppedFRO );
00649 
00650   edm::Handle<EcalTrigPrimDigiCollection> TPCollection;
00651   if ( e.getByLabel(EcalTrigPrimDigiCollection_, TPCollection) ) {
00652 
00653     // Trigger Primitives
00654     EcalTrigPrimDigiCollection::const_iterator TPdigi;
00655     for (TPdigi = TPCollection->begin(); TPdigi != TPCollection->end(); ++TPdigi ) {
00656 
00657       if ( Numbers::subDet( TPdigi->id() ) != EcalBarrel ) continue;
00658 
00659       int iet = TPdigi->id().ieta();
00660       int ietindex = (iet>0) ? iet - 1 : 16 + std::abs(iet);
00661       // phi_tower: change the range from global to SM-local
00662       // phi==0 is in the middle of a SM
00663       int ipt = TPdigi->id().iphi() + 2;
00664       if ( ipt > 72 ) ipt = ipt - 72;
00665       int iptindex = ipt - 1;
00666 
00667       nEvtAnyInterest[iptindex][ietindex]++;
00668 
00669       if ( (TPdigi->ttFlag() & 0x3) == 0 ) nEvtLowInterest[iptindex][ietindex]++;
00670 
00671       if ( (TPdigi->ttFlag() & 0x3) == 1 ) nEvtMediumInterest[iptindex][ietindex]++;
00672 
00673       if ( (TPdigi->ttFlag() & 0x3) == 3 ) nEvtHighInterest[iptindex][ietindex]++;
00674 
00675       EBTTFlags_->Fill( TPdigi->ttFlag() );
00676 
00677       float xiet = (ietindex < 17) ? ietindex + 0.5 : (16-ietindex) + 0.5;
00678       float xipt = iptindex + 0.5;
00679 
00680       if ( ((TPdigi->ttFlag() & 0x3) == 1 || (TPdigi->ttFlag() & 0x3) == 3)
00681            && nCryTower[iptindex][ietindex] != 25 ) EBTTFMismatch_->Fill(xipt, xiet);
00682 
00683     }
00684   } else {
00685     edm::LogWarning("EBSelectiveReadoutTask") << EcalTrigPrimDigiCollection_ << " not available";
00686   }
00687 
00688   for(int ietindex = 0; ietindex < 34; ietindex++ ) {
00689     for(int iptindex = 0; iptindex < 72; iptindex++ ) {
00690 
00691       if(nEvtAnyInterest[iptindex][ietindex]) {
00692 
00693         float xiet = (ietindex < 17) ? ietindex + 0.5 : (16-ietindex) + 0.5;
00694         float xipt = iptindex + 0.5;
00695 
00696         float fraction = float(nEvtHighInterest[iptindex][ietindex]) / float(nEvtAnyInterest[iptindex][ietindex]);
00697         float error = sqrt(fraction*(1-fraction)/float(nEvtAnyInterest[iptindex][ietindex]));
00698 
00699         TH2F *h2d = EBHighInterestTriggerTowerFlagMap_->getTH2F();
00700 
00701         int binet=0, binpt=0;
00702 
00703         if ( h2d ) {
00704           binpt = h2d->GetXaxis()->FindBin(xipt);
00705           binet = h2d->GetYaxis()->FindBin(xiet);
00706         }
00707 
00708         EBHighInterestTriggerTowerFlagMap_->setBinContent(binpt, binet, fraction);
00709         EBHighInterestTriggerTowerFlagMap_->setBinError(binpt, binet, error);
00710 
00711 
00712         fraction = float(nEvtMediumInterest[iptindex][ietindex]) / float(nEvtAnyInterest[iptindex][ietindex]);
00713         error = sqrt(fraction*(1-fraction)/float(nEvtAnyInterest[iptindex][ietindex]));
00714 
00715         h2d = EBMediumInterestTriggerTowerFlagMap_->getTH2F();
00716 
00717         if ( h2d ) {
00718           binpt = h2d->GetXaxis()->FindBin(xipt);
00719           binet = h2d->GetYaxis()->FindBin(xiet);
00720         }
00721 
00722         EBMediumInterestTriggerTowerFlagMap_->setBinContent(binpt, binet, fraction);
00723         EBMediumInterestTriggerTowerFlagMap_->setBinError(binpt, binet, error);
00724 
00725 
00726         fraction = float(nEvtLowInterest[iptindex][ietindex]) / float(nEvtAnyInterest[iptindex][ietindex]);
00727         error = sqrt(fraction*(1-fraction)/float(nEvtAnyInterest[iptindex][ietindex]));
00728 
00729         h2d = EBLowInterestTriggerTowerFlagMap_->getTH2F();
00730 
00731         if ( h2d ) {
00732           binpt = h2d->GetXaxis()->FindBin(xipt);
00733           binet = h2d->GetYaxis()->FindBin(xiet);
00734         }
00735 
00736         EBLowInterestTriggerTowerFlagMap_->setBinContent(binpt, binet, fraction);
00737         EBLowInterestTriggerTowerFlagMap_->setBinError(binpt, binet, error);
00738 
00739       }
00740 
00741     }
00742   }
00743 
00744 
00745 }
00746 
00747 void EBSelectiveReadoutTask::anaDigi(const EBDataFrame& frame, const EBSrFlagCollection& srFlagColl, uint16_t statusCode){
00748 
00749   EBDetId id = frame.id();
00750 
00751   bool barrel = (id.subdetId()==EcalBarrel);
00752 
00753   if(barrel){
00754     ++nEb_;
00755 
00756     int ieta = id.ieta();
00757     int iphi = id.iphi();
00758 
00759     int iEta0 = iEta2cIndex(ieta);
00760     int iPhi0 = iPhi2cIndex(iphi);
00761     if(!ebRuActive_[iEta0/ebTtEdge][iPhi0/ebTtEdge]){
00762       ++nRuPerDcc_[dccNum(id)-1];
00763       ebRuActive_[iEta0/ebTtEdge][iPhi0/ebTtEdge] = true;
00764     }
00765 
00766     EcalTrigTowerDetId towid = id.tower();
00767     int iet = towid.ieta();
00768     int ietindex = (iet>0) ? iet - 1 : 16 + std::abs(iet);
00769     // phi_tower: change the range from global to SM-local
00770     // phi==0 is in the middle of a SM
00771     int ipt = towid.iphi() + 2;
00772     if ( ipt > 72 ) ipt = ipt - 72;
00773     int iptindex = ipt - 1;
00774     
00775     int ism = Numbers::iSM( id );
00776     int itt = Numbers::iTT( towid );
00777 
00778     nCryTower[iptindex][ietindex]++;
00779     
00780     EBSrFlagCollection::const_iterator srf = srFlagColl.find(readOutUnitOf(id));
00781     
00782     if(srf == srFlagColl.end()){
00783       return;
00784     }
00785     
00786     bool highInterest = ((srf->value() & ~EcalSrFlag::SRF_FORCED_MASK)
00787                          == EcalSrFlag::SRF_FULL);
00788     
00789 
00790     int dccZsFIRval = dccZsFIR(frame, firWeights_, firstFIRSample_, 0);
00791 
00792     if(highInterest){
00793       ++nEbHI_;
00794       // if(statusCode != 9) EBHighInterestZsFIR_->Fill( dccZsFIRval );
00795       EBHighInterestZsFIR_->Fill( dccZsFIRval );
00796     } else{//low interest
00797       ++nEbLI_;
00798       // if(statusCode != 9) EBLowInterestZsFIR_->Fill( dccZsFIRval );
00799       EBLowInterestZsFIR_->Fill( dccZsFIRval );
00800     }
00801     ++nPerDcc_[dccNum(id)-1];
00802     ++nPerRu_[ism-1][itt-1];
00803   }
00804 
00805 }
00806 
00807 void EBSelectiveReadoutTask::anaDigiInit(){
00808   nEb_ = 0;
00809   nEbLI_ = 0;
00810   nEbHI_ = 0;
00811   bzero(nPerDcc_, sizeof(nPerDcc_));
00812   bzero(nRuPerDcc_, sizeof(nRuPerDcc_));
00813   bzero(ebRuActive_, sizeof(ebRuActive_));
00814 
00815   for(int idcc=0; idcc<nECALDcc; idcc++) {
00816     for(int isc=0; isc<nDccChs; isc++) {
00817       nPerRu_[idcc][isc] = 0;
00818     }
00819   }
00820 
00821   for(int ietindex = 0; ietindex < 34; ietindex++ ) {
00822     for(int iptindex = 0; iptindex < 72; iptindex++ ) {
00823       nCryTower[iptindex][ietindex] = 0;
00824     }
00825   }
00826 
00827 }
00828 
00829 EcalTrigTowerDetId
00830 EBSelectiveReadoutTask::readOutUnitOf(const EBDetId& xtalId) const{
00831   return xtalId.tower();
00832 }
00833 
00834 unsigned EBSelectiveReadoutTask::dccNum(const DetId& xtalId) const{
00835   int j;
00836   int k;
00837 
00838   if ( xtalId.det()!=DetId::Ecal ) {
00839     throw cms::Exception("EBSelectiveReadoutTask") << "Crystal does not belong to ECAL";
00840   }
00841 
00842   if(xtalId.subdetId()==EcalBarrel){
00843     EBDetId ebDetId(xtalId);
00844     j = iEta2cIndex(ebDetId.ieta());
00845     k = iPhi2cIndex(ebDetId.iphi());
00846   } else {
00847     throw cms::Exception("EBSelectiveReadoutTask") << "Not ECAL barrel.";
00848   }
00849   int iDcc0 = dccIndex(j,k);
00850   assert(iDcc0>=0 && iDcc0<nECALDcc);
00851   return iDcc0+1;
00852 }
00853 
00854 double EBSelectiveReadoutTask::getEbEventSize(double nReadXtals) const{
00855   double ruHeaderPayload = 0.;
00856   const int nEEDcc = 18;
00857   const int firstEbDcc0 = nEEDcc/2;
00858   for (int iDcc0 = firstEbDcc0; iDcc0 < firstEbDcc0 + nEBDcc; ++iDcc0 ) {
00859     ruHeaderPayload += nRuPerDcc_[iDcc0]*8.;
00860   }
00861   return getDccOverhead(EB)*nEBDcc +
00862          nReadXtals*bytesPerCrystal +
00863          ruHeaderPayload;
00864 }
00865 
00866 int EBSelectiveReadoutTask::dccPhiIndexOfRU(int i, int j) const {
00867   //iEta=i, iPhi=j
00868   //phi edge of a SM is 4 TT
00869   return j/4;
00870 }
00871 
00872 int EBSelectiveReadoutTask::dccIndex(int i, int j) const {
00873     //a SM is 85 crystal long:
00874     int iEtaSM = i/85;
00875     //a SM is 20 crystal wide:
00876     int iPhiSM = j/20;
00877     //DCC numbers start at 9 in the barrel and there 18 DCC/SM
00878     return 9+18*iEtaSM+iPhiSM;
00879 }
00880 
00881 //This implementation  assumes that int is coded on at least 28-bits,
00882 //which in pratice should be always true.
00883 int
00884 EBSelectiveReadoutTask::dccZsFIR(const EcalDataFrame& frame,
00885                                  const std::vector<int>& firWeights,
00886                                  int firstFIRSample,
00887                                  bool* saturated){
00888   const int nFIRTaps = 6;
00889   //FIR filter weights:
00890   const std::vector<int>& w = firWeights;
00891 
00892   //accumulator used to compute weighted sum of samples
00893   int acc = 0;
00894   bool gain12saturated = false;
00895   const int gain12 = 0x01;
00896 
00897   int iWeight = 0;
00898   for(int i = -1; i < nFIRTaps - 1; ++i, ++iWeight){
00899     int iSample(i + firstFIRSample);
00900     if(iSample>=0 && iSample < frame.size()){
00901       EcalMGPASample sample(frame[iSample]);
00902       if(sample.gainId()!=gain12) gain12saturated = true;
00903       LogTrace("DccFir") << (iSample>=firstFIRSample?"+":"") << sample.adc()
00904                          << "*(" << w[iWeight] << ")";
00905       acc+=sample.adc()*w[iWeight];
00906     } else{
00907       edm::LogWarning("DccFir") << __FILE__ << ":" << __LINE__ <<
00908         ": Not enough samples in data frame or 'ecalDccZs1stSample' module "
00909         "parameter is not valid...";
00910     }
00911   }
00912   LogTrace("DccFir") << "\n";
00913   //discards the 8 LSBs
00914   //(shift operator cannot be used on negative numbers because
00915   // the result depends on compilator implementation)
00916   acc = (acc>=0)?(acc >> 8):-(-acc >> 8);
00917   //ZS passed if weighted sum acc above ZS threshold or if
00918   //one sample has a lower gain than gain 12 (that is gain 12 output
00919   //is saturated)
00920 
00921   LogTrace("DccFir") << "acc: " << acc << "\n"
00922                      << "saturated: " << (gain12saturated?"yes":"no") << "\n";
00923 
00924   if(saturated){
00925     *saturated = gain12saturated;
00926   }
00927 
00928   return gain12saturated?std::numeric_limits<int>::max():acc;
00929 }
00930 
00931 std::vector<int>
00932 EBSelectiveReadoutTask::getFIRWeights(const std::vector<double>&
00933                                       normalizedWeights){
00934   const int nFIRTaps = 6;
00935   std::vector<int> firWeights(nFIRTaps, 0); //default weight: 0;
00936   const static int maxWeight = 0xEFF; //weights coded on 11+1 signed bits
00937   for(unsigned i=0; i < std::min((size_t)nFIRTaps,normalizedWeights.size()); ++i){
00938     firWeights[i] = lround(normalizedWeights[i] * (1<<10));
00939     if(std::abs(firWeights[i])>maxWeight){//overflow
00940       firWeights[i] = firWeights[i]<0?-maxWeight:maxWeight;
00941     }
00942   }
00943   return firWeights;
00944 }
00945 
00946 void
00947 EBSelectiveReadoutTask::configFirWeights(std::vector<double> weightsForZsFIR){
00948   bool notNormalized  = false;
00949   bool notInt = false;
00950   for(unsigned i=0; i < weightsForZsFIR.size(); ++i){
00951     if(weightsForZsFIR[i] > 1.) notNormalized = true;
00952     if((int)weightsForZsFIR[i]!=weightsForZsFIR[i]) notInt = true;
00953   }
00954   if(notInt && notNormalized){
00955     throw cms::Exception("InvalidParameter")
00956       << "weigtsForZsFIR paramater values are not valid: they "
00957       << "must either be integer and uses the hardware representation "
00958       << "of the weights or less or equal than 1 and used the normalized "
00959       << "representation.";
00960   }
00961   edm::LogInfo log("DccFir");
00962   if(notNormalized){
00963     firWeights_ = std::vector<int>(weightsForZsFIR.size());
00964     for(unsigned i = 0; i< weightsForZsFIR.size(); ++i){
00965       firWeights_[i] = (int)weightsForZsFIR[i];
00966     }
00967   } else{
00968     firWeights_ = getFIRWeights(weightsForZsFIR);
00969   }
00970 
00971   log << "Input weights for FIR: ";
00972   for(unsigned i = 0; i < weightsForZsFIR.size(); ++i){
00973     log << weightsForZsFIR[i] << "\t";
00974   }
00975 
00976   double s2 = 0.;
00977   log << "\nActual FIR weights: ";
00978   for(unsigned i = 0; i < firWeights_.size(); ++i){
00979     log << firWeights_[i] << "\t";
00980     s2 += firWeights_[i]*firWeights_[i];
00981   }
00982 
00983   s2 = sqrt(s2);
00984   log << "\nNormalized FIR weights after hw representation rounding: ";
00985   for(unsigned i = 0; i < firWeights_.size(); ++i){
00986     log << firWeights_[i] / (double)(1<<10) << "\t";
00987   }
00988 
00989   log <<"\nFirst FIR sample: " << firstFIRSample_;
00990 }
00991