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

PulserTimeCalScheme.cxx

Go to the documentation of this file.
00001 
00002 // $Id: PulserTimeCalScheme.cxx,v 1.23 2008/10/31 14:36:12 tagg Exp $
00003 //
00004 // Calibrator scheme for doing both LI hardware correction
00005 // and muon correction.
00006 //
00007 // Inherits from the plain-old TimeCalScheme.
00008 //
00009 // n.tagg1@physics.ox.ac.uk
00011 
00012 #include "PulserTimeCalScheme.h"
00013 #include "MessageService/MsgService.h"
00014 #include "Plex/PlexHandle.h"
00015 #include "Plex/PlexSEIdAltL.h"
00016 #include "Plex/PlexStripEndId.h"
00017 #include "DatabaseInterface/DbiValidityRec.h"
00018 #include "Validity/VldRange.h"
00019 #include "Calibrator.h"
00020 
00021 CVSID("$Id: PulserTimeCalScheme.cxx,v 1.23 2008/10/31 14:36:12 tagg Exp $");
00022 ClassImp(PulserTimeCalScheme)
00023 
00024 
00025 const RawChannelId kVaRcid(Detector::kFar,ElecType::kVA,0,0);
00026 
00027 PulserTimeCalScheme::PulserTimeCalScheme()
00028 {
00029   Registry r;
00030   // Set configurable options.
00031   r.Set("UseMuonCalibration",1);
00032   r.Set("UsePulserCalibration",0);
00033   r.Set("UseShieldCalibration",1);
00034   r.Set("UseJumps",1);
00035   r.Set("JumpTask",1); // (Obsolete - now tied to MuonTask)
00036   r.Set("DoWalkCorrection",1);
00037   r.Set("PulserLed1",2);
00038   r.Set("PulserLed2",3);
00039   r.Set("PulserLed3",4);
00040   r.Set("DefaultTimingCardSetting",260.);
00041   //r.Set("OverallOffset",30.*Munits::ns);
00042   r.Set("ReferenceDate",20040930);
00043   r.Set("ReferenceTime",0);
00044   r.Set("MuonTask","Dogwood");
00045   InitializeConfig(r); 
00046 }
00047 
00048 //.....................................................................
00049 void PulserTimeCalScheme::ConfigModified()
00050 {                                       
00051   Int_t refDate = 0;
00052   Int_t refTime = 0;;
00053   
00054   const char* taskname;
00055 
00056   bool ok = true;
00057   ok = ok && GetConfig().Get("UseMuonCalibration",fUseMuonCalibration);
00058   ok = ok && GetConfig().Get("UseShieldCalibration",fUseShieldCalibration);
00059   ok = ok && GetConfig().Get("UsePulserCalibration",fUsePulserCalibration);
00060   ok = ok && GetConfig().Get("UseJumps",fUseJumps);
00061   //ok = ok && GetConfig().Get("JumpTask",fJumpTask);
00062   ok = ok && GetConfig().Get("DoWalkCorrection",fDoWalkCorrection);
00063   ok = ok && GetConfig().Get("DefaultTimingCardSetting",fDefaultTimingCardSetting);
00064   //ok = ok && GetConfig().Get("OverallOffset",fOverallOffset);
00065   ok = ok && GetConfig().Get("ReferenceDate",refDate);
00066   ok = ok && GetConfig().Get("ReferenceTime",refTime);
00067   for(int i=0;i<kMaxLeds; i++) {
00068     ok = ok && GetConfig().Get(Form("PulserLed%d",i+1),fPulserLed[i]);
00069   }
00070   ok = ok && GetConfig().Get("MuonTask",taskname);
00071 
00072   if(!ok){
00073     MSG("Calib",Msg::kWarning) << "PulserTimeCalScheme couldn't configure properly!" << endl;
00074     GetConfig().PrettyPrint(std::cerr);
00075   }
00076 
00077   if     (0==strcasecmp(taskname,"Dogwood")){ fMuonTask = 2; }
00078   else if(0==strcasecmp(taskname,"Andys"  )){ fMuonTask = 1; }
00079   else if(0==strcasecmp(taskname,"Brians" )){ fMuonTask = 0; }
00080   else{
00081     // Feh?
00082     MSG("Calib",Msg::kWarning) << "PulserTimeCalScheme doesn't recognise task " << taskname << endl;
00083   }  
00084 
00085    fReferenceTime = VldTimeStamp(refDate,refTime,0);
00086 
00087   // Ensure that the DB has been changed for this event.
00088   Reset(GetContext(),true); 
00089 }
00090 
00091 //.....................................................................
00092 void PulserTimeCalScheme::PrintConfig( std::ostream& os ) const
00093 {
00094   char taskname[100];
00095   switch(fMuonTask) {
00096   case 0: sprintf(taskname,"Brians"); break;
00097   case 1: sprintf(taskname,"Andys"); break;
00098   case 2: sprintf(taskname,"Dogwood"); break;
00099   default: sprintf(taskname,"Task %d",fMuonTask); break;
00100   }
00101 
00102   os << "  UseMuonCalibration:   " << ((fUseMuonCalibration)?("On"):("Off")) << endl;
00103   os << "  MuonTask:             " << taskname << endl;
00104   os << "  UseShieldCalibration: " << ((fUseShieldCalibration)?("On"):("Off")) << endl;
00105   os << "  UseJumps:             " << ((fUseJumps)?("On"):("Off")) << endl;
00106   // os << "  JumpTask:             " << fJumpTask << endl;
00107   os << "  UsePulserCalibration: " << ((fUsePulserCalibration)?("On"):("Off")) << endl;  
00108   os << "  DoWalkCorrection:     " << ((fDoWalkCorrection)?("On"):("Off")) << endl;  
00109   os << "  Reference date:       " << fReferenceTime.AsString() << endl;
00110   os << "  PulserLeds to use:    ";
00111   for(int i=0;i<kMaxLeds;i++) {
00112     os << fPulserLed[i];
00113     if(i!=kMaxLeds-1) os << ",";
00114   }
00115   os << endl;
00116     
00117 }
00118 
00119  //.....................................................................
00120 void PulserTimeCalScheme::DoReset( const VldContext& context )
00121 {
00122   MSG("Calib",Msg::kVerbose) << "PulserTimeCalScheme::DoReset()" << endl;
00123   
00124   if(fUseMuonCalibration) {
00125     fMuonResPtr.NewQuery(context,fMuonTask);
00126     
00127     if(fMuonResPtr.GetNumRows()==0) {
00128       MAXMSG("Calib",Msg::kWarning,10) 
00129         << "No rows in CALTIMECALIBRATION with validity context "
00130         << context.AsString() << "  No muon timing calibration will be applied." << endl;
00131       IncrementErrors(kTimeCalibrator,kMissingTable);
00132     }
00133   }
00134   
00135   if(fUseShieldCalibration && context.GetDetector()==Detector::kFar) {
00136     fShieldResPtr.NewQuery(context,99); // Task 99 is for shield.
00137     if(fShieldResPtr.GetNumRows()==0) {
00138         MAXMSG("Calib",Msg::kWarning,10) 
00139           << "No rows for FD shield timing calibration CALTIMECALIBRATION task " 
00140           << 99 << " with validity context "
00141           << context.AsString() << endl;
00142         IncrementErrors(kTimeCalibrator,kMissingTable);
00143     }
00144   }
00145 
00146   if(fUseJumps && fMuonTask>0) {
00147     fJumpResPtr.NewQuery(context,fMuonTask);
00148     // No errors if no data.
00149   }
00150 
00151   VldContext refContext(context.GetDetector(),
00152                         context.GetSimFlag(),
00153                         fReferenceTime);
00154 
00155   if(fUsePulserCalibration) {
00156     // Note: we use the LED number to set the Task in the DB call.
00157     // This allows us to use different LEDs for the calibration if we desire.
00158 
00159     for(int iled=0;iled<kMaxLeds;iled++) {
00160       fDriftPtr[iled].NewQuery(context,fPulserLed[iled]);
00161       if(fDriftPtr[iled].GetNumRows()==0) {
00162         MAXMSG("Calib",Msg::kWarning,10) 
00163           << "No rows in PULSERTIMEDRIFT task " << fPulserLed[iled] << " with validity context "
00164           << context.AsString() << endl;
00165         IncrementErrors(kTimeCalibrator,kMissingTable);
00166       }
00167 
00168       
00169       fDriftRefPtr[iled].NewQuery(refContext,fPulserLed[iled]);
00170       if(fDriftRefPtr[iled].GetNumRows()==0) {
00171         MAXMSG("Calib",Msg::kWarning,10) 
00172           << "No rows in PULSERTIMEDRIFT task " << fPulserLed[iled] << " with reference context "
00173           << refContext.AsString() << endl;
00174         IncrementErrors(kTimeCalibrator,kMissingTable);
00175       }
00176       
00177     }
00178 
00179     // Time card and reference.
00180 
00181     fTimingCardResPtr.NewQuery(context,0);
00182     if(fTimingCardResPtr.GetNumRows()==0) {
00183       MAXMSG("Calib",Msg::kWarning,10) 
00184         << "No rows in PULSERTIMINGCARDSETTING with validity context "
00185         << context.AsString() << endl;
00186       IncrementErrors(kTimeCalibrator,kMissingTable);
00187     }
00188 
00189     fTimingCardReferencePtr.NewQuery(refContext,0);
00190     if(fTimingCardReferencePtr.GetNumRows()==0) {
00191       MAXMSG("Calib",Msg::kWarning,10) 
00192         << "No rows in PULSERTIMINGCARDSETTING with reference context "
00193         << refContext.AsString() << endl;
00194       IncrementErrors(kTimeCalibrator,kMissingTable);
00195     }
00196 
00197   }
00198 }
00199 
00200 //.....................................................................
00201 DoubleErr PulserTimeCalScheme::GetCalibratedTime(DoubleErr rawtime,
00202                                                 FloatErr rawcharge,
00203                                                 const PlexStripEndId& seid) const
00204 {
00216 
00217   // Find raw channel.
00218   DoubleErr time = rawtime;
00219 
00220   if(seid.IsVetoShield()) {
00221 
00222     // Shield hits:
00223     if(fUseShieldCalibration) time = CalibrateShield(time,rawcharge,seid,true);     
00224   } else {
00225 
00226     // Non-shield hits:
00227 
00228     if(GetContext().GetDetector()==Detector::kFar) {
00229       PlexHandle plex(GetContext());
00230       RawChannelId rcid = plex.GetRawChannelId(seid);
00231       if(fUseJumps)             time = CalibrateByJumps(time,rcid,true);
00232       if(fUsePulserCalibration) time = CalibrateByPulser(time,rcid,true);
00233     }
00234     if(fUseMuonCalibration)   time = CalibrateByMuon(time,seid,true);
00235     if(fDoWalkCorrection)     time-= WalkCorrection(rawcharge,seid);
00236   }
00237 
00238   return time;
00239 }
00240 
00241 //.....................................................................
00242 DoubleErr PulserTimeCalScheme::DecalTime(DoubleErr caltime, 
00243                                         FloatErr rawcharge,
00244                                         const PlexStripEndId& seid) const
00245 {
00259 
00260   // Find raw channel.
00261   DoubleErr time = caltime;
00262 
00263   if(seid.IsVetoShield()) {
00264 
00265     // Shield hits:
00266     if(fUseShieldCalibration) time = CalibrateShield(time,rawcharge,seid,false); 
00267 
00268   } else {
00269 
00270     // Non-shield hits:
00271 
00272     if(GetContext().GetDetector()==Detector::kFar) {
00273       PlexHandle plex(GetContext());
00274       RawChannelId rcid = plex.GetRawChannelId(seid);
00275       if(fUseJumps)             time = CalibrateByJumps(time,rcid,false);
00276       if(fUsePulserCalibration) time = CalibrateByPulser(time,rcid,false);
00277     }
00278     if(fUseMuonCalibration)   time = CalibrateByMuon(time,seid,false);
00279     if(fDoWalkCorrection)     time+= WalkCorrection(rawcharge,seid);
00280   }
00281 
00282   return time;
00283 }
00284 
00285 
00286 //.....................................................................
00287 DoubleErr PulserTimeCalScheme::CalibrateByJumps(DoubleErr rawtime,               
00288                                                 const RawChannelId& rcid,
00289                                                 Bool_t calibrate) const
00290 {
00291   // Find index number into table.
00292   UInt_t index = CalTimeJump::GetIndex(rcid);
00293 
00294   // If a jump entry exists, apply it.
00295 
00296   const CalTimeJump* jump = fJumpResPtr.GetRowByIndex(index);
00297   if(jump) {
00298     if(calibrate)
00299       return rawtime - (double)jump->GetJump();
00300     else
00301       return rawtime + (double)jump->GetJump();
00302   }
00303 
00304   // Otherwise, do nothing.
00305 
00306   return rawtime;
00307 }
00308 
00309 //.....................................................................
00310 DoubleErr PulserTimeCalScheme::CalibrateByMuon(DoubleErr rawtime,               
00311                                            const PlexStripEndId& seid,
00312                                            Bool_t calibrate) const
00313 {
00314   // Now need to get the row which corresponds to the stripendnum.
00315   const CalTimeCalibration* dpgc = fMuonResPtr.GetRowByIndex(seid.BuildPlnStripEndKey());
00316 
00317   if(dpgc==0) {
00318     if(fMuonResPtr.GetNumRows()>0) {
00319       MAXMSG("Calib",Msg::kWarning,10) 
00320         << "PulserTimeCalScheme: No database row for StripEnd " << seid.AsString() << "\n";
00321       
00322       IncrementErrors(kTimeCalibrator,kMissingRow,seid);
00323     }
00324     return rawtime + DoubleErr(0,20.*Munits::ns); // Show there's no calib constant.
00325   }
00326   if(calibrate)
00327     return (rawtime/(double)dpgc->GetScale()) -  (double)dpgc->GetOffset();
00328 
00329   // else decalibrate:
00330   // No inverse function exists in the row function, so I'll kludge one here.
00331   // NJT 7/04
00332   return (rawtime +  (double)dpgc->GetOffset())*(double)dpgc->GetScale();
00333 }
00334 
00335 
00336 
00337 //.....................................................................
00338 DoubleErr PulserTimeCalScheme::CalibrateByPulser(DoubleErr rawtime,               
00339                                              const RawChannelId& rcid,
00340                                              Bool_t calibrate) const
00341 {
00342   // Find index number into table.
00343   UInt_t index = PulserTimeDrift::GetIndex(rcid);
00344   
00345   const PulserTimeDrift* drift    = 0;
00346   const PulserTimeDrift* driftref = 0;
00347 
00348   // Get drift point and drift reference point
00349   Int_t whichled = 0;
00350   bool driftok = GetPulserCalibration(whichled,index,drift,driftref);
00351   
00352   // If not good, look through the list of backups.
00353   while(!driftok){
00354     whichled++;
00355     if(whichled<kMaxLeds) {
00356       driftok = GetPulserCalibration(whichled,index,drift,driftref);
00357       MSG("Calib",Msg::kDebug) << "PulserTiming: " << rcid.AsString() << " Fell back to LED " << fPulserLed[whichled] << endl;
00358     } else {
00359       MAXMSG("Calib",Msg::kWarning,10) 
00360         << "PulserTimeCalScheme: Failed to find calibration for channel " 
00361         << rcid.AsString() << " index " << index << " in primary or fallback tables.\n";
00362       IncrementErrors(kTimeCalibrator,kMissingRow,rcid);
00363       return rawtime + DoubleErr(0,50.*Munits::ns); // no calibration. Add 50ns error to show.
00364     }
00365   }
00366   
00367   
00368   // Get Settings row, if it exists.
00369   const PulserTimingCardSetting* cardSetting = 
00370     fTimingCardResPtr.GetRowByIndex(rcid.GetCrate());
00371   const PulserTimingCardSetting* refCardSetting = 
00372     fTimingCardReferencePtr.GetRowByIndex(rcid.GetCrate());
00373 
00374   Double_t tpmt_delay_ns = fDefaultTimingCardSetting;
00375   Double_t ref_delay_ns  = fDefaultTimingCardSetting;
00376   
00377   // Check for errors getting setting.
00378   if(cardSetting==0) {
00379     if(fTimingCardResPtr.GetNumRows()>0) {
00380       MAXMSG("Calib",Msg::kWarning,10) << "Incomplete PulserTimingCardSettings table!" << endl;      
00381     }
00382     IncrementErrors(kTimeCalibrator,kMissingRow,rcid);    
00383   } else {
00384     tpmt_delay_ns = cardSetting->GetDelayNanoSecs();
00385   }
00386   
00387   
00388   // Check for errors getting reference setting.
00389   if(refCardSetting==0) {
00390     if(fTimingCardReferencePtr.GetNumRows()>0) {
00391       MAXMSG("Calib",Msg::kWarning,10) << "Incomplete PulserTimingCardSettings table!" << endl;      
00392     }
00393     IncrementErrors(kTimeCalibrator,kMissingRow,rcid);    
00394   } else {
00395     ref_delay_ns = cardSetting->GetDelayNanoSecs();
00396   }
00397   
00398   
00399   // Finally, do the correction:
00400   
00401   // Crate offset due to changed timing card setting:
00402   double crate_offset_t = (tpmt_delay_ns - ref_delay_ns)*Munits::ns;
00403   
00404   // Offset as calibrated by LI. Longer timing card settings
00405   // mean that the drift point is too big a number.
00406   double drift_tdcs = (drift->GetMean() - driftref->GetMean());
00407   double drift_err  = (drift->GetRms() / sqrt(drift->GetEntries()));
00408   double convert = Calibrator::Instance().GetTDCConvert(kVaRcid); // s per tick
00409   DoubleErr drift_t(drift_tdcs * convert,
00410                     drift_err  * convert);
00411   
00412   // And the time walk.
00413   
00414   
00415   DoubleErr offset = drift_t - crate_offset_t;
00416   
00417   if(calibrate) 
00418     return rawtime - offset;
00419   
00420   // else:
00421   return rawtime + offset;
00422 }
00423 
00424 Bool_t 
00425 PulserTimeCalScheme::GetPulserCalibration(Int_t iled, UInt_t index,
00426                                           const PulserTimeDrift* &drift, 
00427                                           const PulserTimeDrift* &ref) const
00428 {
00429   // Retrieve rows from the DB. Return true if the rows exist and
00430   // are good, false if they are bad.
00431 
00432   drift = fDriftPtr[iled].GetRowByIndex(index);
00433   ref   = fDriftRefPtr[iled].GetRowByIndex(index);
00434 
00435   // Do they exist?
00436   if(drift==0) return false;
00437   if(ref==0) return false;
00438 
00439   // Are the means valid to a good precision?
00440   // Error limit: 0.2 ticks.
00441   // So, want to fail if RMS/Entries > 0.2 ticks
00442   // Rearrange to get below:
00443   // (The clever bit here is that this automatically checks for entries==0)
00444 
00445   if( drift->GetRms() >= sqrt(drift->GetEntries())*0.2 ) return false;
00446   if(   ref->GetRms() >= sqrt(  ref->GetEntries())*0.2 ) return false;
00447 
00448 
00449   return true;
00450 }
00451 
00452 
00453 
00454 //.....................................................................
00455 DoubleErr PulserTimeCalScheme::WalkCorrection(FloatErr rawcharge, 
00456                                               const PlexStripEndId&) const
00457 {
00463 
00464   // These are Andy's paramaterisations for the FD, hard-coded for now.
00465   if(GetContext().GetDetector()==Detector::kFar) {
00466 
00467     const float kParData[4] = {  5.44066e+00,
00468                               -5.94887e-01,
00469                               -7.36609e-02,
00470                               7.66637e-03 };
00471 
00472     const float kParMC[4] = { 4.18608e+00,
00473                               -3.75033e-01,
00474                               -9.50218e-02,
00475                               9.52560e-03 };
00476     
00477     const float* par = kParData;
00478     if(GetContext().GetSimFlag()==SimFlag::kMC) par = kParMC;
00479       
00480     if(rawcharge<=0) rawcharge = 1; // Be careful.
00481     double cx = log(rawcharge()/2.3);
00482     double walk = (
00483                    par[0]
00484                    + (par[1] * cx)
00485                    + (par[2] * cx *cx)
00486                    + (par[3] * cx * cx *cx) 
00487                    );
00488     // These parameters are in units of meters, so convert to time:
00489     return walk / Munits::c_light; // Fixme: does not paramaterize error.
00490       
00491   }
00492 
00493   return 0;
00494 }
00495 
00496 //.....................................................................
00497 DoubleErr PulserTimeCalScheme::CalibrateShield(DoubleErr rawtime,
00498                                                FloatErr rawcharge,
00499                                                const PlexStripEndId& seid, 
00500                                                Bool_t calibrate) const
00501 {
00502    // Now need to get the row which corresponds to the stripendnum.
00503   const CalTimeCalibration* dpgc = fShieldResPtr.GetRowByIndex(seid.BuildPlnStripEndKey());
00504 
00505   if(dpgc==0) {
00506     if(fShieldResPtr.GetNumRows()>0) {
00507       MAXMSG("Calib",Msg::kWarning,10) 
00508         << "PulserTimeCalScheme: No database row for shield StripEnd " << seid.AsString() << "\n";      
00509       IncrementErrors(kTimeCalibrator,kMissingRow,seid);
00510     }
00511     return rawtime - DoubleErr(-30.0*Munits::ns, // -30ns is the usual average
00512                                20.*Munits::ns); // Show there's no calib constant.
00513   }
00514 
00515   // apply the 'extra' walk correction for shield hits.
00516   if(rawcharge<1) rawcharge=1; // Protect against -ve numbers
00517   Double_t logq = log(rawcharge);
00518 
00519   Double_t walk = 0;
00520   if(fDoWalkCorrection) {
00521     const float kgainadjust=60./90.; // I think this compensates for the extra gain in the shield
00522     walk = WalkCorrection(rawcharge*kgainadjust,seid);
00523     walk += dpgc->GetSlewC1()
00524     + dpgc->GetSlewC2()*logq
00525     + dpgc->GetSlewC3()*logq*logq
00526     + dpgc->GetSlewC4()*logq*logq*logq;
00527   }
00528 
00529 
00530   if(calibrate)
00531     return rawtime - walk + (double)dpgc->GetOffset();
00532   
00533   // else decalibrate:
00534   return  rawtime +  walk - (double)dpgc->GetScale();
00535 
00536 }
00537 

Generated on Sat Nov 7 01:27:15 2009 for loon by  doxygen 1.3.9.1