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

Generated on Fri Mar 28 15:38:19 2008 for loon by  doxygen 1.3.9.1