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.34 2007/11/11 05:51:05 rhatcher 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 const VldTimeStamp ndSwitch(2006,7,27,14,40,0,0);
00320 double offset = 0;
00321
00323
00324
00325 offset += 2.44935653818215832*Munits::millisecond;
00326
00327
00328
00329
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 offset += 1.1147*Munits::microsecond;
00349
00351
00352 if(cx.GetTimeStamp() < ndSwitch) {
00353
00354
00355 offset += 0.160*Munits::microsecond;
00356 } else {
00357
00358
00359
00360
00361
00362 offset += 6.7*Munits::nanosecond
00363 +0.2446*Munits::microsecond;
00364
00365 }
00366
00368
00369
00370
00371
00372 offset += 0.450*Munits::microsecond;
00373
00375
00376
00377
00378
00379 offset += 10*Munits::nanosecond;
00380
00382
00383
00384
00385
00386 offset += -7.0*Munits::nanosecond;
00387
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 offset += -5140*Munits::nanosecond;
00405
00407
00408
00409
00410
00411 offset += -30.6547*Munits::microsecond;
00412
00414
00415
00416
00417
00418 offset += -153.0 * Munits::nanosecond;
00419
00421
00422
00423
00424 offset += -27 * Munits::nanosecond;
00425
00426
00428
00429
00430
00431
00433
00434
00435
00436
00437
00438 offset += 16.0*Munits::nanosecond;
00439
00440
00442
00443
00444
00445
00446 return offset;
00447 }
00448
00449 Double_t SpillTimeFinder::GetOffsetKickerToNDNu(const VldContext&)
00450 {
00456 const double kOffset =
00457
00458
00459 +19*11.064*Munits::microsecond
00460 +6.2*Munits::microsecond
00461
00462
00463
00464
00465
00466 -0.9*Munits::microsecond
00467
00468
00469
00470
00471
00472 - 1.0*Munits::microsecond
00473
00474
00475
00476
00477
00478 - 0.450*Munits::microsecond
00479
00480 ;
00481
00482 return kOffset;
00483 }
00484
00485 Double_t SpillTimeFinder::GetOffsetSgateToNDNu(const VldContext& cx)
00486 {
00491
00492
00493
00494
00495 UInt_t sec = cx.GetTimeStamp().GetSec();
00496 if(sec < 1115450000) {
00497 return 0.4 * Munits::microsecond;
00498 } else if(sec < 1115977300) {
00499 return -0.7 * Munits::microsecond;
00500 } else {
00501 return 1.5 * Munits::microsecond;
00502 }
00503
00504
00505 }
00506
00507
00508 void SpillTimeFinder::FindBestRows(DbiResultPtr<SpillTimeND> &table,
00509 const VldTimeStamp& time,
00510 const SpillTimeND* &outPrev,
00511 const SpillTimeND* &outNext)
00512 {
00518
00519
00520 outPrev = outNext = 0;
00521
00522 UInt_t low = 0;
00523 UInt_t high= table.GetNumRows();
00524
00525 if(high <= 0) return;
00526
00527
00528
00529 double dt;
00530 double minneg=1e99;
00531 double minpos=1e99;
00532
00533
00534 for(UInt_t i=low;i<high;i++) {
00535 const SpillTimeND* row = table.GetRow(i);
00536 dt = GetTimeDifference(row->GetTimeStamp(),time);
00537 if(dt <=0) {
00538 if( (-dt)<minneg ) {
00539 minneg = -dt;
00540 outPrev = row;
00541 }
00542 } else {
00543 if( (dt)<minpos ) {
00544 minpos = -dt;
00545 outNext = row;
00546 }
00547 }
00548 }
00549
00550
00551 const VldTimeStamp tooEarly(1975,0,0,0,0,0,0);
00552
00553 if(outPrev)
00554 if(outPrev->GetTimeStamp() < tooEarly) outPrev = 0;
00555 if(outNext)
00556 if(outNext->GetTimeStamp() < tooEarly) outNext = 0;
00557 }
00558
00559 Double_t SpillTimeFinder::GetTimeDifference(const VldTimeStamp& a,
00560 const VldTimeStamp& b)
00561 {
00562
00563 double d1 = a.GetSec() - b.GetSec();
00564 double d2 = (a.GetNanoSec() - b.GetNanoSec())*1e-9;
00565 return d1+d2;
00566 }
00567
00568
00569
00570
00571
00572
00573 const SpillTimeND& SpillTimeFinder::GetRecentSpill(const VldContext& context)
00574 {
00575
00576
00577 const SpillTimeND* prev;
00578 const SpillTimeND* next;
00579 FindClosestEntries(context,prev,next);
00580 if(prev) return *prev;
00581 else return kSpillTime_VeryOld;
00582 }
00583
00584 const SpillTimeND& SpillTimeFinder::GetNextSpill(const VldContext& context)
00585 {
00586
00587
00588 const SpillTimeND* prev;
00589 const SpillTimeND* next;
00590 FindClosestEntries(context,prev,next);
00591 if(next) return *next;
00592 else return kSpillTime_Future;
00593 }
00594
00595 const SpillTimeND& SpillTimeFinder::GetNearestSpill(const VldContext& context)
00596 {
00597
00598
00599 const SpillTimeND* prev;
00600 const SpillTimeND* next;
00601 FindClosestEntries(context,prev,next);
00602
00603 if((next==0) && (prev==0)) return kSpillTime_VeryOld;
00604
00605 if(!prev) return *next;
00606 if(!next) return *prev;
00607
00608 double dt1 = GetTimeDifference(prev->GetTimeStamp(),context.GetTimeStamp());
00609 double dt2 = GetTimeDifference(next->GetTimeStamp(),context.GetTimeStamp());
00610
00611 if(fabs(dt1)<=fabs(dt2)) {
00612 return *prev;
00613 }
00614
00615 return *next;
00616 }
00617
00618 VldTimeStamp SpillTimeFinder::GetTimeOfRecentSpill(const VldContext& cx)
00619 {
00620 VldTimeStamp tspill = GetRecentSpill(cx).GetTimeStamp();
00621 tspill.Add(GetOffset(cx,fTask));
00622 return tspill;
00623 }
00624
00625 VldTimeStamp SpillTimeFinder::GetTimeOfNextSpill(const VldContext& cx)
00626 {
00627 VldTimeStamp tspill = GetNextSpill(cx).GetTimeStamp();
00628 tspill.Add(GetOffset(cx,fTask));
00629 return tspill;
00630 }
00631
00632 VldTimeStamp SpillTimeFinder::GetTimeOfNearestSpill(const VldContext& cx)
00633 {
00634 VldTimeStamp tspill = GetNearestSpill(cx).GetTimeStamp();
00635 tspill.Add(GetOffset(cx,fTask));
00636 return tspill;
00637 }
00638
00639