CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/SimGeneral/NoiseGenerators/src/GaussianTailNoiseGenerator.cc

Go to the documentation of this file.
00001 #include "SimGeneral/NoiseGenerators/interface/GaussianTailNoiseGenerator.h"
00002 #include "CLHEP/Random/RandPoissonQ.h"
00003 #include "CLHEP/Random/RandGaussQ.h"
00004 #include "CLHEP/Random/RandFlat.h"
00005 
00006 #include <math.h>
00007 
00008 #include <gsl/gsl_sf_erf.h>
00009 #include <gsl/gsl_sf_result.h>
00010 
00011 GaussianTailNoiseGenerator::GaussianTailNoiseGenerator(CLHEP::HepRandomEngine& eng ) :
00012   gaussDistribution_(eng),
00013   poissonDistribution_(eng),
00014   flatDistribution_(eng)
00015 {
00016   // we have two cases: 512 and 768 channels
00017   // other cases are not allowed so far (performances issue)
00018   for(unsigned int i=0;i<512;++i) channel512_[i]=i;
00019   for(unsigned int i=0;i<768;++i) channel768_[i]=i;
00020 }
00021 
00022 // this version is used by pixel
00023 void GaussianTailNoiseGenerator::generate(int NumberOfchannels, 
00024                                           float threshold, 
00025                                           float noiseRMS, 
00026                                           std::map<int,float, std::less<int> >& theMap ) {
00027 
00028    // Gaussian tail probability
00029   gsl_sf_result result;
00030   int status = gsl_sf_erf_Q_e(threshold, &result);
00031 
00032   if (status != 0) std::cerr<<"GaussianTailNoiseGenerator::could not compute gaussian tail probability for the threshold chosen"<<std::endl;
00033 
00034   float probabilityLeft = result.val;  
00035   float meanNumberOfNoisyChannels = probabilityLeft * NumberOfchannels;
00036   int numberOfNoisyChannels = poissonDistribution_.fire(meanNumberOfNoisyChannels);
00037 
00038   float lowLimit = threshold * noiseRMS;
00039   for (int i = 0; i < numberOfNoisyChannels; i++) {
00040 
00041     // Find a random channel number    
00042     int theChannelNumber = (int)flatDistribution_.fire(NumberOfchannels);
00043 
00044     // Find random noise value
00045     double noise = generate_gaussian_tail(lowLimit, noiseRMS);
00046               
00047     // Fill in map
00048     theMap[theChannelNumber] = noise;
00049     
00050   }
00051 }
00052 
00053 // this version is used by strips
00054 void GaussianTailNoiseGenerator::generate(int NumberOfchannels, 
00055                                           float threshold, 
00056                                           float noiseRMS, 
00057                                           std::vector<std::pair<int,float> > &theVector ) {
00058   // Compute number of channels with noise above threshold
00059   // Gaussian tail probability
00060   gsl_sf_result result;
00061   int status = gsl_sf_erf_Q_e(threshold, &result);
00062   if (status != 0) std::cerr<<"GaussianTailNoiseGenerator::could not compute gaussian tail probability for the threshold chosen"<<std::endl;
00063   double probabilityLeft = result.val;  
00064   double meanNumberOfNoisyChannels = probabilityLeft * NumberOfchannels;
00065   int numberOfNoisyChannels = poissonDistribution_.fire(meanNumberOfNoisyChannels);
00066   if(numberOfNoisyChannels>NumberOfchannels) numberOfNoisyChannels=NumberOfchannels;
00067 
00068   // Compute the list of noisy channels
00069   theVector.reserve(numberOfNoisyChannels);
00070   float lowLimit = threshold * noiseRMS;
00071   int*  channels = getRandomChannels(numberOfNoisyChannels,NumberOfchannels);
00072   
00073   for (int i = 0; i < numberOfNoisyChannels; i++) {
00074     // Find random noise value
00075     double noise = generate_gaussian_tail(lowLimit, noiseRMS);
00076     // Fill in the vector
00077     theVector.push_back(std::pair<int, float>(channels[i], noise));
00078   }
00079 }
00080 
00081 /*
00082 // used by strips in VR mode
00083 void GaussianTailNoiseGenerator::generateRaw(int NumberOfchannels, 
00084                                              float noiseRMS, 
00085                                              std::vector<std::pair<int,float> > &theVector ) {
00086   theVector.reserve(NumberOfchannels);
00087   for (int i = 0; i < NumberOfchannels; i++) {
00088     // Find random noise value
00089     float noise = gaussDistribution_.fire(0.,noiseRMS);
00090     // Fill in the vector
00091     theVector.push_back(std::pair<int, float>(i,noise));
00092   }
00093 }
00094 */
00095 
00096 // used by strips in VR mode
00097 void GaussianTailNoiseGenerator::generateRaw(float noiseRMS,
00098                                              std::vector<double> &theVector ) {
00099   // it was shown that a complex approach, inspired from the ZS case,
00100   // does not allow to gain much. 
00101   // A cut at 2 sigmas only saves 25% of the processing time, while the cost
00102   // in terms of meaning is huge.
00103   // We therefore use here the trivial approach (as in the early 2XX cycle)
00104   unsigned int numberOfchannels = theVector.size();
00105   for (unsigned int i = 0; i < numberOfchannels; ++i) {
00106     if(theVector[i]==0) theVector[i] = gaussDistribution_.fire(0.,noiseRMS);
00107   }
00108 }
00109 
00110 int*
00111 GaussianTailNoiseGenerator::getRandomChannels(int numberOfNoisyChannels, int numberOfchannels) {
00112   if(numberOfNoisyChannels>numberOfchannels) numberOfNoisyChannels = numberOfchannels;
00113   int* array = channel512_;
00114   if(numberOfchannels==768) array = channel768_;
00115   int theChannelNumber;
00116   for(int j=0;j<numberOfNoisyChannels;++j) {
00117     theChannelNumber = (int)flatDistribution_.fire(numberOfchannels-j)+j;
00118     // swap the two array elements... this is optimized by the compiler
00119     int b = array[j];
00120     array[j] = array[theChannelNumber];
00121     array[theChannelNumber] = b;
00122   }
00123   return array;
00124 }
00125 
00126 double
00127 GaussianTailNoiseGenerator::generate_gaussian_tail(const double a, const double sigma){
00128   /* Returns a gaussian random variable larger than a
00129    * This implementation does one-sided upper-tailed deviates.
00130    */
00131   
00132   double s = a/sigma;
00133   
00134   if (s < 1){
00135     /*
00136       For small s, use a direct rejection method. The limit s < 1
00137       can be adjusted to optimise the overall efficiency 
00138     */
00139     double x;
00140     
00141     do{
00142       x = gaussDistribution_.fire(0.,1.0);
00143     }
00144     while (x < s);
00145     return x * sigma;
00146     
00147   }else{
00148     
00149     /* Use the "supertail" deviates from the last two steps
00150      * of Marsaglia's rectangle-wedge-tail method, as described
00151      * in Knuth, v2, 3rd ed, pp 123-128.  (See also exercise 11, p139,
00152      * and the solution, p586.)
00153      */
00154     
00155     double u, v, x;
00156     
00157     do{
00158       u = flatDistribution_.fire();
00159       do{
00160         v = flatDistribution_.fire();
00161       }while (v == 0.0);
00162       x = sqrt(s * s - 2 * log(v));
00163     }
00164     while (x * u > s);
00165     return x * sigma;
00166   }
00167 }