Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SimPmtM16.cxx

Go to the documentation of this file.
00001 #include "SimPmtM16.h"
00002 #include "MessageService/MsgService.h"
00003 #include "SimPmtMaker.h"
00004 #include <cmath>
00005 
00006 // Register this class with the factory.
00007 SimPmtMakerProxy<SimPmtM16> gSimPmtM16Proxy("SimPmtM16");
00008 
00009 CVSID("$Id: SimPmtM16.cxx,v 1.15 2008/11/18 17:31:02 rhatcher Exp $");
00010 
00011 ClassImp(SimPmtM16)
00012 
00013 SimPmtM16::SimPmtM16(PlexPixelSpotId tube, 
00014                      VldContext context,
00015                      TRandom* random)  :
00016   SimPmt(tube,context,random,16,8) 
00017 {
00018 }
00019 
00020 
00021 void SimPmtM16::Print(Option_t* /*option*/) const
00022 {
00023   printf("  SimPmtM16::Print()  -- Tube: %s\n",fTube.AsString("t"));
00024 
00025  // Iterate over all time buckets.
00026   for(SimPmtBucketIterator it(*this); !it.End(); it.Next()) {
00027   int ibucket = it.BucketId();
00028   
00029   printf("  Time bucket %d:\n",ibucket);
00030 
00031   // output:
00032   // pixels:  16 15 14 13   fibres:  8 7 6
00033   //          12 11 10  9             5 4
00034   //           8  7  6  5            3 2 1
00035   //           4  3  2  1
00036   printf("  Photoelectrons(Npe)\n");
00037   for(int row=0; row < 4; row++) {
00038     printf("  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f\n",
00039            GetPe(16-row*4,8,ibucket),  GetPe(16-row*4,7,ibucket),  GetPe(16-row*4,6,ibucket),
00040            GetPe(15-row*4,8,ibucket),  GetPe(15-row*4,7,ibucket),  GetPe(15-row*4,6,ibucket),
00041            GetPe(14-row*4,8,ibucket),  GetPe(14-row*4,7,ibucket),  GetPe(14-row*4,6,ibucket),
00042            GetPe(13-row*4,8,ibucket),  GetPe(13-row*4,7,ibucket),  GetPe(13-row*4,6,ibucket));
00043 
00044     printf("     %5.0f %5.0f        %5.0f %5.0f        %5.0f %5.0f        %5.0f %5.0f\n",
00045            GetPe(16-row*4,5,ibucket),  GetPe(16-row*4,4,ibucket),
00046            GetPe(15-row*4,5,ibucket),  GetPe(15-row*4,4,ibucket),
00047            GetPe(14-row*4,5,ibucket),  GetPe(14-row*4,4,ibucket),
00048            GetPe(13-row*4,5,ibucket),  GetPe(13-row*4,4,ibucket));
00049     
00050     printf("  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f  %5.0f %5.0f %5.0f\n",
00051            GetPe(16-row*4,3,ibucket),  GetPe(16-row*4,2,ibucket),  GetPe(16-row*4,1,ibucket),
00052            GetPe(15-row*4,3,ibucket),  GetPe(15-row*4,2,ibucket),  GetPe(15-row*4,1,ibucket),
00053            GetPe(14-row*4,3,ibucket),  GetPe(14-row*4,2,ibucket),  GetPe(14-row*4,1,ibucket),
00054            GetPe(13-row*4,3,ibucket),  GetPe(13-row*4,2,ibucket),  GetPe(13-row*4,1,ibucket));
00055            
00056     printf("\n");
00057   }
00058   
00059   printf("  Charges (fC)\n");
00060   for(int row=0; row < 4; row++) {
00061     // printf("    %7.1f %7.1f %7.1f %7.1f\n",
00062     printf("    %f \t %f \t %f \t %f\n",
00063            GetCharge(16-row*4,ibucket)/Munits::fC, GetCharge(15-row*4,ibucket)/Munits::fC,
00064            GetCharge(14-row*4,ibucket)/Munits::fC, GetCharge(13-row*4,ibucket)/Munits::fC);
00065   }
00066   
00067   printf("\n");
00068   }
00069 }
00070 
00071 
00072 Float_t SimPmtM16::GenChargeFromPE( Int_t pixel, Int_t spot, Float_t pe )
00073 {
00074   //
00075   // Does a single charge simulation.
00076   //
00077   
00078   // First version, by Nathaniel.
00079   // Uses the generalized poisson to get the job done.
00080 
00081   if(pe<=0) return 0;
00082 
00083   // The secondary emmission ratio is directly related to the width of the 1pe peak.
00084   Double_t gain, width;
00085   GetGainAndWidth(pixel,spot,gain,width);
00086   
00087   // Secondary emmission ratio is (mean*mean)/(rms*rms). 'width' is fractional width, so:
00088   Float_t secemm = 1/(width*width);
00089 
00090   // Choose a random number from the spectrum with a peak at the number of expected 2nary pes.
00091   Float_t mean2ndaryPe = pe * secemm;
00092   Float_t secondary_pe = RandomGenPoisson(mean2ndaryPe);
00093  
00094  // convert this into charge. 
00095   Float_t charge = (secondary_pe / secemm)       // Charge in PE-units
00096     * gain
00097     * Munits::e_SI;               // e to charge
00098   
00099 
00100   MSG("DetSim",Msg::kVerbose) << "SimPmtM16: pe to charge: " 
00101                               << pe << "\t"
00102                               << secemm << "\t"
00103                               << secondary_pe << "\t"
00104                               << gain << "\t"
00105                               << charge << endl;
00106   return charge;
00107 }
00108 
00109 Float_t SimPmtM16::GenDarkNoiseCharge( Int_t /* pixel */, Float_t /* timeWindow */ )
00110 {
00111   //
00112   // Dark noise simulation.
00113   //
00114   // Return the charge (in fC) that results from opening an integration gate of duration timeWindow (in Munits).
00115   // (This should return zero most of the time).
00116   //
00117   
00118   // No simulation yet.
00119   return 0; 
00120 }
00121 
00122 
00123 Float_t SimPmtM16::GenNonlinearCharge( Int_t /* pixel */,  Float_t inCharge ) 
00124 {
00125   //
00126   // Nonlinearity Simulation.
00127   //
00128   // Given a charge on the anode, this routine applies
00129   // the nonlinearity for the PMT to give a new output charge.
00130   // 
00131   // For a completely linear response, return inCharge.
00132   
00133   return inCharge; 
00134 }
00135 
00136 
00137 // The following is pretty much copied-and-pasted out of
00138 // m16_xt.F, the xtalk simulation put in by Mike Kordosky
00139 // in GMINOS.
00140 
00141 const float m16_opt_bc[] = { 0, 4.1E-4, 30.8E-4, 7.1E-4,
00142                      15.7E-4,         43.8E-4,
00143                      4.4E-4, 44.4E-4, 8.6E-4,
00144                      0.0,     0.0,    0.0};
00145 const float m16_ul_rprob[] = { 0, 1.0351, 1.40591, 2.51808,
00146                        1.0000, 1.3926,
00147                        0.939646, 1.05889, 1.33843};
00148 const float m16_u_rprob[] = { 0, 1.92966, 2.08835, 1.93475,
00149                       1.0000, 1.01693,
00150                       0.581402, 0.58964, 0.548125};
00151 const float m16_ur_rprob[] = { 0, 1.77202, 1.10947, 0.881364,
00152                        1.0000, 0.869394,
00153                        1.02619, 0.902475, 0.821414};
00154 const float m16_l_rprob[] = { 0, 0.742614, 1.46936, 4.88177,
00155                       1.0000, 2.72021,
00156                       0.80697, 1.495, 4.89158};
00157 const float m16_r_rprob[] = { 0, 1.69269, 0.626856, 0.372045,
00158                       1.0000, 0.489508,
00159                       1.68536, 0.642841, 0.391364};
00160 const float m16_dl_rprob[] = { 0, 0.841386, 1.04104, 1.71787,
00161                        1.0000, 1.79258,
00162                        1.28237, 1.79684, 4.16197};
00163 const float m16_d_rprob[] = { 0, 0.450814, 0.469413, 0.428049,
00164                       1.0000, 1.00814,
00165                       2.0646, 2.23663, 2.11148};
00166 const float m16_dr_rprob[] = { 0, 0.964592, 0.65102, 0.561097,
00167                        1.0000, 0.815038,
00168                        2.25732, 1.13462, 0.816332};
00169 const float m16_wd_rprob[] = { 0, 1.0, 1.0, 1.0,
00170                        1.0, 1.0,
00171                        1.0, 1.0, 1.0};
00172 const float m16_pd_rprob[] = { 0, 1.0, 1.0, 1.0,
00173                        1.0, 1.0,
00174                        1.0, 1.0, 1.0};
00175 const float m16_o_rprob[] = { 0, 1.0, 1.0, 1.0,
00176                       1.0, 1.0,
00177                       1.0, 1.0, 1.0};
00178 
00179 
00180 Float_t SimPmtM16::GenOpticalCrosstalk( Int_t injPixel, Int_t injSpot,
00181                                    Int_t xPixel, Float_t injPE ) 
00182 {
00183   // 
00184   // Optical crosstalk simulation.
00185   //
00186   // If injPE photoelectrons of light are injected into injPixel and injSpot,
00187   // this routine returns the number of the photoelectrons that will leak into
00188   // the xtalkPixel.  Note that this should probably be a random integer..
00189   //
00190   
00191   // Return 0 for no crosstalk.
00192     //   Pixels:
00193   //   4  3  2  1
00194   //   8  7  6  5
00195   //   12 11 10 9
00196   //   16 15 14 13
00197 
00198   //     8 border pixels:
00199   //     1 2 3
00200   //     4 X 5   (X = hit pixel)
00201   //     6 7 8
00202   //
00203   //     All others:
00204   //     9 = Far neighbor going with dynode structure
00205   //     10 = Far neighbor going perp to dynode structure
00206   //     11 = Far diagonal neighbor
00207   //     0 = hit_pixel.eq.xt_pixel ! an error
00208   if(injPixel==xPixel) return 0;
00209   
00210   Float_t coeff;
00211   Float_t rprob;
00212 
00213   if(xPixel==(injPixel-4)) { // 2
00214     coeff = m16_opt_bc[2];
00215     rprob = m16_u_rprob[injSpot];
00216   }
00217   else if(xPixel==(injPixel+4)) { // 7
00218     coeff = m16_opt_bc[7];
00219     rprob = m16_d_rprob[injSpot];
00220   }
00221   else if((xPixel==(injPixel+1))&&(injPixel%4!=0)) { // 4
00222     coeff = m16_opt_bc[4];
00223     rprob = m16_l_rprob[injSpot];
00224   }
00225   else if((xPixel==(injPixel-1))&&((injPixel-1)%4!=0)) { // 5
00226     coeff = m16_opt_bc[5];
00227     rprob = m16_r_rprob[injSpot];
00228   }
00229   else if((injPixel%4!=0)&&(xPixel==injPixel-3)) { //1
00230     coeff = m16_opt_bc[1];
00231     rprob = m16_ul_rprob[injSpot];
00232   }
00233   else if(((injPixel-1)%4!=0)&&(xPixel==injPixel-5)) {  // 3
00234     coeff = m16_opt_bc[3];
00235     rprob = m16_ur_rprob[injSpot];
00236   }
00237   else if((injPixel%4!=0)&&(xPixel==injPixel+5)) { // 6
00238     coeff = m16_opt_bc[6];
00239     rprob = m16_dl_rprob[injSpot];
00240   }
00241   else if(((injPixel-1)%4!=0)&&(xPixel==injPixel+3)) {  // 8
00242     coeff = m16_opt_bc[8];
00243     rprob = m16_dr_rprob[injSpot];
00244   }
00245   else if( abs(injPixel-xPixel)%4 == 0 ) { // 9
00246     coeff = m16_opt_bc[9];
00247     rprob = m16_wd_rprob[injSpot];
00248   } 
00249   else if(((injPixel-1)%4) == ((xPixel-1)%4)) { // 10
00250     coeff = m16_opt_bc[10];
00251     rprob = m16_pd_rprob[injSpot];
00252   }
00253   else{ // 11
00254     coeff = m16_opt_bc[11];
00255     rprob = m16_o_rprob[injSpot];
00256   }
00257 
00258   // correct poisson coefficient for pixel spot
00259   // dependence
00260   const Float_t ref_pe = 35.0;
00261   const Float_t m16_opt_xt_scale = 2.0;
00262 
00263   Float_t cor1_coeff = -(1.0/ref_pe)*
00264     log(1.0-rprob*(1.0-exp(-coeff*ref_pe)));
00265   // correct poisson coefficient for overall scale
00266   Float_t cor2_coeff = -(1.0/ref_pe)*
00267     log(1.0-m16_opt_xt_scale*(1.0-exp(-cor1_coeff*ref_pe)));
00268   // calculate xt probability
00269 
00270   // HACK HACK HACK
00271   // This adds just a wee little bit of crosstalk to any
00272   // pair of pixel/spots.  Total addition is ~1 percent total
00273   // crosstalk, but across the whole face of the pmt.
00274   // cor2_coeff += 0.0005;
00275   
00276   // Scale it.
00277   cor2_coeff *= fsPmtScaleOpticalCrosstalk;
00278 
00279   return (Float_t)fRandom->Poisson(cor2_coeff * injPE);
00280 }
00281 
00282 Float_t SimPmtM16::GenElectricalCrosstalk( Int_t /* injPixel */,
00283                                            Int_t /* xtalkPixel */, 
00284                                            Float_t /* injCharge */ ) 
00285 {
00286   //
00287   // Electrical crosstalk simulation.
00288   //
00289   // If inCharge femtoCoulombs of charge are seen on the anode of injPixel, then
00290   // this returns the quantity of charge that will be leaked to xtalkPixel.
00291   // This may be a random quantity, or a fixed fraction, depending on the model.
00292 
00293  return 0; 
00294 }
00295 

Generated on Mon Feb 15 11:07:37 2010 for loon by  doxygen 1.3.9.1