CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC4_patch1/src/SimCalorimetry/HcalSimAlgos/src/HPDNoiseLibraryReader.cc

Go to the documentation of this file.
00001 
00002 // --------------------------------------------------------
00003 // A class to read HPD noise from the library.
00004 // The deliverable of the class is the collection of
00005 // noisy HcalDetIds with associated noise in units of fC for
00006 // 10 time samples. During the library production a higher
00007 // theshold is used to find a noisy HPD. A lower threshold is
00008 // used to eliminate adding unnecessary quite channels to HPD 
00009 // noise event collection. Therefore user may not see whole 18 
00010 // channels for noisy HPD.
00011 //
00012 // Project: HPD noise library reader
00013 // Author: T.Yetkin University of Iowa, Feb. 7, 2008
00014 // $Id: HPDNoiseLibraryReader.cc,v 1.5 2012/06/07 18:12:43 wmtan Exp $
00015 // --------------------------------------------------------
00016 
00017 #include "SimCalorimetry/HcalSimAlgos/interface/HPDNoiseLibraryReader.h"
00018 
00019 using namespace edm;
00020 using namespace std;
00021 
00022 HPDNoiseLibraryReader::HPDNoiseLibraryReader(const edm::ParameterSet & iConfig)
00023 :theDischargeNoiseRate(0),
00024 theIonFeedbackFirstPeakRate(0),
00025 theIonFeedbackSecondPeakRate(0),
00026 theNoisyPhi(0),
00027 theRandFlat(0),
00028 theRandGaussQ(0) {
00029     setRandomEngine();
00030 
00031     ParameterSet pSet = iConfig.getParameter < edm::ParameterSet > ("HPDNoiseLibrary");
00032     FileInPath filepath = pSet.getParameter < edm::FileInPath > ("FileName");
00033 
00034     theHPDName = pSet.getUntrackedParameter < string > ("HPDName", "HPD");
00035     string pName = filepath.fullPath();
00036 
00037     if (pName.find(".") == 0)
00038         pName.erase(0, 2);
00039     theReader = new HPDNoiseReader(pName);
00040     theNames = theReader->allNames();   // all 72x2 HPDs
00041 
00042     fillRates();
00043 }
00044 
00045 HPDNoiseLibraryReader::~HPDNoiseLibraryReader() {
00046     if (theRandFlat)
00047         delete theRandFlat;
00048 
00049     if (theRandGaussQ)
00050         delete theRandGaussQ;
00051 }
00052 
00053 void HPDNoiseLibraryReader::initializeServices() {
00054     if (not edmplugin::PluginManager::isAvailable()) {
00055         edmplugin::PluginManager::configure(edmplugin::standard::config());
00056     }
00057 
00058     std::string config =
00059       "process CorrNoise = {"
00060       "service = RandomNumberGeneratorService" "{" "untracked uint32 sourceSeed = 123456789" "}" "}";
00061 
00062     // create the services
00063     edm::ServiceToken tempToken = edm::ServiceRegistry::createServicesFromConfig(config);
00064 
00065     // make the services available
00066     edm::ServiceRegistry::Operate operate(tempToken);
00067 }
00068 void HPDNoiseLibraryReader::setRandomEngine() {
00069     edm::Service < edm::RandomNumberGenerator > rng;
00070     if (!rng.isAvailable()) {
00071         throw cms::Exception("Configuration") << "HcalHPDNoiseLibrary requires the RandomNumberGeneratorService\n"
00072           "which is not present in the configuration file.  You must add the service\n"
00073           "in the configuration file or remove the modules that require it.";
00074     }
00075     setRandomEngine(rng->getEngine());
00076 }
00077 void HPDNoiseLibraryReader::setRandomEngine(CLHEP::HepRandomEngine & engine) {
00078     if (theRandGaussQ)
00079         delete theRandGaussQ;
00080 
00081     if (theRandFlat)
00082         delete theRandFlat;
00083 
00084     theRandGaussQ = new CLHEP::RandGaussQ(engine);
00085     theRandFlat = new CLHEP::RandFlat(engine);
00086 }
00087 
00088 void HPDNoiseLibraryReader::fillRates() {
00089     for (size_t i = 0; i < theNames.size(); ++i) {
00090         HPDNoiseReader::Handle hpdObj = theReader->getHandle(theNames[i]);
00091         if (theReader->valid(hpdObj)) {
00092             theDischargeNoiseRate.push_back(theReader->dischargeRate(hpdObj));
00093             theIonFeedbackFirstPeakRate.push_back(theReader->ionFeedbackFirstPeakRate(hpdObj));
00094             theIonFeedbackSecondPeakRate.push_back(theReader->ionFeedbackSecondPeakRate(hpdObj));
00095         } else {
00096             std::cerr << "HPD Handle Object is not valid!" << endl;
00097         }
00098     }
00099 }
00100 
00101 HPDNoiseData *HPDNoiseLibraryReader::getNoiseData(int iphi) {
00102 
00103 
00104     HPDNoiseData *data = 0; //data->size() is checked wherever actually used  
00105 
00106     // make sure that iphi from HcalDetId is found noisy at first.
00107     // In other words, be sure that iphi is in the collection of
00108     // noisy Phis
00109     if (!(IsNoiseApplicable(iphi)))         
00110         return data;
00111 
00112     int zside = 1;
00113 
00114     if (iphi > 72) {
00115         iphi = iphi - 72;
00116         zside = -1;
00117     }
00118     std::string name;
00119     if (zside == 1) {
00120         name = "ZPlus" + theHPDName + itos(iphi);
00121     } else if (zside == -1) {
00122         name = "ZMinus" + theHPDName + itos(iphi);
00123     } else {
00124         cerr << " ZSide Calculation Error." << endl;
00125     }
00126     HPDNoiseReader::Handle hpdObj = theReader->getHandle(name);
00127     if (theReader->valid(hpdObj)) {
00128         // randomly select one entry from library for this HPD
00129         unsigned long entry = theRandFlat->fireInt(theReader->totalEntries(hpdObj));
00130 
00131         theReader->getEntry(hpdObj, entry, &data);
00132     } else {
00133         std::cerr << " HPD Name in the library is not valid." << std::endl;
00134     }
00135     return data;
00136 }
00137 
00138 
00139 void HPDNoiseLibraryReader::getNoisyPhis() {
00140 
00141     clearPhi();
00142     double rndm[144];
00143 
00144     theRandFlat->shootArray(144, rndm);
00145 
00146     for (int i = 0; i < 144; ++i) {
00147         if (rndm[i] < theDischargeNoiseRate[i]) {
00148             theNoisyPhi.push_back(i + 1);
00149         }
00150     }
00151 }
00152 
00153 void HPDNoiseLibraryReader::getBiasedNoisyPhis() {
00154 
00155     clearPhi();
00156     double rndm[144];
00157 
00158     theRandFlat->shootArray(144, rndm);
00159     for (int i = 0; i < 144; ++i) {
00160         if (rndm[i] < theDischargeNoiseRate[i]) {
00161             theNoisyPhi.push_back(i + 1);
00162         }
00163     }
00164     // make sure one HPD is always noisy
00165     if (theNoisyPhi.size() == 0) {
00166         int iPhi = (theRandFlat->fireInt(144)) + 1; // integer from interval [0-144[ + 1
00167 
00168         theNoisyPhi.push_back(iPhi);
00169     }
00170 }
00171 
00172 vector <pair<HcalDetId, const float *> >HPDNoiseLibraryReader::getNoisyHcalDetIds() {
00173 
00174     vector <pair< HcalDetId, const float *> >result;
00175 
00176     // decide which phi are noisy by using noise rates 
00177     // and random numbers (to be called for each event)
00178     getNoisyPhis();
00179     for (int i = 0; i < int (theNoisyPhi.size()); ++i) {
00180         int iphi = theNoisyPhi[i];
00181         HPDNoiseData *data;
00182 
00183         data = getNoiseData(iphi);
00184         for (unsigned int i = 0; i < data->size(); ++i) {
00185 
00186             result.emplace_back(data->getDataFrame(i).id(), data->getDataFrame(i).getFrame());
00187         }
00188     }
00189     return result;
00190 }
00191 
00192 vector <pair<HcalDetId, const float *> >HPDNoiseLibraryReader::getNoisyHcalDetIds(int timeSliceId) 
00193 {
00194     vector <pair< HcalDetId, const float *> >result;
00195     // decide which phi are noisy by using noise rates 
00196     // and random numbers (to be called for each event)
00197     getNoisyPhis();
00198     for (int i = 0; i < int (theNoisyPhi.size()); ++i) {
00199         int iphi = theNoisyPhi[i];
00200         HPDNoiseData *data;
00201 
00202         data = getNoiseData(iphi);
00203         for (unsigned int i = 0; i < data->size(); ++i) {
00204             float* data_ = const_cast<float*>(data->getDataFrame(i).getFrame());
00205             shuffleData(timeSliceId, data_);
00206             const float* _data_ =const_cast<const float*>(data_);
00207             result.emplace_back(data->getDataFrame(i).id(), _data_);
00208         }
00209     }
00210     return result;
00211 
00212 }
00213 vector < pair < HcalDetId, const float *> >HPDNoiseLibraryReader::getBiasedNoisyHcalDetIds(int timeSliceId) {
00214 
00215     vector < pair < HcalDetId, const float *> >result;
00216 
00217     // decide which phi are noisy by using noise rates 
00218     // and random numbers (to be called for each event)
00219     // at least one Phi is always noisy.
00220     getBiasedNoisyPhis();
00221     for (int i = 0; i < int (theNoisyPhi.size()); ++i) {
00222         int iphi = theNoisyPhi[i];
00223         HPDNoiseData *data;
00224 
00225         data = getNoiseData(iphi);
00226         for (unsigned int i = 0; i < data->size(); ++i) {
00227             float* data_ = const_cast<float*>(data->getDataFrame(i).getFrame());
00228             shuffleData(timeSliceId, data_);
00229             const float* _data_ =const_cast<const float*>(data_);
00230             result.emplace_back(data->getDataFrame(i).id(), _data_);
00231         }
00232     }
00233     return result;
00234 }
00235 
00236 vector < pair < HcalDetId, const float *> >HPDNoiseLibraryReader::getBiasedNoisyHcalDetIds() {
00237 
00238     vector < pair < HcalDetId, const float *> >result;
00239 
00240     // decide which phi are noisy by using noise rates 
00241     // and random numbers (to be called for each event)
00242     // at least one Phi is always noisy.
00243     getBiasedNoisyPhis();
00244     for (int i = 0; i < int (theNoisyPhi.size()); ++i) {
00245         int iphi = theNoisyPhi[i];
00246         HPDNoiseData *data;
00247 
00248         data = getNoiseData(iphi);
00249         for (unsigned int i = 0; i < data->size(); ++i) {
00250             result.emplace_back(data->getDataFrame(i).id(), data->getDataFrame(i).getFrame());
00251         }
00252     }
00253     return result;
00254 }
00255 
00256 double HPDNoiseLibraryReader::getIonFeedbackNoise(HcalDetId id, double energy, double bias) {
00257 
00258     // constants for simulation/parameterization
00259     double pe2Charge = 0.333333;    // fC/p.e.
00260     double GeVperfC = 0.177;    // in unit GeV/fC and this will be updated when it start reading from DB.
00261     double PedSigma = 0.8;
00262     double noise = 0.;          // fC
00263 
00264     int iphi = (id.ieta() > 0) ? (id.iphi()) : (id.iphi() + 72);
00265     double rateInTail = theIonFeedbackFirstPeakRate[iphi - 1];
00266     double rateInSecondTail = theIonFeedbackSecondPeakRate[iphi - 1];
00267 
00268     if (bias != 0.) {
00269         rateInTail = rateInTail * bias;
00270         rateInSecondTail = rateInSecondTail * bias;
00271     } else {
00272         edm::LogError("HPDNoise") << "HPDNoise: ion feedback error (biased or unbiased selection)." << bias << " failed";
00273         throw cms::Exception("Unknown", "biase selection ")
00274         << "Usage of " << bias << " fails\n";
00275     }
00276     double Charge = energy / GeVperfC;
00277 
00278     // three gauss fit is applied to data to get ion feedback distribution
00279     // the script is at neutralino: /home/tyetkin/work/hpd_noise/PlotFromPelin.C
00280     // a new fit woth double-sigmoids is under way.
00281     // parameters (in fC)
00282     // first gaussian
00283     // double p0 = 9.53192e+05;
00284     // double p1 = -3.13653e-01;
00285     // double p2 = 2.78350e+00;
00286 
00287     // second gaussian
00288     // double p3 = 2.41611e+03;
00289     double p4 = 2.06117e+01;
00290     double p5 = 1.09239e+01;
00291 
00292     // third gaussian
00293     // double p6 = 3.42793e+01;
00294     double p7 = 5.45548e+01;
00295     double p8 = 1.59696e+01;
00296 
00297     if (Charge > 3 * PedSigma) {    // 3 sigma away from pedestal mean
00298         int npe = int (Charge / pe2Charge);
00299         double a = 0.;
00300         double b = 0.;
00301 
00302         for (int j = 0; j < npe; ++j) {
00303             double probability = theRandFlat->shoot();
00304 
00305             if (probability < rateInTail) { // total tail
00306                 if (probability < rateInSecondTail) {   // second tail
00307                     Rannor(a, b);
00308                     noise += b * p8 + p7;
00309                 } else {
00310                     Rannor(a, b);
00311                     noise += b * p5 + p4;
00312                 }
00313             }
00314         }
00315         // add pedestal 
00316         if (noise > 0.)
00317             noise += theRandGaussQ->fire(0, 2 * PedSigma);
00318     }
00319     return (noise * GeVperfC);  // returns noise in GeV.
00320 
00321 }
00322 
00323 bool HPDNoiseLibraryReader::IsNoiseApplicable(int iphi) {
00324 
00325     bool isAccepted = false;
00326     vector < int >::iterator phi_iter;
00327 
00328     phi_iter = find(theNoisyPhi.begin(), theNoisyPhi.end(), iphi);
00329     if (phi_iter != theNoisyPhi.end()) {
00330         isAccepted = true;
00331     }
00332     return isAccepted;
00333 }
00334 void HPDNoiseLibraryReader::shuffleData(int timeSliceId, float* &data)
00335 {
00336    if(timeSliceId == -1 || (timeSliceId>=10)) return;
00337    //make a local copy of input data
00338    float Data[10] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.};
00339    for(int i=0;i<10;++i){
00340        Data[i] = data[i];
00341    }
00342    int ts_max = -1;
00343    float max = -999.;
00344    for(int i=0;i<10;++i){
00345        if(Data[i]>max){
00346            max = data[i];
00347            ts_max = i;
00348        }
00349    }
00350    if((ts_max == -1)){//couldn't find ts_max, return the same value.
00351        return;
00352    }else{
00353        // always shift the noise to the right by putting zeroes to the previous slices.
00354        // the noise is pedestal subtracted. 0 value is acceptable.
00355        int k = -1;
00356        for(int i=0;i<10;++i){
00357            data[i] = 0.;
00358            int newIdx = timeSliceId+k;
00359            float dd = 0.;
00360            if(newIdx < 10){
00361                data[newIdx] = Data[ts_max+k];
00362                dd = Data[ts_max+k];
00363                i = newIdx;
00364            }
00365            data[i] = dd;
00366            ++k;
00367        }
00368                                                                                                            
00369    }
00370 }
00371 
00372 //I couldn't find Rannor in CLHEP/Random. For now, use it from ROOT (copy/paste) by little modification.
00373 void HPDNoiseLibraryReader::Rannor(double &a, double &b) {
00374     double r,
00375       x,
00376       y,
00377       z;
00378 
00379     y = theRandFlat->shoot();
00380     z = theRandFlat->shoot();
00381     x = z * 6.28318530717958623;
00382     r = TMath::Sqrt(-2 * TMath::Log(y));
00383     a = r * TMath::Sin(x);
00384     b = r * TMath::Cos(x);
00385 }
00386 string HPDNoiseLibraryReader::itos(int i) {
00387     stringstream s;
00388 
00389     s << i;
00390     return s.str();
00391 }
00392 
00393 void HPDNoiseLibraryReader::clearPhi() {
00394     theNoisyPhi.clear();
00395 }