00001 #include <cmath>
00002 #include <TMath.h>
00003 #include "MessageService/MsgService.h"
00004 #include "Digitization/DigiSignal.h"
00005 #include "SimVaElectronics.h"
00006 #include "SimElecMaker.h"
00007 #include "Calibrator/Calibrator.h"
00008 #include "Calibrator/CalVaLinearity.h"
00009
00010
00011 SimElecMakerProxy<SimVaElectronics> gSimVaElec("SimVaElectronics");
00012
00013 CVSID("$Id: SimVaElectronics.cxx,v 1.30 2008/10/24 12:01:43 blake Exp $");
00014
00015 ClassImp(SimVaElectronics)
00016
00017 SimVaElectronics::SimVaElectronics( VldContext context, TRandom* random )
00018 : SimElectronics( context, random ),
00019 fVaGain(0.375/Munits::fC),
00020 fVaPedWidth(2.8),
00021 fTimeSmearingMode(SimTimeSmearingMode::kBreitWigner),
00022 fTimingWidth(0.0),
00023 fVaSparsifyThresh(17),
00024 fVaDynodeThresh(57),
00025 fVaNonlinearity(1),
00026 fVaLinearityP0(24),
00027 fVaLinearityP1(16091.3),
00028 fVaLinearityP2(4.63),
00029 fVaLinearityP3(13683.9),
00030 fVaLinearityP4(6650.11),
00031 fVarcTriggerMode(SimVarcTriggerMode::k2of36),
00032 fVarcTriggerWindow(400.*Munits::ns),
00033 fVaChipRandomDeadRate(700*Munits::hertz),
00034 fVaChipDeadTime(5.*Munits::microsecond),
00035 fDoLookupNonlinearity(0),
00036 fCalVaLinearity(0)
00037 {
00038 fCalVaLinearity = new CalVaLinearity(RawChannelId(),
00039 fVaLinearityP0, fVaLinearityP1,
00040 fVaLinearityP2, fVaLinearityP3,
00041 fVaLinearityP4
00042 );
00043 }
00044
00045
00046 SimVaElectronics::~SimVaElectronics()
00047 {
00048 if(fCalVaLinearity) delete fCalVaLinearity;
00049 }
00050
00051
00052 void SimVaElectronics::ReadoutDetector( SimPmtList& pmtList )
00053 {
00054 PlexHandle plex(fContext);
00055
00056
00057 std::map<int,std::vector<double> > varcTrigTimes;
00058 std::map<int,std::vector<double> >::iterator it;
00059
00060
00061 std::map<int,bool> deadChips;
00062
00063
00064 if(fVaChipRandomDeadRate>0.) {
00065 SimPmtList::iterator PmtIt;
00066 for(PmtIt = pmtList.begin(); PmtIt!= pmtList.end(); PmtIt++) {
00067
00068
00069 double deadProb = fVaChipRandomDeadRate*fVaChipDeadTime;
00070
00071 bool isDead = false;
00072 if(fRandom->Rndm()<deadProb) isDead = true;
00073
00074 deadChips[PmtIt->first] = isDead;
00075 }
00076 }
00077
00078 Int_t crate, varc, vmm;
00079
00080 if(fVarcTriggerMode != SimVarcTriggerMode::kNone) {
00081
00082
00083 SimPmtList::iterator PmtIt;
00084 for(PmtIt = pmtList.begin(); PmtIt!= pmtList.end(); PmtIt++) {
00085 SimPmt* pmt = PmtIt->second;
00086 if(pmt) {
00087
00088 RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(1));
00089 if ( (rcid.GetElecType()==ElecType::kVA) ) {
00090
00091
00092
00093 if((DynodeTrigger(pmt->GetDynodeCharge())) && (!deadChips[PmtIt->first])) {
00094 crate = rcid.GetCrate();
00095 varc = rcid.GetVarcId();
00096 vmm = rcid.GetVmm();
00097
00098
00099 int index = crate*100 + varc*10;
00100 if(fVarcTriggerMode == SimVarcTriggerMode::k2of6) {
00101 index += vmm;
00102 }
00103
00104 Double_t time = pmt->GetDynodeTime();
00105 varcTrigTimes[index].push_back(time);
00106 }
00107 }
00108 }
00109 }
00110
00111
00112 for(it = varcTrigTimes.begin(); it!=varcTrigTimes.end(); it++) {
00113 sort(it->second.begin(),it->second.end());
00114
00115
00116
00117
00118
00119 }
00120 }
00121
00122
00123
00124 SimPmtList::iterator PmtIt;
00125 for(PmtIt = pmtList.begin(); PmtIt!= pmtList.end(); PmtIt++) {
00126 SimPmt* pmt = PmtIt->second;
00127 if(pmt) {
00128
00129 RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(1));
00130 if ( rcid.GetElecType()==ElecType::kVA ) {
00131
00132 crate = rcid.GetCrate();
00133 varc = rcid.GetVarcId();
00134 vmm = rcid.GetVmm();
00135
00136 bool trig = true;
00137
00138 if(fVarcTriggerMode != SimVarcTriggerMode::kNone) {
00139
00140 int index = crate*100 + varc*10;
00141 if(fVarcTriggerMode == SimVarcTriggerMode::k2of6) {
00142 index += vmm;
00143 }
00144
00145
00146 trig = false;
00147
00148 std::vector<double> &tVec = varcTrigTimes[index];
00149
00150 int nhits = 0;
00151 for(UInt_t i=0; i<tVec.size(); i++) {
00152 double dt = tVec[i] - pmt->GetDynodeTime();
00153 if(fabs(dt)<fVarcTriggerWindow)
00154 nhits++;
00155 }
00156 if(nhits>1) trig=true;
00157 }
00158
00159 if(DynodeTrigger(pmt->GetDynodeCharge()))
00160 ReadoutPmt(pmt,trig, deadChips[PmtIt->first]);
00161 }
00162 }
00163 }
00164
00165 }
00166
00167
00168
00169 void SimVaElectronics::ReadoutPmt( SimPmt* pmt, bool trig, bool isDead)
00170 {
00171
00172
00173
00174 MSG("DetSim",Msg::kDebug) << "SimVaElectronics::ReadoutPmt "
00175 << pmt->GetTubeId().AsString()
00176 << " type " << pmt->GetType()
00177 << endl;
00178
00179 PlexHandle plex(fContext);
00180
00181
00182 if((trig)&&(!isDead)) {
00183 AddDigitsAfterFETrigger( pmt->GetTotalHitPixels(true) );
00184 AddAdcsAfterFETrigger( pmt->GetTotalCharge() * fVaGain );
00185 }
00186
00187 for(int ipixel = 1; ipixel<= pmt->GetNumberOfPixels(); ipixel++) {
00188 RawChannelId rcid = plex.GetRawChannelId(pmt->GetPixelSpotId(ipixel));
00189
00190
00191
00192 Float_t bigpe=0;
00193 Int_t bigspot=1;
00194 for(int ispot=1;ispot<=pmt->GetNumberOfSpots();ispot++) {
00195 float pe = pmt->GetPeXtalk(ipixel, ispot);
00196 if(pe > bigpe) {
00197 bigpe = pe;
00198 bigspot = ispot;
00199 }
00200 }
00201
00202 DigiSignal* signal = pmt->CreateSignal(ipixel);
00203 AddSignal(signal);
00204 int errorbits = 0;
00205 if(!trig) errorbits+=1;
00206 if(isDead) errorbits+=2;
00207
00208 if(!(rcid.IsNull())) {
00209 Int_t adc = GenSimulatedADC(pmt->GetCharge(ipixel),
00210 rcid,
00211 pmt->GetPixelSpotId(ipixel, bigspot) );
00212 Int_t tdc = GenSimulatedTDC(pmt->GetDynodeTime(), rcid);
00213
00214 SimDigit d( pmt->GetPixelSpotId(ipixel),
00215 rcid,
00216 adc,
00217 tdc,
00218 signal,
00219 errorbits
00220 );
00221 MSG("DetSim",Msg::kVerbose) << "ReadoutPmt: " << d.AsString() << std::endl;
00222
00223
00224 if(d.GetADC() > fVaSparsifyThresh) {
00225 AddDigit(d);
00226
00227
00228 AddDigitsAfterSpars(1);
00229 AddAdcsAfterSpars(d.GetADC());
00230 }
00231 }
00232 }
00233 }
00234
00235
00236 Bool_t SimVaElectronics::DynodeTrigger( double dynCharge )
00237 {
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 const float kThresh0 = 63.0 * 2.4 *0.8 /(fVaGain);
00257
00258 double thresh = (double)(63 - fVaDynodeThresh)/63. * kThresh0;
00259
00260 if(dynCharge > thresh) return true;
00261 else return false;
00262 }
00263
00264 int SimVaElectronics::GenSimulatedADC( double inCharge,
00265 const RawChannelId&,
00266 const PlexPixelSpotId& psid)
00267 {
00268
00269 double adc = inCharge * fVaGain;
00270
00271 if(fDoLookupNonlinearity) {
00272 PlexHandle plex(fContext);
00273 PlexStripEndId seid = plex.GetStripEndId(psid);
00274 if(seid.IsValid()) {
00275 adc = Calibrator::Instance().DecalLinearity(adc, seid);
00276 }
00277 }
00278 else if(fVaNonlinearity) {
00279 if(adc > 16384) adc = 16384;
00280 adc = fCalVaLinearity->UnLinearize(adc);
00281 }
00282
00283 double x = fRandom->Gaus(adc, fVaPedWidth);
00284 return (int)(TMath::Floor(x));
00285 }
00286
00287 int SimVaElectronics::GenSimulatedTDC( double inTime, const RawChannelId& rcid )
00288 {
00289
00290
00291 if(inTime>=kPmtTime_Never) {
00292 MSG("DetSim",Msg::kWarning) << "GenSimulatedTDC got a hit with a PMT that never fired!" << endl;
00293
00294 return 650000000;
00295 }
00296
00297
00298 double deltaTime = 0.0;
00299 if( fTimeSmearingMode>0 && fTimingWidth>0.0 ) {
00300
00301
00302 if( fTimeSmearingMode==SimTimeSmearingMode::kBreitWigner ){
00303 deltaTime = ( fRandom->BreitWigner( 0.0, fTimingWidth ) )*Munits::ns;
00304 }
00305
00306
00307 else if( fTimeSmearingMode==SimTimeSmearingMode::kGaussian ){
00308 deltaTime = ( fRandom->Gaus( 0.0, fTimingWidth ) )*Munits::ns;
00309 }
00310
00311
00312 else if( fTimeSmearingMode==SimTimeSmearingMode::kUniform ){
00313 deltaTime = ( fRandom->Uniform( -fTimingWidth, +fTimingWidth ) )*Munits::ns;
00314 }
00315
00316 }
00317
00318
00319 double x = Calibrator::Instance().GetTDCFromTime(inTime+deltaTime,rcid);
00320
00321 return (int)(TMath::Floor(x));
00322 }
00323
00324 void
00325 SimVaElectronics::Print(Option_t*) const
00326 {
00327 printf("VA Front End: vaGain %f ADC/fC\n",fVaGain*Munits::fC);
00328 printf(" vaPedWidth %f ADCs\n",fVaPedWidth);
00329 printf(" vaTimingWidth %f ns\n",fTimingWidth);
00330 printf(" vaSparsifyThresh %d ADCs\n",fVaSparsifyThresh);
00331 printf(" vaDynodeThresh %d DACs\n",fVaDynodeThresh);
00332 printf(" vaNoninearity %d (%s)\n",fVaNonlinearity,(fVaNonlinearity)?"Nonlinear":"Linear");
00333 printf(" vaLinearityParams: %f %.1f %.1f %.1f %.1f\n",fVaLinearityP0, fVaLinearityP1,fVaLinearityP2,fVaLinearityP3,fVaLinearityP4);
00334 printf("VA Back End: varcTriggerMode %d (0=none, 1=2/6, 2=2/36)\n",fVarcTriggerMode);
00335 printf(" varcTriggerWindow %f ns\n",fVarcTriggerWindow);
00336 printf(" vaChipRandomDeadRate %f Hz\n",fVaChipRandomDeadRate);
00337 printf(" vaChipDeadTime %f us\n",fVaChipDeadTime/Munits::microsecond);
00338 printf(" doLookupNonlinearity %s \n",fDoLookupNonlinearity?("on"):("off") );
00339
00340 }
00341
00342 void
00343 SimVaElectronics::Config( Registry& config )
00344 {
00345
00346
00347
00348 config.Get("vaGain",fVaGain);
00349 config.Get("vaPedWidth",fVaPedWidth);
00350 config.Get("vaTimeSmearingMode",fTimeSmearingMode);
00351 config.Get("vaTimingWidth",fTimingWidth);
00352 config.Get("vaSparsifyThresh",fVaSparsifyThresh);
00353 config.Get("vaDynodeThresh",fVaDynodeThresh);
00354 config.Get("vaNonlinearity",fVaNonlinearity);
00355 config.Get("vaLinearityP0",fVaLinearityP0);
00356 config.Get("vaLinearityP1",fVaLinearityP1);
00357 config.Get("vaLinearityP2",fVaLinearityP2);
00358 config.Get("vaLinearityP3",fVaLinearityP3);
00359 config.Get("vaLinearityP4",fVaLinearityP4);
00360 config.Get("varcTriggerMode",fVarcTriggerMode);
00361 config.Get("varcTriggerWindow",fVarcTriggerWindow);
00362 config.Get("vaChipRandomDeadRate",fVaChipRandomDeadRate);
00363 config.Get("vaChipDeadTime",fVaChipDeadTime);
00364 config.Get("doLookupNonlinearity",fDoLookupNonlinearity);
00365
00366 if(fCalVaLinearity) delete fCalVaLinearity;
00367 fCalVaLinearity = new CalVaLinearity(RawChannelId(),
00368 fVaLinearityP0,
00369 fVaLinearityP1,
00370 fVaLinearityP2,
00371 fVaLinearityP3,
00372 fVaLinearityP4
00373 );
00374
00375 if(fVaSparsifyThresh<=0)
00376 MSG("DetSim",Msg::kWarning) << "WARNING: The VA sparsification threshold " << std::endl
00377 << " is less than zero!" << std::endl;
00378 SimElectronics::Config(config);
00379 }