00001 #include "SpillTimeFinder.h"
00002 #include "Conventions/Munits.h"
00003 #include "MessageService/MsgService.h"
00004 #include "DatabaseInterface/DbiSqlContext.h"
00005 #include <cmath>
00006
00007 CVSID( "$Id: SpillTimeFinder.cxx,v 1.35 2008/05/30 18:35:43 tagg Exp $" );
00008
00009 SpillTimeFinder* SpillTimeFinder::fgInstance = 0;
00010
00011 static SpillTimeND kSpillTime_VeryOld(VldTimeStamp(0,0));
00012 static SpillTimeND kSpillTime_Future(VldTimeStamp(2147480000,0));
00013
00014 SpillTimeFinder& SpillTimeFinder::Instance()
00015 {
00018
00019
00020 static Cleaner cleaner;
00021
00022
00023 if (!fgInstance) {
00024 cleaner.UseMe();
00025 fgInstance = new SpillTimeFinder();
00026 if (!fgInstance) {
00027 MSG("SpillTime", Msg::kError)
00028 << "No DigitSpillTimeFinder Instance - fatal." << endl;
00029 assert(fgInstance);
00030 }
00031 }
00032 return *fgInstance;
00033 }
00034
00035
00036 SpillTimeFinder::SpillTimeFinder() :
00037 fPrevTable(0),
00038 fNextTable(0),
00039 fLastQueryPrev(kSpillTime_Future),
00040 fLastQueryNext(kSpillTime_VeryOld)
00041 {
00042 Registry r;
00043 r.Set("Task",3);
00044 InitializeConfig(r);
00045 }
00046
00047 SpillTimeFinder::~SpillTimeFinder()
00048 {
00049 if(fPrevTable) delete fPrevTable;
00050 if(fNextTable) delete fNextTable;
00051 }
00052
00053 void SpillTimeFinder::ResetCache()
00054 {
00055 fLastQueryPrev=kSpillTime_Future;
00056 fLastQueryNext=kSpillTime_VeryOld;
00057 }
00058
00059 void SpillTimeFinder::ConfigModified()
00060 {
00061 bool ok = true;
00062 ok = ok && GetConfig().Get("Task",fTask);
00063 if(!ok) MSG("SpillTimeFinder",Msg::kWarning) << "Problem configuring SpillTimeFinder." << endl;
00064 ResetCache();
00065 }
00066
00067 Bool_t SpillTimeFinder::DataIsAvailable( const VldContext& context )
00068 {
00073
00074
00075 VldTimeStamp kickerTime = context.GetTimeStamp();
00076 Double_t offset = GetOffset(context,fTask);
00077 kickerTime.Add(-offset);
00078
00079 VldContext kickerContext(Detector::kNear,
00080 context.GetSimFlag(),
00081 kickerTime);
00082
00083
00084 fCurrentTable.NewQuery(kickerContext,fTask);
00085
00086
00087
00088
00089 const DbiValidityRec* myVrec = fCurrentTable.GetValidityRec();
00090 if ( myVrec->IsGap () ) return false;
00091
00092 return true;
00093 }
00094
00095
00096
00097 void SpillTimeFinder::FindClosestEntries(const VldContext& context,
00098 const SpillTimeND* &outPrev,
00099 const SpillTimeND* &outNext )
00100 {
00101
00106
00107 if(context.GetSimFlag()==SimFlag::kMC)
00108 MSG("SpillTimeFinder",Msg::kError) << "MC context in SpillTimeFinder request. This will all end in tears, I know it..." << endl;
00109
00110 outPrev = outNext = 0;
00111
00112
00113 VldTimeStamp kickerTime = context.GetTimeStamp();
00114 Double_t offset = GetOffset(context,fTask);
00115 kickerTime.Add(-offset);
00116
00117 VldContext kickerContext(Detector::kNear,
00118 context.GetSimFlag(),
00119 kickerTime );
00120
00121 MSG("SpillTimeFinder",Msg::kVerbose)
00122 << "STF Query: " << context.AsString() << endl;
00123 MSG("SpillTimeFinder",Msg::kVerbose)
00124 << "Kicker Context: " << kickerContext.AsString() << endl;
00125
00126
00127
00128
00129
00130 if(kickerTime < fLastQueryNext.GetTimeStamp()) {
00131 if(kickerTime > fLastQueryPrev.GetTimeStamp()) {
00132
00133 MSG("SpillTimeFinder",Msg::kDebug) << "Using last call's cached result." << endl;
00134 outPrev = &fLastQueryPrev;
00135 outNext = &fLastQueryNext;
00136 MSG("SpillTimeFinder",Msg::kVerbose) << "Result: " << outPrev->GetTimeStamp().AsString()
00137 << " " << outNext->GetTimeStamp().AsString() << endl;
00138
00139 return;
00140 }
00141 }
00142
00143
00144
00145 fCurrentTable.NewQuery(kickerContext,fTask);
00146
00147
00148
00149 MSG("SpillTimeFinder",Msg::kDebug) << "Requested context, got " << fCurrentTable.GetNumRows() << " rows" << endl;
00150
00151 FindBestRows(fCurrentTable,kickerTime, outPrev, outNext);
00152
00153 MSG("SpillTimeFinder",Msg::kVerbose) << "First query: Prev = "
00154 << ((outPrev==0)?"<null>":outPrev->GetTimeStamp().AsString())
00155 << " "
00156 << ((outNext==0)?"<null>":outNext->GetTimeStamp().AsString())
00157 << endl;
00158
00159
00160
00161
00162 if((outPrev)&&(outNext)) return;
00163
00164
00166
00167
00168
00169
00170 VldTimeStamp curStartVldTime;
00171 VldTimeStamp curStopVldTime;
00172
00173
00174 const DbiValidityRec* curValidity = fCurrentTable.GetValidityRec();
00175 if(curValidity) {
00176
00177 curStartVldTime = curValidity->GetVldRange().GetTimeStart();
00178 curStopVldTime = curValidity->GetVldRange().GetTimeEnd();
00179 } else {
00180 curStartVldTime = kickerTime;
00181 curStopVldTime = kickerTime;
00182 }
00183
00184 fLastQueryRangeBeg = curStartVldTime;
00185 fLastQueryRangeBeg.Add(GetOffset(context,fTask));
00186 fLastQueryRangeEnd = curStopVldTime;
00187 fLastQueryRangeEnd.Add(GetOffset(context,fTask));
00188
00189
00190
00191 while(outPrev ==0) {
00192 if(curStartVldTime < VldTimeStamp(1975,0,0,0,0,0)){
00193 MSG("SpillTimeFinder",Msg::kDebug) << "Hit start of vld range. Hit starting bookend (<1975 AD)" << endl;
00194 outPrev = &kSpillTime_VeryOld;
00195 break;
00196 }
00197
00198 MSG("SpillTimeFinder",Msg::kDebug) << "Hit start of vld range.. looking earlier..." << endl;
00199
00200 const char* sqltxt = Form("(TIMEEND<='%s') and (TASK=%d) and (DETECTORMASK & %d) and (SIMMASK & %d) order by TIMEEND desc limit 1",
00201 curStartVldTime.AsString("s"),
00202 fTask,
00203 kickerContext.GetDetector(),
00204 kickerContext.GetSimFlag() );
00205 MSG("SpillTimeFinder",Msg::kDebug) << "Request: " << sqltxt << endl;
00206
00207 DbiSqlContext myContext(sqltxt);
00208 if(fPrevTable) {
00209 fPrevTable->NewQuery(myContext,Dbi::kAnyTask);
00210 } else {
00211 fPrevTable = new DbiResultPtr<SpillTimeND>("SPILLTIMEND",myContext);
00212 }
00213
00214 if(fPrevTable->GetNumRows()>0) {
00215
00216 MSG("SpillTimeFinder",Msg::kDebug) << "...earlier table gotten. Rows: " << fPrevTable->GetNumRows() << endl;
00217 const SpillTimeND* n;
00218 FindBestRows(*fPrevTable,kickerTime,outPrev,n);
00219 if(n>0) MSG("SpillTimeFinder",Msg::kError) << "Conflict! Found 'next' time in 'previous' table: " << n->GetTimeStamp().AsString() << endl;
00220
00221 } else {
00222 VldTimeStamp nexttry = fPrevTable->GetValidityRec()->GetVldRange().GetTimeStart();
00223 if(nexttry >= curStartVldTime) nexttry = VldTimeStamp(curStartVldTime.GetSec()-1,0);
00224 curStartVldTime = nexttry;
00225 }
00226 }
00227
00228
00229
00230 while(outNext ==0) {
00231 MSG("SpillTimeFinder",Msg::kDebug) << "Hit end of vld range.. looking later..." << endl;
00232 const char* sqltxt = Form("(TIMESTART>='%s') and (TASK=%d) and (DETECTORMASK & %d) and (SIMMASK & %d) order by TIMESTART asc limit 1",
00233 curStopVldTime.AsString("s"),
00234 fTask,
00235 kickerContext.GetDetector(),
00236 kickerContext.GetSimFlag()
00237 );
00238
00239 MSG("SpillTimeFinder",Msg::kDebug) << "Request: " << sqltxt << endl;
00240
00241 DbiSqlContext myContext(sqltxt);
00242 if(fNextTable)
00243 fNextTable->NewQuery(myContext,Dbi::kAnyTask);
00244 else
00245 fNextTable = new DbiResultPtr<SpillTimeND>("SPILLTIMEND",myContext);
00246
00247 if(fNextTable->GetNumRows()>0) {
00248
00249 MSG("SpillTimeFinder",Msg::kDebug) << "...later table gotten. Rows: " << fNextTable->GetNumRows() << endl;
00250 const SpillTimeND* p;
00251
00252 FindBestRows(*fNextTable,kickerTime,p,outNext);
00253 if(p>0) MSG("SpillTimeFinder",Msg::kError) << "Conflict! Found 'previous' time in 'next' table: " << p->GetTimeStamp().AsString() << endl;
00254
00255 } else {
00256 VldTimeStamp nexttry = fNextTable->GetValidityRec()->GetVldRange().GetTimeStart();
00257 if(nexttry <= curStopVldTime) nexttry = VldTimeStamp(curStopVldTime.GetSec()+1,0);
00258 curStopVldTime = nexttry;
00259 }
00260 }
00261
00262
00263 if(outPrev->GetTimeStamp() > kickerTime) MSG("SpillTimeFinder",Msg::kError) << "Sanity check failed. Prev time is late!";
00264 if(outNext->GetTimeStamp() < kickerTime) MSG("SpillTimeFinder",Msg::kError) << "Sanity check failed. Next time is early!";
00265
00266
00267 fLastQueryPrev = *outPrev;
00268 fLastQueryNext = *outNext;
00269
00270 MSG("SpillTimeFinder",Msg::kVerbose) << "Result: " << outPrev->GetTimeStamp().AsString()
00271 << " " << outNext->GetTimeStamp().AsString() << endl;
00272
00273 }
00274
00275
00276
00277 Double_t SpillTimeFinder::GetOffset(const VldContext& context, Int_t task)
00278 {
00285
00286 Double_t offset = 0;
00287
00288 switch(context.GetDetector()) {
00289 case Detector::kFar:
00290 offset += GetOffsetNDNuToFDNu(context);
00291 case Detector::kNear:
00292 if(task == SpillTimeND::kTask_Vtm) {
00293 offset += GetOffsetSgateToNDNu(context);
00294 } else {
00295 offset += GetOffsetKickerToNDNu(context);
00296 }
00297 break;
00298 default:
00299 break;
00300 }
00301 return offset;
00302 }
00303
00304 Double_t SpillTimeFinder::GetOffsetNDNuToFDNu(const VldContext& cx)
00305 {
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 double offset = 0;
00322 fCalibrationNDNuToFDNu.NewQuery(cx,0);
00323 if(fCalibrationNDNuToFDNu.GetNumRows()>0) {
00324 static int sCall = 0;
00325 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo) << "Initial Spill Timing Calibration constants (NDNuToFDNu):" << endl;
00326 for(unsigned int i = 0; i<fCalibrationNDNuToFDNu.GetNumRows(); i++) {
00327 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo)
00328 << Form("%10.5e",fCalibrationNDNuToFDNu.GetRow(i)->GetOffset())
00329 << " +- "
00330 << fCalibrationNDNuToFDNu.GetRow(i)->GetError()
00331 << "\t"
00332 << fCalibrationNDNuToFDNu.GetRow(i)->GetDescription() << endl;
00333
00334 offset += fCalibrationNDNuToFDNu.GetRow(i)->GetOffset();
00335 }
00336 sCall++;
00337 return offset;
00338 }
00339
00340 MAXMSG("SpillTimeFinder",Msg::kWarning,1) << "Could not find SPILLTIMECALIBRATION table." << endl;
00341 MAXMSG("SpillTimeFinder",Msg::kWarning,1) << "Resorting to hard-coded calibration." << endl;
00342
00343 const VldTimeStamp ndSwitch(2006,7,27,14,40,0,0);
00344
00346
00347
00348 offset += 2.44935653818215832*Munits::millisecond;
00349
00350
00351
00352
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 offset += 1.1147*Munits::microsecond;
00372
00374
00375 if(cx.GetTimeStamp() < ndSwitch) {
00376
00377
00378 offset += 0.160*Munits::microsecond;
00379 } else {
00380
00381
00382
00383
00384
00385 offset += 6.7*Munits::nanosecond
00386 +0.2446*Munits::microsecond;
00387
00388 }
00389
00391
00392
00393
00394
00395 offset += 0.450*Munits::microsecond;
00396
00398
00399
00400
00401
00402 offset += 10*Munits::nanosecond;
00403
00405
00406
00407
00408
00409 offset += -7.0*Munits::nanosecond;
00410
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 offset += -5140*Munits::nanosecond;
00428
00430
00431
00432
00433
00434 offset += -30.6547*Munits::microsecond;
00435
00437
00438
00439
00440
00441 offset += -153.0 * Munits::nanosecond;
00442
00444
00445
00446
00447 offset += -27 * Munits::nanosecond;
00448
00449
00451
00452
00453
00454
00456
00457
00458
00459
00460
00461 offset += 16.0*Munits::nanosecond;
00462
00463
00465
00466
00467
00468
00469 return offset;
00470 }
00471
00472 Double_t SpillTimeFinder::GetOffsetKickerToNDNu(const VldContext& cx)
00473 {
00478
00479 double offset = 0;
00480 fCalibrationKickerToNDNu.NewQuery(cx,1);
00481 if(fCalibrationKickerToNDNu.GetNumRows()>0) {
00482 static int sCall = 0;
00483 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo) << "Initial Spill Timing Calibration constants (KickerToNDNu):" << endl;
00484 for(unsigned int i = 0; i<fCalibrationKickerToNDNu.GetNumRows(); i++) {
00485 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo)
00486 << Form("%10.5e",fCalibrationKickerToNDNu.GetRow(i)->GetOffset())
00487 << " +- "
00488 << fCalibrationKickerToNDNu.GetRow(i)->GetError()
00489 << "\t"
00490 << fCalibrationKickerToNDNu.GetRow(i)->GetDescription() << endl;
00491
00492 offset += fCalibrationKickerToNDNu.GetRow(i)->GetOffset();
00493 }
00494 sCall++;
00495 return offset;
00496 }
00497
00498
00500 const double kOffset =
00501
00502
00503 +19*11.064*Munits::microsecond
00504 +6.2*Munits::microsecond
00505
00506
00507
00508
00509
00510 -0.9*Munits::microsecond
00511
00512
00513
00514
00515
00516 - 1.0*Munits::microsecond
00517
00518
00519
00520
00521
00522 - 0.450*Munits::microsecond
00523
00524 ;
00525
00526 return kOffset;
00527 }
00528
00529 Double_t SpillTimeFinder::GetOffsetSgateToNDNu(const VldContext& cx)
00530 {
00535
00536 double offset = 0;
00537 fCalibrationSgateToNDNu.NewQuery(cx,2);
00538 if(fCalibrationSgateToNDNu.GetNumRows()>0) {
00539 static int sCall = 0;
00540 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo) << "Initial Spill Timing Calibration constants (SgateToNDNu):" << endl;
00541 for(unsigned int i = 0; i<fCalibrationSgateToNDNu.GetNumRows(); i++) {
00542 if(sCall==0) MSG("SpillTimeFinder",Msg::kInfo)
00543 << Form("%10.5e",fCalibrationSgateToNDNu.GetRow(i)->GetOffset())
00544 << " +- "
00545 << fCalibrationSgateToNDNu.GetRow(i)->GetError()
00546 << "\t"
00547 << fCalibrationSgateToNDNu.GetRow(i)->GetDescription() << endl;
00548
00549 offset += fCalibrationSgateToNDNu.GetRow(i)->GetOffset();
00550 }
00551 sCall++;
00552 return offset;
00553 }
00554
00555
00556
00557
00558
00559 UInt_t sec = cx.GetTimeStamp().GetSec();
00560 if(sec < 1115450000) {
00561 return 0.4 * Munits::microsecond;
00562 } else if(sec < 1115977300) {
00563 return -0.7 * Munits::microsecond;
00564 } else {
00565 return 1.5 * Munits::microsecond;
00566 }
00567
00568
00569 }
00570
00571
00572 void SpillTimeFinder::FindBestRows(DbiResultPtr<SpillTimeND> &table,
00573 const VldTimeStamp& time,
00574 const SpillTimeND* &outPrev,
00575 const SpillTimeND* &outNext)
00576 {
00582
00583
00584 outPrev = outNext = 0;
00585
00586 UInt_t low = 0;
00587 UInt_t high= table.GetNumRows();
00588
00589 if(high <= 0) return;
00590
00591
00592
00593 double dt;
00594 double minneg=1e99;
00595 double minpos=1e99;
00596
00597
00598 for(UInt_t i=low;i<high;i++) {
00599 const SpillTimeND* row = table.GetRow(i);
00600 dt = GetTimeDifference(row->GetTimeStamp(),time);
00601 if(dt <=0) {
00602 if( (-dt)<minneg ) {
00603 minneg = -dt;
00604 outPrev = row;
00605 }
00606 } else {
00607 if( (dt)<minpos ) {
00608 minpos = -dt;
00609 outNext = row;
00610 }
00611 }
00612 }
00613
00614
00615 const VldTimeStamp tooEarly(1975,0,0,0,0,0,0);
00616
00617 if(outPrev)
00618 if(outPrev->GetTimeStamp() < tooEarly) outPrev = 0;
00619 if(outNext)
00620 if(outNext->GetTimeStamp() < tooEarly) outNext = 0;
00621 }
00622
00623 Double_t SpillTimeFinder::GetTimeDifference(const VldTimeStamp& a,
00624 const VldTimeStamp& b)
00625 {
00626
00627 double d1 = a.GetSec() - b.GetSec();
00628 double d2 = (a.GetNanoSec() - b.GetNanoSec())*1e-9;
00629 return d1+d2;
00630 }
00631
00632
00633
00634
00635
00636
00637 const SpillTimeND& SpillTimeFinder::GetRecentSpill(const VldContext& context)
00638 {
00639
00640
00641 const SpillTimeND* prev;
00642 const SpillTimeND* next;
00643 FindClosestEntries(context,prev,next);
00644 if(prev) return *prev;
00645 else return kSpillTime_VeryOld;
00646 }
00647
00648 const SpillTimeND& SpillTimeFinder::GetNextSpill(const VldContext& context)
00649 {
00650
00651
00652 const SpillTimeND* prev;
00653 const SpillTimeND* next;
00654 FindClosestEntries(context,prev,next);
00655 if(next) return *next;
00656 else return kSpillTime_Future;
00657 }
00658
00659 const SpillTimeND& SpillTimeFinder::GetNearestSpill(const VldContext& context)
00660 {
00661
00662
00663 const SpillTimeND* prev;
00664 const SpillTimeND* next;
00665 FindClosestEntries(context,prev,next);
00666
00667 if((next==0) && (prev==0)) return kSpillTime_VeryOld;
00668
00669 if(!prev) return *next;
00670 if(!next) return *prev;
00671
00672 double offset = GetOffset(context,fTask);
00673 VldTimeStamp prevts = prev->GetTimeStamp();
00674 prevts.Add(offset);
00675 VldTimeStamp nextts = next->GetTimeStamp();
00676 nextts.Add(offset);
00677
00678 double dt1 = GetTimeDifference(prevts,context.GetTimeStamp());
00679 double dt2 = GetTimeDifference(nextts,context.GetTimeStamp());
00680
00681 if(fabs(dt1)<=fabs(dt2)) {
00682 return *prev;
00683 }
00684
00685 return *next;
00686 }
00687
00688 VldTimeStamp SpillTimeFinder::GetTimeOfRecentSpill(const VldContext& cx)
00689 {
00690 VldTimeStamp tspill = GetRecentSpill(cx).GetTimeStamp();
00691 tspill.Add(GetOffset(cx,fTask));
00692 return tspill;
00693 }
00694
00695 VldTimeStamp SpillTimeFinder::GetTimeOfNextSpill(const VldContext& cx)
00696 {
00697 VldTimeStamp tspill = GetNextSpill(cx).GetTimeStamp();
00698 tspill.Add(GetOffset(cx,fTask));
00699 return tspill;
00700 }
00701
00702 VldTimeStamp SpillTimeFinder::GetTimeOfNearestSpill(const VldContext& cx)
00703 {
00704 VldTimeStamp tspill = GetNearestSpill(cx).GetTimeStamp();
00705 tspill.Add(GetOffset(cx,fTask));
00706 return tspill;
00707 }
00708
00709