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

SimVaTimedElectronics.cxx

Go to the documentation of this file.
00001 #include <TMath.h>
00002 #include "MessageService/MsgService.h"
00003 #include "Digitization/DigiSignal.h"
00004 #include "SimVaTimedElectronics.h"
00005 #include "SimElecMaker.h"
00006 #include "Calibrator/Calibrator.h"
00007 
00008 // Register this class with the factory.
00009 SimElecMakerProxy<SimVaTimedElectronics> gSimVaTimedElec("SimVaTimedElectronics");
00010 
00011 CVSID("$Id: SimVaTimedElectronics.cxx,v 1.10 2007/02/07 16:08:33 rodriges Exp $");
00012 
00013 ClassImp(SimVaTimedElectronics)
00014 
00015 SimVaTimedElectronics::SimVaTimedElectronics(  VldContext context, TRandom* random )
00016   : SimVaElectronics( context, random ),
00017     fVaShapingTime(500.*Munits::ns)
00018 {
00019 }
00020 
00021 void SimVaTimedElectronics::Config( Registry& config )
00022 {
00023   // Modify the configuration.
00024   //
00025   // Use this method to set static members with the class configuration.
00026   config.Get("vaShapingTime",fVaShapingTime);
00027   SimVaElectronics::Config(config);
00028 }
00029 
00030 
00031 void SimVaTimedElectronics::ReadoutDetector( SimPmtList& pmtList )
00032 {
00033   PlexHandle plex(fContext);
00034   
00035   // For timing-cut version of varc pretrigger.
00036   std::map<int,std::vector<double> > varcTrigTimes;
00037   std::map<int,std::vector<double> >::iterator it;
00038   
00039   // Put our PMTs into pseudo-VARCs (vmms), then deal with each varc (or vmm).
00040   std::map<int,vector<SimPmt*> > varcs;
00041   std::map<int,vector<SimPmt*> >::iterator varcItr;
00042 
00043   SimPmtList::iterator PmtIt;
00044   for(PmtIt = pmtList.begin(); PmtIt!= pmtList.end(); PmtIt++)  {
00045     SimPmt* pmt = PmtIt->second;
00046     if(pmt) {
00047       RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(1));
00048       if ( (rcid.GetElecType()==ElecType::kVA) ) {
00049         if(DynodeTrigger(pmt->GetDynodeCharge())>0.) { 
00050           // PMT has at least 1 trigger.
00051           int crate = rcid.GetCrate();
00052           int varc  = rcid.GetVarcId();
00053           int vmm   = rcid.GetVmm();
00054           int index = crate*100 + varc*10;
00055           if(fVarcTriggerMode == SimVarcTriggerMode::k2of6) {
00056             index += vmm;
00057           }
00058           varcs[index].push_back(pmt);
00059         }
00060       }
00061     }
00062   }
00063   
00064   // Now read out each varc.
00065   for(varcItr=varcs.begin();varcItr!=varcs.end();varcItr++) {
00066     // Start with the first 
00067     MSG("DetSim",Msg::kDebug) << "Reading out varc " << varcItr->first << endl;
00068     ReadoutVarc(varcItr->second);
00069   }
00070 }
00071 
00072 void SimVaTimedElectronics::ReadoutVarc( std::vector<SimPmt*>& pmts )
00073 {
00078   
00079   // Efficient precheck: there must be at least two pmts fired to make it go.
00080   if(fVarcTriggerMode != SimVarcTriggerMode::kNone) {
00081     if(pmts.size()<2) return; 
00082   };
00083 
00084 
00085   // Make a recording of when any dynode triggers happened.
00086 
00087   std::vector<double> vDynodeTimes;
00088   for(UInt_t i=0; i<pmts.size(); i++) {
00089     if(pmts[i]==0) continue; // Sanity check.
00090     
00091     // Go through all buckets in order.
00092     // Record dynode hits as they happen. No dead-chip time here, 
00093     // this is just when the ASD-Lite fires.
00094         
00095     double lastHitTime = -1e9;
00096 
00097     SimPmtBucketIterator bIt( *(pmts[i]) );
00098     for( ; !bIt.End(); bIt.Next() ) {
00099       Int_t bucket = bIt.BucketId();
00100       double bucketcharge = pmts[i]->GetDynodeCharge(bucket);
00101       if(DynodeTrigger(bucketcharge)) {
00102         double t = pmts[i]->GetDynodeTime(bucket);
00103         if((t-lastHitTime)>fVaChipDeadTime) {
00104           lastHitTime = t;
00105           vDynodeTimes.push_back(t);
00106           MSG("DetSim",Msg::kDebug) << "Dynode trigger at " << t << endl;
00107         }
00108       }
00109     }
00110   }
00111   
00112   // Now we can construct the varc trigger times.
00113 
00114   // Sort them.
00115   std::sort(vDynodeTimes.begin(),vDynodeTimes.end());
00116 
00117   // Vector of varc trigger times.
00118   std::vector<double> vVarcTrigTimes;
00119 
00120   if(fVarcTriggerMode != SimVarcTriggerMode::kNone) {
00121     for(UInt_t i=0; i<(vDynodeTimes.size() - 1); i++) {
00122       if((vDynodeTimes[i+1]-vDynodeTimes[i])<fVarcTriggerWindow) {
00123         vVarcTrigTimes.push_back(vDynodeTimes[i]);
00124       }
00125     }
00126   } else {
00127     // No trigger being asserted, so let everything sail through.
00128     vVarcTrigTimes = vDynodeTimes; 
00129   }
00130 
00131   // No go through the process again, looking for valid pmt triggers:
00132   for(UInt_t i=0; i<pmts.size(); i++) {
00133     if(pmts[i]==0) continue; // Sanity check.
00134     
00135     // Go through all buckets in order.
00136     // Do readouts as they happen, applying chip-recovery-time
00137     
00138     // Start off randomly dead, according to the formula given:
00139     double lastHitTime = -1e9;    
00140 
00141     SimPmtBucketIterator bIt( *(pmts[i]) );
00142     for( ; !bIt.End(); bIt.Next() ) {
00143       Int_t bucket = bIt.BucketId();
00144       double bucketcharge = pmts[i]->GetDynodeCharge(bucket);
00145       
00146       // Did it have enough charge to fire?
00147       if(DynodeTrigger(bucketcharge)) {
00148         double t = pmts[i]->GetDynodeTime(bucket);
00149 
00150         // Has it fired recently?
00151         if((t-lastHitTime)>fVaChipDeadTime) {
00152 
00153           // The chip was alive. 
00154           // Was there a valid varc trigger recently?
00155           bool fired = false;
00156           if(fVarcTriggerMode == SimVarcTriggerMode::kNone) {
00157             fired=true;
00158           }
00159           else {
00160             for(UInt_t j=0;j<vVarcTrigTimes.size();j++) {
00161               Double_t dt = t - vVarcTrigTimes[j];
00162               // if dt==0, we have the first hit that triggered the 2/36,
00163               // which should be read out. Use the "dt > -epsilon"
00164               // comparison to avoid using "==" with floats
00165               if ( ( dt > -1e-12 ) && ( dt < fVarcTriggerWindow ) ) {
00166                 fired = true;
00167               }
00168             }
00169           }
00170           if(fired) {
00171             MSG("DetSim",Msg::kDebug) << "Chip fired. " << t/Munits::ns << endl;
00172             lastHitTime = t;
00173             ReadoutPmt(pmts[i],t);                       
00174           }
00175         }
00176       }
00177     }
00178   }
00179   
00180   
00181 }
00182 
00183 
00184 
00185 void SimVaTimedElectronics::ReadoutPmt( SimPmt* pmt, 
00186                                         Double_t dynodeTrigTime)
00187 {
00188  MSG("DetSim",Msg::kDebug) << "SimVaTimedElectronics::ReadoutPmt " 
00189                            << pmt->GetTubeId().AsString() 
00190                            << " type " << pmt->GetType()
00191                            << " at time " << dynodeTrigTime
00192                            << endl;
00193 
00194   PlexHandle plex(fContext);
00195 
00196   // Interesting statistics:
00197   AddDigitsAfterFETrigger( pmt->GetTotalHitPixels(true) );
00198   AddAdcsAfterFETrigger( pmt->GetTotalCharge() * fVaGain );
00199  
00200   for(int ipixel = 1; ipixel<= pmt->GetNumberOfPixels(); ipixel++) {
00201     RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(ipixel));
00202     
00203    int errorbits = 0;
00204 
00205     if(!(rcid.IsNull())) {
00206       //
00207       //  This stuff adds up all the buckets for a pixel into a single
00208       //  response. The charge is shaped by the VA shaping circuit.
00209       //
00210 
00211       DigiSignal* totalSignal = new DigiSignal();
00212       AddSignal(totalSignal);
00213 
00214       std::vector<Float_t> spotpe(pmt->GetNumberOfSpots()+1,0);
00215       
00216       // Find effective charge by convoluting signal with shaping curve.
00217       double qeff = 0;
00218       double qtot = 0;
00219       SimPmtBucketIterator it(*pmt);  
00220       for( ;  !it.End(); it.Next() ) { 
00221         int bucketId = it.BucketId(); 
00222         SimPmtTimeBucket& pmttb = pmt->GetBucket(bucketId);
00223         SimPixelTimeBucket& pixtb = pmttb.GetPixelBucket(ipixel);
00224 
00225         // Which spot was hit?
00226         for(int ispot=0;ispot<=pmt->GetNumberOfSpots();ispot++)
00227           spotpe[ispot]+=pixtb.GetPEXtalk(ispot);
00228         
00229         double dt = pmt->BucketToStartTime(bucketId) - dynodeTrigTime;
00230         
00231         // Skip buckets before this hit.
00232         if(pmt->BucketToStopTime(bucketId) <= dynodeTrigTime) continue;
00233         
00234         // Skip buckets that happen long after this hit.
00235         if(dt > fVaChipDeadTime) break;
00236         
00237         // Add the signal for this bucket.
00238         DigiSignal* signal = pixtb.CreateSignal();
00239         totalSignal->Merge(*signal);
00240         delete signal;
00241 
00242         double q = pixtb.GetCharge();    
00243         double resp = 1.0;
00244         if(dt>0) {
00245           // PHillip Litchfield tells me this is a good function form for the 
00246           // shaping of the VA circuit: t^2 exp(-2t/T)
00247           double t = dt+fVaShapingTime;
00248           resp = t*t*exp(-2*t/fVaShapingTime)/(fVaShapingTime*fVaShapingTime*exp(-2.0));      
00249         }
00250         qeff += q*resp;
00251         qtot += q;
00252       }
00253       
00254       MSG("DetSim",Msg::kDebug) << "Shaped readout of " << rcid.AsString() 
00255                                 << " TrueQ = " << qtot/Munits::fC
00256                                 << " fC.  Shaped Q = " << qeff/Munits::fC 
00257                                 << endl; 
00258 
00259       // Which spot was the best one for nonlinearity?
00260       int bigspot = 1;
00261       for(int ispot=1;ispot<=pmt->GetNumberOfSpots();ispot++)
00262         if(spotpe[ispot] > spotpe[bigspot]) bigspot = ispot;
00263 
00264       PlexPixelSpotId bestPsid = pmt->GetPixelSpotId(ipixel,bigspot);
00265 
00266       int adc = GenSimulatedADC( qeff, rcid, bestPsid );
00267       int tdc = GenSimulatedTDC( dynodeTrigTime, rcid );
00268       
00269       SimDigit d(  pmt->GetPixelSpotId(ipixel),
00270                    rcid,
00271                    adc,
00272                    tdc,
00273                    totalSignal,
00274                    errorbits
00275                    );
00276       MSG("DetSim",Msg::kVerbose) << "ReadoutPmt: " << d.AsString() << std::endl;    
00277 
00278       // Sparsify and record.
00279       if(d.GetADC() > fVaSparsifyThresh) { 
00280         AddDigit(d);
00281         
00282         // Stats:
00283         AddDigitsAfterSpars(1);
00284         AddAdcsAfterSpars(d.GetADC());
00285       }
00286     }
00287   }
00288 
00289 }
00290 
00291 
00292 void
00293 SimVaTimedElectronics::Print(Option_t* option) const
00294 {
00295   SimVaElectronics::Print(option);
00296   printf("Timing:        fVaShapingTime        %f ns\n",fVaShapingTime/Munits::ns);
00297 } 

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