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

CoilTools.cxx

Go to the documentation of this file.
00001 #include "CoilTools.h"
00002 
00003 #include "BfldDbiCoilLimits.h"
00004 #include "BfldDbiCoilState.h"
00005 #include "Dcs_Mag_Near.h"
00006 
00007 #include <MessageService/MsgService.h>
00008 CVSID("$Id: CoilTools.cxx,v 1.18 2007/12/07 00:37:46 rhatcher Exp $");
00009 using namespace std;
00010 
00011 #include <DatabaseInterface/DbiTableProxyRegistry.h>
00012 #include <DatabaseInterface/DbiSqlContext.h>
00013 #include <DatabaseInterface/DbiResultPtr.h>
00014 #include <DatabaseInterface/DbiValidityRec.h>
00015 #include <DatabaseInterface/DbiWriter.h>
00016 #include <DatabaseInterface/DbiWriter.tpl>
00017 
00018 #include <cmath>
00019 #include <cassert>
00020 
00021 ClassImp(CoilTools)
00022 
00023 CoilTools* CoilTools::fgInstance = 0;  // initialize pointer to instance
00024 
00025 //_____________________________________________________________________________
00026 
00027 // function templates for extended/local query 
00028 
00029 template <class T> 
00030 void CoilTools::ExtendedQuery(const VldContext& vldc, 
00031                             DbiResultPtr<T>& resultPtr,
00032                             VldRange& resultRange)
00033 {
00034   MSG("Dcs",Msg::kDebug)
00035     << " CoilTools::ExtendedQuery<" << typeid(T).name() 
00036     << "> looking for " << vldc.AsString("sql") << endl;
00037 
00038   // make an extended query on the DB for the Dcs_Mag_Near table
00039   Detector::Detector_t det = vldc.GetDetector();
00040   SimFlag::SimFlag_t  sflg = vldc.GetSimFlag();
00041   VldTimeStamp minTime = vldc.GetTimeStamp();
00042   VldTimeStamp maxTime = vldc.GetTimeStamp();
00043   minTime.Add(-60*60); // only 60 min in reverse direction
00044   maxTime.Add(+fWindow);
00045   // create an extended context
00046   DbiSqlContext econtext(DbiSqlContext::kOverlaps,
00047                          minTime,maxTime,det,sflg);
00048   // update the table with new context
00049   resultPtr.NewQuery(econtext,fTask);
00050   // record what range we requested
00051   resultRange = VldRange(det,sflg,minTime,maxTime,"econtext");
00052   // the DBI range might be bigger as it slops over the ends
00053   const DbiValidityRec* dbiVldRec = resultPtr.GetValidityRec();
00054 
00055   //resultRange = dbiVldRec->GetVldRange();
00056 
00057   if ( dbiVldRec->IsGap() ) {
00058     MAXMSG("Dcs",Msg::kInfo,10)  
00059       << " CoilTools::ExtendedQuery<" << typeid(T).name()
00060       << "> saw a gap for " << vldc.AsString("c")
00061       // << dbiVldRec->GetVldRange().AsString("acs-") // ==> (0,0,now,now,"unknown")
00062       << endl;
00063   }
00064 
00065   MSG("Dcs",Msg::kDebug) 
00066     << "CoilTools::ExtendedQuery<" << typeid(T).name() << "> narrow "
00067     << resultRange.AsString("acs-") 
00068     //<< " dbi " << dbiVldRec->GetVldRange().AsString("acs-")
00069     << " found " << resultPtr.GetNumRows() << " rows " << endl;
00070 
00071 }
00072 
00073 //_____________________________________________________________________________
00074 
00075 template <class T> 
00076 void CoilTools::LocalQuery(const VldContext& vldc, 
00077                            DbiResultPtr<T>& extResPtr,
00078                            std::map<int, const T*>& resultAggMap,
00079                            VldRange& resultRange)
00080 {
00081 // Rummage through the DbiResultPtr set (holding an extended query results)
00082 // to find an appropriate entries (for each aggregate #), put them into the 
00083 // map and return the overall trimmed range.
00084 // Assume that the one with the latest CREATIONDATE is "best" for the
00085 // passed VldContext but we must also trim down the VldRange based on
00086 // other later CREATIONDATE entries for the aggregate.
00087   
00088   MSG("Dcs",Msg::kDebug)
00089     << " Local looking for " << vldc.AsString("sql") << endl;
00090 
00091   // invalidate what we are going to fill
00092   resultAggMap.clear();
00093   resultRange = VldRange();
00094 
00095   // some temporaries
00096   std::map<int, VldTimeStamp> lastCreationDateMap; // = VldTimeStamp::GetBOT();
00097   std::map<int, VldRange>     aggRangeMap;
00098   std::map<int, UInt_t>       iSeqNoUsed; 
00099   typedef std::map<int, const T*>  resMap_t;
00100   typedef typename resMap_t::iterator resItr_t;
00101   resItr_t resItr;
00102 
00103   VldTimeStamp tsVldc = vldc.GetTimeStamp();
00104 
00105   // find the compatible row with latest CREATIONDATE
00106   for ( UInt_t irow = 0; irow < extResPtr.GetNumRows(); ++irow ) {
00107     const T* ptrRow = extResPtr.GetRow(irow);
00108     int aggNo = ptrRow->GetAggregateNo();
00109     const DbiValidityRec* dbiVldRec = extResPtr.GetValidityRec(ptrRow);
00110     const VldRange& rowRange = dbiVldRec->GetVldRange();
00111     if ( rowRange.IsCompatible(vldc) ) {
00112       VldTimeStamp foundCreationDate = dbiVldRec->GetCreationDate();
00113       MSG("Dcs",Msg::kVerbose)
00114         << " row " << irow 
00115         << " SEQNO " << dbiVldRec->GetSeqNo()
00116         << " created " << foundCreationDate.AsString("sql")
00117         << " vld " << rowRange.AsString("acs-")
00118         << endl;
00119 
00120       const T* oldRow = resultAggMap[aggNo];
00121       if ( ! oldRow ) lastCreationDateMap[aggNo] = VldTimeStamp::GetBOT();
00122 
00123       // take the last creation date that satisfies
00124       if ( foundCreationDate > lastCreationDateMap[aggNo] ) {
00125         lastCreationDateMap[aggNo] = foundCreationDate;
00126         resultAggMap[aggNo]        = ptrRow;
00127         aggRangeMap[aggNo]         = rowRange;
00128         iSeqNoUsed[aggNo]          = dbiVldRec->GetSeqNo();
00129       }
00130     }
00131   }
00132 
00133   // prepare to trim the range 
00134   std::map<int, VldTimeStamp> maxStart;
00135   std::map<int, VldTimeStamp> minEnd;
00136   for ( resItr=resultAggMap.begin() ; resItr!=resultAggMap.end() ; ++resItr) {
00137     int aggNo = resItr->first;
00138     maxStart[aggNo] = aggRangeMap[aggNo].GetTimeStart();
00139     minEnd[aggNo]   = aggRangeMap[aggNo].GetTimeEnd();
00140     MSG("Dcs",Msg::kVerbose)
00141       << " aggNo " << aggNo
00142       << " iSeqNoUsed " << iSeqNoUsed[aggNo] << " " 
00143       << aggRangeMap[aggNo].AsString("acs-") << endl;
00144   }
00145 
00146   // trim the ranges
00147   for ( UInt_t irow = 0; irow < extResPtr.GetNumRows(); ++irow ) {
00148     const T* ptrRow = extResPtr.GetRow(irow);
00149     int aggNo = ptrRow->GetAggregateNo();
00150     if ( ptrRow == resultAggMap[aggNo] ) continue;  // don't trim against self
00151     const DbiValidityRec* dbiVldRec = extResPtr.GetValidityRec(ptrRow);
00152     const VldRange& rowRange = dbiVldRec->GetVldRange();
00153     VldTimeStamp foundCreationDate = dbiVldRec->GetCreationDate();
00154 
00155     // skip entries created before the chosen one are not relevant
00156     if ( foundCreationDate < lastCreationDateMap[aggNo] ) continue;
00157 
00158     // Rows that overlap the chosen row but were created after it was
00159     // can trim its range.
00160     VldTimeStamp thisStart = rowRange.GetTimeStart();
00161     VldTimeStamp thisEnd   = rowRange.GetTimeEnd();
00162     //
00163     // start time is inclusive, end time is exclusive
00164     //
00165     // find overlaps
00166     if ( thisEnd   < maxStart[aggNo] ) continue;  // too low  for aggregate
00167     if ( thisStart > minEnd[aggNo]   ) continue;  // too high for aggregate
00168 
00169     //MSG("Dcs",Msg::kVerbose)
00170     //  << " row " << irow << " trim aggno=" << aggNo 
00171     //  << " SEQNO " << dbiVldRec->GetSeqNo()
00172     //  << " thisRnage " << rowRange.AsString("acs-")
00173     //  << endl;
00174 
00175     // trim low end of aggregate's range
00176     if ( thisEnd  < tsVldc && thisEnd > maxStart[aggNo] ) {  
00177       MSG("Dcs",Msg::kVerbose)
00178         << " row " << irow << " trim aggno=" << aggNo 
00179         << " low  " << maxStart[aggNo].AsString("sql")
00180         << " SEQNO " << dbiVldRec->GetSeqNo()
00181         << " created " << foundCreationDate.AsString("sql")
00182         << " vld " << aggRangeMap[aggNo].AsString("acs-")
00183         << endl;
00184       maxStart[aggNo] = thisEnd;
00185     }
00186     // trim high end of aggregate's range
00187     if ( thisStart > tsVldc && thisStart < minEnd[aggNo] ) { 
00188       MSG("Dcs",Msg::kVerbose)
00189         << " row " << irow << " trim aggno=" << aggNo
00190         << " high " << minEnd[aggNo].AsString("sql")
00191         << " SEQNO " << dbiVldRec->GetSeqNo()
00192         << " created " << foundCreationDate.AsString("sql")
00193         << " vld " << aggRangeMap[aggNo].AsString("acs-")
00194         << endl;
00195       minEnd[aggNo] = thisStart;
00196     }
00197   }
00198 
00199   resultRange = VldRange(0xFFFF,0xFFFF,
00200                          VldTimeStamp::GetBOT(),VldTimeStamp::GetEOT(),
00201                          "CoilTools::LocalQuery");
00202   for ( resItr=resultAggMap.begin() ; resItr!=resultAggMap.end() ; ++resItr) {
00203     int aggNo = resItr->first;
00204     // trim aggregate's range
00205     aggRangeMap[aggNo].SetTimeStart(maxStart[aggNo]);
00206     aggRangeMap[aggNo].SetTimeEnd(minEnd[aggNo]);
00207     // trim overall range base on this aggregate
00208     resultRange.TrimTo(aggRangeMap[aggNo]);
00209     MSG("Dcs",Msg::kDebug)
00210       << " trimmed aggNo " << aggNo << " SEQNO "
00211       << extResPtr.GetValidityRec(resultAggMap[aggNo])->GetSeqNo()
00212       << " VldRange " << aggRangeMap[aggNo].AsString("acs-") << endl;
00213   }
00214   MSG("Dcs",Msg::kDebug)
00215     << " overall final VldRange " << resultRange.AsString("acs-") << endl;
00216 
00217   int nfound = resultAggMap.size();
00218   if ( nfound == 0 ) {
00219     MSG("Dcs",Msg::kDebug) 
00220       << "LocalQuery<" << typeid(T).name() 
00221       << " saw no appropriate rows" << endl;
00222   } else if ( nfound != GetNCoils(vldc) ) {
00223     MSG("Dcs",Msg::kDebug) 
00224       << "LocalQuery<" << typeid(T).name() << " saw " << nfound 
00225       << " matching rows (expected " << GetNCoils(vldc) << " for " 
00226       << vldc << " in " 
00227       << extResPtr.GetValidityRec()->GetVldRange().AsString("acs-")
00228       << endl;
00229   }
00230 
00231 }
00232 
00233 //_____________________________________________________________________________
00234 // mini function
00235 int CoilTools::GetNCoils(const VldContext& vldc)
00236 {
00237   // number of coils
00238   switch (vldc.GetDetector()) {
00239   case Detector::kNear:  return 1;
00240   case Detector::kFar:   return 2;
00241   default:               return 0;
00242   }
00243 }
00244 
00245 //_____________________________________________________________________________
00246 
00247 CoilTools::CoilTools()
00248   : fWindow(2*24*60*60)   // by default 48hr window in local cache
00249   , fTask(0)
00250 {
00251   // default ctor
00252   fCoilStateSet.clear();
00253   fMagNearSet.clear();
00254 }
00255 
00256 //_____________________________________________________________________________
00257 
00258 CoilTools& CoilTools::Instance()
00259 {
00260   //MSG("Dcs",Msg::kDebug) << " CoilTools::Instance() " << endl;
00261 
00262   // Cleaner destructor calls CoilTools dtor
00263   static Cleaner cleaner;
00264   
00265   // create singleton instance of CoilTools
00266   if ( ! fgInstance ) {
00267     MSG("Dcs",Msg::kDebug) << "create CoilTools::fgInstance " << endl;
00268     cleaner.UseMe();
00269     fgInstance = new CoilTools();
00270   }
00271   
00272   // die if we couldn't actually create an instance
00273   if ( ! fgInstance ) {
00274     MSG("Dcs",Msg::kFatal) 
00275       << "Could not create CoilTools::fgInstance !!" << endl;
00276     assert(fgInstance);
00277   }
00278 
00279   // return reference to the one-and-only
00280   return *fgInstance;
00281 
00282 }
00283 
00284 //_____________________________________________________________________________
00285 
00286 // Take a row from the DCS_MAG_FAR (or _NEAR) table and decide if we need 
00287 // to write about it in BFLDDBICOILSTATE
00288 void CoilTools::Distill(VldTimeStamp start, 
00289                         VldTimeStamp end, 
00290                         Int_t sm,  
00291                         Float_t curr,
00292                         Detector::Detector_t NearOrFar) {
00293 
00294   // Bail on bad SM or detector flag
00295   if ((sm > 2) || (sm < 1)) {
00296     MSG("Dcs", Msg::kError) << "HOWL!  Bad SM " << sm << endl;
00297     exit(-1);
00298   }
00299   CoilTools::CheckNearOrFar(NearOrFar);
00300 
00301   // Set up distillation parameters
00302   // On first pass, select Near or Far.  We will never mix the two in one job
00303   static Bool_t first = true;
00304   static Double_t MaxTime;
00305   static Double_t MaxDelay;
00306   static Double_t MaxSmallGap;
00307   static Float_t  MaxDeltaCurrent;
00308   if (first) {
00309     first = false;
00310     if (NearOrFar == Detector::kFar) { // Set parameters for Far Det
00311       MSG("Dcs", Msg::kInfo) << "Distilling the Far Detector Coil" << endl;
00312       MaxTime     = 3600.0; // 1 Hour, longest time to 
00313                                                   // wait between distilled
00314                                                   // rows
00315 
00316       MaxDelay    = 900.0;  // 15 Minutes, longest time
00317                                                   // of a gap in which the 
00318                                                   // magnet must have been up 
00319                                                   // the whole time if it's 
00320                                                   // at 80A afterwards, since 
00321                                                   // it takes 15 minutes to 
00322                                                   // ramp up the magnet 
00323                                                   // completely
00324 
00325       MaxSmallGap = 150.0;  // 2.5 Minutes, there are 
00326                                                   // often individual data 
00327                                                   // points dropped.  Given a 
00328                                                   // readout cycle of a bit 
00329                                                   // more than a minute, this 
00330                                                   // delta-t catches these 
00331                                                   // small gaps
00332 
00333       MaxDeltaCurrent = 0.015; // How big a current jump 
00334                                                      // can we tolerate before
00335                                                      // writing out a data 
00336                                                      // point? This is more 
00337                                                      // than 2 ADC ticks, I 
00338                                                      // think
00339     } else { // Set parameters for Near Det
00340       MSG("Dcs", Msg::kInfo) << "Distilling the Near Detector Coil" << endl;
00341       MaxTime     = 3600.0; // 1 Hour, longest time to 
00342                                                   // wait between distilled
00343                                                   // rows
00344 
00345       MaxDelay    = 2700.0; // 45 Minutes, longest time
00346                                                   // of a gap in which the 
00347                                                   // magnet must have been up 
00348                                                   // the whole time.  The ND 
00349                                                   // magnet ramps up much 
00350                                                   // faster than the ACNET 
00351                                                   // readout, so this 
00352                                                   // parameter is useless for 
00353                                                   // ND
00354 
00355       MaxSmallGap = 2700.0; // 45 Minutes, to allow us 
00356                                                   // to miss one readout cycle
00357                                                   // (20min) without freaking 
00358                                                   // out
00359 
00360       MaxDeltaCurrent = 5.1; // How big a current jump 
00361                                                    // can we tolerate before
00362                                                    // writing out a data 
00363                                                    // point?  2.5A seems to be one ADC tick at ND
00364     }
00365   } // end of if (first)
00366 
00367   // Static stuff to remember between calls
00368   static const VldTimeStamp BOT = VldTimeStamp::GetBOT();
00369   static const VldTimeStamp EOT = VldTimeStamp::GetEOT();
00370 
00371   // The last row written out:
00372   static VldTimeStamp LastDistillTime[2]    = {BOT, BOT};
00373   static Float_t      LastDistillCurrent[2] = {0.0, 0.0};
00374 
00375   // The last row read:
00376   static VldTimeStamp LastReadTime[2]       = {BOT, BOT};
00377   static Float_t      LastReadCurrent[2]    = {0.0, 0.0};
00378 
00379   // The row which will next be written out:
00380   static VldTimeStamp SaveReadTime[2]       = {BOT, BOT};
00381   static Float_t      SaveReadCurrent[2]    = {0.0, 0.0};
00382 
00383   // Index for the above arrays
00384   Int_t smindex = sm - 1;
00385 
00386   // If start==EOT, that's the signal to dump the last row saved through
00387   // last row seen unless it happened to have already been dumped, or the last 
00388   // saved value is bogus
00389   if ((start == EOT) && 
00390       (SaveReadTime[smindex] != BOT) &&
00391       (SaveReadTime[smindex] != EOT)) {
00392     MSG("Dcs", Msg::kInfo) << "SM" << sm << " Forced dump of this row "<< endl;
00393     // If row was just dumped, don't do it again
00394     if (SaveReadTime[smindex] == LastReadTime[smindex]) {
00395       MSG("Dcs", Msg::kInfo) << " Row already just dumped "<< endl;
00396     } else {
00397       CoilTools::WriteRow(SaveReadTime[smindex],LastReadTime[smindex],sm,
00398                           SaveReadCurrent[smindex],NearOrFar);
00399     }
00400     // reset saved values to defaults just in case
00401     SaveReadTime[smindex] = BOT;
00402     SaveReadCurrent[smindex] = 0.0;
00403     return;
00404   }
00405 
00406   // Comment out if you want to backfill early stuff
00407   // If LastReadTime is BOT then this is the first call - go to the DB 
00408   // and get the last previous entry as a starting point
00409   if (LastReadTime[smindex] == BOT)
00410     if (!CoilTools::GetLast(start,sm,&LastReadTime[smindex],
00411                             &LastReadCurrent[smindex],NearOrFar)) {
00412       SaveReadTime[smindex] = LastReadTime[smindex];
00413       SaveReadCurrent[smindex] = LastReadCurrent[smindex];
00414     } else {
00415       MSG("Dcs", Msg::kError) << "HOWL!  Can't get initial conditions from DB" << endl;
00416       //      exit(-1);
00417       // For initial run, of course we can't, so comment out this exit
00418     }
00419 
00420   // Spew this one
00421   MSG("Dcs", Msg::kDebug) << "SM" << sm << " Start: " << start.AsString("s") 
00422                           << " End: " << end.AsString("s") << "\tCurr: " 
00423                           << curr << endl;
00424 
00425   // Decide if we need to write a distilled entry.
00426   // 1) More than MaxTime time has elapsed since last one;
00427   // 2) Current has changed by more than MaxDeltaCurrent
00428   // 3) This reading is beyond the last entry + MaxDelay
00429   // 4) If start == EOT write out the last row (unless that row 
00430   //    happened to already have been written out, see above)
00431   // Need to be smarter about this - how long a gap do we really care
00432   // about?  Also need to be able to go back and overide earlier
00433   // validity if a long gap turns out to really be a problem.  Say, a gap
00434   // then a bad current should disqualify the whole gap.
00435 
00436   Float_t DeltaTime    = (Double_t)start - (Double_t)SaveReadTime[smindex];
00437   Float_t DeltaDelay   = (Double_t)start - (Double_t)LastReadTime[smindex];
00438   Float_t DeltaCurrent = curr - SaveReadCurrent[smindex];
00439 
00440   // Check to see if gap in time exists more than MaxSmallGap but less
00441   // than MaxDelay.  If so there may be a problem, but probably not if
00442   // the next data point is at full voltage (as was the last), since
00443   // ramping up that far takes MaxDelay to happen.  Otherwise, dump the row.
00444   // Gap will need to be set manually as with all gaps - but be sure
00445   // to flag this one as bad when you do!
00446   if ((DeltaDelay > MaxSmallGap) && (DeltaDelay < MaxDelay)) {
00447     if ((fabs(curr) < 79.0) || (fabs(LastReadCurrent[smindex]) < 79.0)) {
00448       // Uh-oh, magnet has crashed, dump saved stuff
00449       MSG("Dcs", Msg::kSynopsis) << "SM" << sm << " SAVED: DeltaTime = " 
00450                                  << DeltaTime << " DeltaDelay " 
00451                                  << DeltaDelay << " DeltaCurrent = " 
00452                                  << DeltaCurrent << endl;
00453       MSG("Dcs", Msg::kWarning) << "SM" << sm << " GAP from " 
00454                                 << LastReadTime[smindex].AsString("s") 
00455                                 << " to " 
00456                                 << start.AsString("s") 
00457                                 << " with low current " << curr << endl;
00458       CoilTools::WriteRow(SaveReadTime[smindex],LastReadTime[smindex],sm,
00459                           SaveReadCurrent[smindex],NearOrFar);
00460       // Save this info for next loop
00461       LastDistillTime[smindex] = SaveReadTime[smindex];
00462       LastDistillCurrent[smindex] = SaveReadCurrent[smindex];
00463       SaveReadTime[smindex] = start;
00464       SaveReadCurrent[smindex] = curr;
00465     } else {
00466       // Otherwise just keep on truckin'
00467       MSG("Dcs", Msg::kWarning) << "SM" << sm << " GAP of " << DeltaDelay 
00468                                 << " skipped since current is " << curr 
00469                                 << endl;
00470     }
00471   }
00472 
00473   if ((DeltaTime >= MaxTime) || 
00474       (fabs(DeltaCurrent) >= MaxDeltaCurrent) ||
00475       (DeltaDelay >= MaxDelay)) {
00476     MSG("Dcs", Msg::kSynopsis) << "SM" << sm << " SAVED: DeltaTime = " 
00477                                << DeltaTime << " DeltaDelay " 
00478                                << DeltaDelay << " DeltaCurrent = " 
00479                                << DeltaCurrent << endl;
00480     // If this is not the first row we want to save, we now know the 
00481     // validity of the last one, either:
00482     //   a) if not too big a gap, it stops now
00483     //   b) if too big a gap, take the last known readout as a stop point
00484     //      This leaves a validity gap which corresponds to the unknown
00485     //      time period, needs manually filled in the DB
00486     // don't write an empty row at the start though
00487     if (SaveReadTime[smindex] != BOT) { 
00488       if (DeltaDelay < MaxDelay) {
00489         CoilTools::WriteRow(SaveReadTime[smindex],start,sm,
00490                             SaveReadCurrent[smindex],NearOrFar);
00491       } else {
00492         MSG("Dcs", Msg::kWarning) << "SM" << sm << " GAP from " 
00493                                   << LastReadTime[smindex].AsString("s") 
00494                                   << " to " << start.AsString("s") << endl;
00495         CoilTools::WriteRow(SaveReadTime[smindex],
00496                             LastReadTime[smindex],sm,SaveReadCurrent[smindex],
00497                             NearOrFar);
00498       }
00499       LastDistillTime[smindex] = SaveReadTime[smindex];
00500       LastDistillCurrent[smindex] = SaveReadCurrent[smindex];
00501     }
00502     // Save current info to be start of next distillation
00503     SaveReadTime[smindex] = start;
00504     SaveReadCurrent[smindex] = curr;
00505   }
00506 
00507   // Record this row for future reference
00508   LastReadTime[smindex] = start;
00509   LastReadCurrent[smindex] = curr;
00510 }
00511 
00512 //_____________________________________________________________________________
00513 
00514 // Figure out a status to write
00515 void CoilTools::WriteRow(VldTimeStamp start, 
00516                          VldTimeStamp end, 
00517                          Int_t sm, 
00518                          Float_t curr,
00519                          Detector::Detector_t NearOrFar) {
00520 
00521   CoilTools::CheckNearOrFar(NearOrFar);
00522 
00523   // Figure out a status
00524   UInt_t status = 0;
00525 
00526   VldContext vldc(NearOrFar,SimFlag::kData,start);
00527   std::pair<Float_t,Float_t> limits = CoilCurrentLimits(vldc);
00528   // Switch on which detector
00529   if (NearOrFar == Detector::kFar) {
00530     // Check for reversed field
00531     if (curr < 0.0) status |= CoilStatus::kReverse;
00532     //if ((fabs(curr) < 79.0) || (fabs(curr) > 81.0)) {
00533     // RWH 2007.12 change to using CoilCurrentLimits()
00534     if (fabs(curr) < fabs(limits.first) || 
00535         fabs(curr) > fabs(limits.second)  ) { 
00536       status |= CoilStatus::kBad;
00537       status |= CoilStatus::kBadCurrent;
00538     }
00539   } else {
00540     // Check for reversed field.  Opposite sign convention for ND
00541     if (curr > 0.0) status |= CoilStatus::kReverse;
00542     // Changed from 4955 and 5005, April 2007, ATH
00543     //if ((fabs(curr) < 4940.0) || (fabs(curr) > 4990.0)) { 
00544     // RWH 2007.12 change to using CoilCurrentLimits()
00545     if (fabs(curr) < fabs(limits.first) || 
00546         fabs(curr) > fabs(limits.second)  ) { 
00547       status |= CoilStatus::kBad; 
00548       status |= CoilStatus::kBadCurrent; 
00549     } 
00550   }
00551   CoilTools::Write(start,end,sm,curr,status,NearOrFar);
00552 
00553   // Flagging gaps is done manually.  A tool to write the records after
00554   // a human reads the distiller logs and checks CRL is found in ManualGaps.C
00555 
00556   MSG("Dcs", Msg::kInfo) << "SM" << sm << " DISTILLED: Start: " 
00557                          << start.AsString("s") 
00558                          << " End: "  << end.AsString("s")<< "\tCurr: " 
00559                          << curr << " " << CoilStatus::MaskToString(status) 
00560                          << endl;
00561 }
00562 
00563 //_____________________________________________________________________________
00564 
00565 // Get the last coil row before start for sm, return the time and current
00566 // Need to figure out what to do if that time is in the middle of something 
00567 // instead of on the end.  Hopefully it's always on the end during normal ops.
00568 Int_t CoilTools::GetLast(VldTimeStamp start,   
00569                          Int_t sm,   
00570                          VldTimeStamp *LastTime, 
00571                          Float_t *LastCurr,
00572                          Detector::Detector_t NearOrFar) {
00573 
00574   CoilTools::CheckNearOrFar(NearOrFar);
00575 
00576   // Ask for last time before the start of the current record.
00577   // Originally this code section did not exist, but just asked for the
00578   // last record period.  However, it we are re-running data and trying
00579   // to overlay validities with new, better stuff we need the last entry
00580   // _before_ the current record.
00581   DbiSqlContext myContext = DbiSqlContext("TIMEEND <= \'");
00582   myContext << start.AsString("s")  << '\'';
00583 
00584   // Setup query for detector and SM
00585   if (NearOrFar == Detector::kNear) {
00586     myContext << " AND AGGREGATENO = 1 AND DETECTORMASK & 1 ORDER BY TIMEEND DESC LIMIT 1";
00587   } else {
00588     if (sm==1) 
00589       myContext << " AND AGGREGATENO = 1 AND DETECTORMASK & 2 ORDER BY TIMEEND DESC LIMIT 1";
00590     else
00591       myContext << " AND AGGREGATENO = 2 AND DETECTORMASK & 2 ORDER BY TIMEEND DESC LIMIT 1";
00592   }
00593 
00594   // Actually make the query
00595   DbiResultPtr<BfldDbiCoilState> rsPtr1("BFLDDBICOILSTATE",myContext);
00596 
00597   Int_t numRows = rsPtr1.GetNumRows();
00598   MSG("Dcs", Msg::kDebug) << "The context: " << myContext.GetString() 
00599                           << " selected " << numRows 
00600                           << " rows from the BFLDDBICOILSTATE table" << endl;
00601 
00602   Bool_t FoundIt = false;
00603   // Loop over the entries
00604   for (int i = 0; i < numRows; ++i) {
00605     // Grab the row
00606     const BfldDbiCoilState* mag = rsPtr1.GetRow(i);
00607 
00608     if (mag->GetSupermodule() == sm) {
00609       // Grab that row's validity
00610       const DbiValidityRec* v_rec = rsPtr1.GetValidityRec(mag);
00611       const VldRange&  v_range = v_rec->GetVldRange();
00612       *LastTime = v_range.GetTimeEnd();
00613       // Extract some magnet data
00614       *LastCurr=mag->GetCurrent();
00615       FoundIt = true;
00616       break;
00617     }
00618   }
00619   if (FoundIt) {
00620     MSG("Dcs", Msg::kInfo) << "SM" << sm << " Got last time in DB as " 
00621                             << LastTime->AsString("s")
00622                             << " with current " << *LastCurr << " given " 
00623                             << start.AsString("s") << endl;
00624     return(0);
00625   } else {
00626     MSG("Dcs", Msg::kError) << "SM" << sm << " No last time in DB given " 
00627                             << start.AsString("s") << endl;
00628     return(-1);
00629   }
00630 }
00631 
00632 //_____________________________________________________________________________
00633 
00634 // Format messages, which one can't do from CINT
00635 // Use this to set up where logs will go in the cron jobbed database filler
00636 void CoilTools::FixFormat() {
00637   // Get pointers to the message service and to the stream I want ("Dcs")
00638   MsgService* msvc = MsgService::Instance();
00639   MsgStream*  mstr = msvc->GetStream("Dcs");
00640   
00641   // Set the log level for the stream. If you just want the default
00642   // (kInfo) this line is not needed
00643   mstr->SetLogLevel(Msg::kDebug);
00644   
00645   // Send GAP-related messages off to a file instead of just stdout
00646   // so humans can be notified
00647   // kWarning should be the minimal level the cron job needs to work.  For 
00648   // more, it seems we have to list each level not just a threshold, that's 
00649   // a pain.
00650   mstr->AttachOStream(Msg::kWarning,"distill-gaps.log");
00651   mstr->AttachOStream(Msg::kError,"distill-gaps.log");
00652   mstr->AttachOStream(Msg::kInfo,"distill-gaps.log");
00653   mstr->AttachOStream(Msg::kDebug,"distill-gaps.log");
00654   mstr->AttachOStream(Msg::kSynopsis,"distill-gaps.log");
00655   
00656   // Clean up format flags for warning messages
00657   mstr->RemoveFormat(Msg::kWarning, 
00658                 Msg::kPriority+Msg::kName+Msg::kTime+Msg::kFile+Msg::kCVSId+Msg::kLine);
00659   // Clean up format flags for debug messages
00660   mstr->RemoveFormat(Msg::kDebug, 
00661                 Msg::kPriority+Msg::kName+Msg::kTime+Msg::kFile+Msg::kLine);
00662 }
00663 
00664 //_____________________________________________________________________________
00665 
00666 // Check that NearOrFar is sane
00667 void CoilTools::CheckNearOrFar(Detector::Detector_t NearOrFar) {
00668   if (!((NearOrFar == Detector::kNear) || (NearOrFar == Detector::kFar))) {
00669     MSG("Dcs", Msg::kError) << "HOWL!  Bad Detector Type " 
00670                             << Detector::AsString(NearOrFar) << endl;
00671     exit(-1);
00672   }
00673 }
00674 
00675 //_____________________________________________________________________________
00676 
00677 // The ND stuff is a hack.  One could go distill DCS_MAG_NEAR into
00678 // BfldDbiCoilState entries and just use mostly the same framework.
00679 // However, DCS_MAG_NEAR is already distilled at the data collection end
00680 // of things.  So, just go look there and don't waste time re-distilling
00681 // data.
00682 
00683 Bool_t CoilTools::IsOK(const VldContext& vldc)
00684 { 
00685   // Switch behavior by detector
00686   switch ( vldc.GetDetector() ) {
00687   case Detector::kFar:   
00688     return CoilTools::Instance().IsCoilStateOK(vldc);
00689     break;
00690   case Detector::kNear:  
00691     return CoilTools::Instance().IsMagNearOK(vldc);
00692     break;
00693   default:
00694     return false;
00695   }
00696 }
00697 
00698 Bool_t CoilTools::IsReverse(const VldContext& vldc)
00699 { 
00700   // Switch behavior by detector
00701   switch ( vldc.GetDetector() ) {
00702   case Detector::kFar:
00703     return CoilTools::Instance().IsCoilStateReverse(vldc);
00704     break;
00705   case Detector::kNear:
00706     return CoilTools::Instance().IsMagNearReverse(vldc);
00707     break;
00708   default:
00709     return false;
00710   }
00711 }
00712 
00713 std::pair<Float_t,Float_t> CoilTools::CoilCurrent(const VldContext& vldc)
00714 { 
00715   // Switch behavior by detector 
00716   std::pair<Float_t,Float_t> coil_currents(0,0);
00717 
00718   const BfldDbiCoilState* farsm1;
00719   const BfldDbiCoilState* farsm2;
00720   const Dcs_Mag_Near *nearstate;
00721   switch ( vldc.GetDetector() ) {
00722   case Detector::kFar:
00723     farsm1 = CoilTools::Instance().GetCoilState(vldc,1);
00724     farsm2 = CoilTools::Instance().GetCoilState(vldc,2);
00725     if (farsm1) coil_currents.first  = farsm1->GetCurrent();
00726     if (farsm1) coil_currents.second = farsm2->GetCurrent();
00727     break;
00728   case Detector::kNear:
00729     nearstate = CoilTools::Instance().GetMagNear(vldc);
00730     if (nearstate) {
00731       // just one coil, but set both to be same for convenience
00732       coil_currents.first = coil_currents.second = nearstate->GetCurrent();
00733     }
00734     break;
00735   default:
00736     break;
00737   }
00738   return coil_currents;
00739 }
00740 
00741 // Wrappers for broken out context (assuming kData)
00742 
00743 Bool_t CoilTools::IsOK(VldTimeStamp now, Detector::Detector_t det)
00744 {
00745   // Go get the data at time "now" for detector det
00746   VldContext vldc(det,SimFlag::kData,now);
00747   return CoilTools::IsOK(vldc);
00748 }
00749 
00750 Bool_t CoilTools::IsReverse(VldTimeStamp now, Detector::Detector_t det)
00751 {
00752   // Go get the data at time "now" for detector det
00753   VldContext vldc(det,SimFlag::kData,now);
00754   return CoilTools::IsReverse(vldc);
00755 }
00756 
00757 //_____________________________________________________________________________
00758 std::pair<Float_t,Float_t> CoilTools::CoilCurrentLimits(const VldContext& vldc)
00759 { 
00760   std::pair<Float_t,Float_t> limits(0,0);
00761 
00762   // try the DB, don't abort if table is missing or no results
00763   Dbi::Task task = Dbi::kDefaultTask;
00764   DbiResultPtr<BfldDbiCoilLimits> rsptr_limits(vldc,task,Dbi::kDisabled);
00765   Int_t numrows = rsptr_limits.GetNumRows();
00766   if ( numrows > 0 ) {
00767     if ( numrows > 1 ) {
00768       MAXMSG("Dcs",Msg::kWarning,4)
00769         << "More than one BfldDbiCoilLimits entry for VLD " << vldc << endl;
00770     }
00771     const BfldDbiCoilLimits* limits_row = rsptr_limits.GetRow(0);
00772     limits = limits_row->GetLimits();
00773 
00774     // for test purposes
00775     static int lastSeqNo = 0;
00776     const DbiValidityRec* vldrec = rsptr_limits.GetValidityRec(limits_row);
00777     int currSeqNo = vldrec->GetSeqNo();
00778     if ( currSeqNo != lastSeqNo ) {
00779       MSG("Dcs",Msg::kSynopsis)
00780         << "BfldDbiCoilLimits: "
00781         << limits.first << " to " << limits.second
00782         << ", using SEQNO " << currSeqNo 
00783         << endl
00784         << " for " 
00785         << vldrec->GetVldRange().AsString("acs-") 
00786         << endl;
00787       lastSeqNo = currSeqNo;
00788     }
00789   } else {
00790     // set some defaults in case no DB entry
00791     switch ( vldc.GetDetector() ) {
00792     case Detector::kNear:
00793       // pre April 2007
00794       //limits.first  = 4955.0;
00795       //limits.second = 5005.0;
00796       // post April 2007 through mid Dec 2007
00797       //limits.first  = 4940.0;
00798       //limits.second = 4990.0;
00799       // post Dec 2007 - very wide, to account for noise in readback
00800       limits.first  = 4800.0;  // low limit
00801       limits.second = 5100.0;  // high limit
00802       break;
00803     case Detector::kFar:
00804       limits.first   = 79.0;   // low limit
00805       limits.second  = 81.0;   // high limit 
00806       break;
00807     default:
00808       MAXMSG("Dcs",Msg::kInfo,4) 
00809         << "Calling CoilCurrentLimits() on Detector::k"
00810         << Detector::AsString(vldc.GetDetector())
00811         << " is non-sensical" << endl;
00812       break;
00813     }
00814     MAXMSG("Dcs",Msg::kInfo,1) 
00815       << "No DBI entry for BfldDbiCoilLimits for " << endl
00816       << "   VldContext = " << vldc << endl
00817       << "   use: " << limits.first << " to " << limits.second << endl;
00818   }
00819 
00820   // return best limits
00821   return limits;
00822 }
00823 
00824 //_____________________________________________________________________________
00825 const BfldDbiCoilState* CoilTools::GetCoilState(const VldContext& vldc, int ism)
00826 {
00827   // make sure extended query fCoilState covers requested validity
00828   if ( ! fExtendedRangeCoilState.IsCompatible(vldc) ) {
00829     ExtendedQuery<BfldDbiCoilState>(vldc,fDRPCoilState,fExtendedRangeCoilState);
00830     fLocalRangeCoilState = VldRange();  // invalidate local range
00831   }
00832   // if necessary, find correct row in extended query
00833   if ( ! fLocalRangeCoilState.IsCompatible(vldc) )
00834     LocalQuery<BfldDbiCoilState>(vldc,fDRPCoilState,
00835                                  fCoilStateSet,fLocalRangeCoilState);
00836 
00837   // assume NearDet has sm=1 and FarDet has sm=1,2
00838   if ( ism < 0 || ism > GetNCoils(vldc) ) return 0;
00839   return fCoilStateSet[ism];  // index into array by SM
00840 }
00841 
00842 //_____________________________________________________________________________
00843 
00844 Bool_t CoilTools::IsCoilStateOK(const VldContext& vldc)
00845 { 
00846 
00847   int nOK=0, nBad=0;
00848 
00849   int ncoils = GetNCoils(vldc);
00850   for (int icoil = 1; icoil <= ncoils ; ++icoil ) {
00851     const BfldDbiCoilState* coilState = GetCoilState(vldc,icoil);
00852     if ( ! coilState ) {
00853       // coilState should now be set.  If it isn't for Data it
00854       // is a problem, but for non-Data (i.e. MC)
00855       // assume it is simply "missing" (and OK).
00856       if (vldc.GetSimFlag() != SimFlag::kData) ++nOK; 
00857     } else {
00858       if ( coilState->IsOK() ) ++nOK;
00859       else                     ++nBad;
00860     }
00861   }
00862 
00863   if ( nOK  == ncoils ) return true;
00864   if ( nBad == ncoils ) return false;
00865 
00866   // inconsistent state
00867   static VldTimeStamp lastWarning = VldTimeStamp::GetBOT();
00868   VldTimeStamp thisTime = vldc.GetTimeStamp();
00869   // don't warn but every timeDelta seconds
00870   const int timeDelta = 60*20;  // 20 min
00871   if ( TMath::Abs(lastWarning.GetSec()-thisTime.GetSec()) > timeDelta ) {
00872       MSG("Dcs",Msg::kWarning)
00873         << "CoilTools saw inconsistent OK state " << endl
00874         << "  nOK=" << nOK << " nBad=" << nBad << " of " << ncoils << " coils "
00875         << " for " << vldc.AsString("c") << endl
00876         << "  suppress further warnings in the next " << timeDelta
00877         << " seconds." << endl;
00878       lastWarning = thisTime;
00879     }
00880   return false;  // what to choose, what to choose?  Anything bad ==> not OK
00881 
00882 }
00883 
00884 //_____________________________________________________________________________
00885 
00886 Bool_t CoilTools::IsCoilStateReverse(const VldContext& vldc)
00887 {
00888 
00889   int nfwd=0, nrev=0;
00890 
00891   int ncoils = GetNCoils(vldc);
00892   for (int icoil = 1; icoil <= ncoils ; ++icoil ) {
00893     const BfldDbiCoilState* coilState = GetCoilState(vldc,icoil);
00894     if ( ! coilState ) {
00895       // coilState should now be set.  If it isn't for Data it
00896       // is a problem, but for non-Data (i.e. MC)
00897       // assume it is simply "missing" (and 'forward').
00898       if (vldc.GetSimFlag() != SimFlag::kData) ++nfwd; 
00899     } else {
00900       if ( coilState->GetStatus() & CoilStatus::kReverse ) ++nrev;
00901       else                                                 ++nfwd;
00902     }
00903   }
00904 
00905   if ( nfwd == ncoils ) return false;
00906   if ( nrev == ncoils ) return true;
00907 
00908   static VldTimeStamp lastWarning = VldTimeStamp::GetBOT();
00909   VldTimeStamp thisTime = vldc.GetTimeStamp();
00910   // don't warn but every timeDelta seconds
00911   const int timeDelta = 60*20;  // 20 min
00912   if ( TMath::Abs(lastWarning.GetSec()-thisTime.GetSec()) > timeDelta ) {
00913       MSG("Dcs",Msg::kWarning)
00914         << "CoilTools saw inconsistent polarities " << endl
00915         << "  nforward=" << nfwd << " nreverse=" << nrev
00916         << " for " << vldc.AsString("c") << endl
00917         << "  suppress further warnings in the next " << timeDelta
00918         << " seconds." << endl;
00919       lastWarning = thisTime;
00920     }
00921   return true;  // what to choose, what to choose?  either reverse ==> report reversed
00922 
00923 }
00924 
00925 //_____________________________________________________________________________
00926 
00927 const Dcs_Mag_Near* CoilTools::GetMagNear(const VldContext& vldc)
00928 {
00929   // make sure extended query fMagNear covers requested validity
00930   if ( ! fExtendedRangeMagNear.IsCompatible(vldc) ) {
00931     ExtendedQuery<Dcs_Mag_Near>(vldc,fDRPMagNear,fExtendedRangeMagNear);
00932     fLocalRangeMagNear = VldRange();  // invalidate local range
00933   }
00934   // if necessary, find correct row in extended query
00935   if ( ! fLocalRangeMagNear.IsCompatible(vldc) )
00936     LocalQuery<Dcs_Mag_Near>(vldc,fDRPMagNear,fMagNearSet,fLocalRangeMagNear);
00937 
00938   return fMagNearSet[1];
00939 
00940 }
00941 
00942 //_____________________________________________________________________________
00943 
00944 Bool_t CoilTools::IsMagNearOK(const VldContext& vldc)
00945 {
00946 
00947   const Dcs_Mag_Near* magNear = GetMagNear(vldc);
00948 
00949   if ( ! magNear ) {
00950     // fMagNear should now be set.  If it isn't then assume it's bad
00951     // for data, but simply "missing" for MC.
00952     if (vldc.GetSimFlag() == SimFlag::kData) return false; 
00953     else                                     return true;
00954   }
00955 
00956   std::pair<Float_t,Float_t> limits = CoilCurrentLimits(vldc);
00957   Float_t curr = magNear->GetCurrent();
00958   // Changed from 4955 and 5005, April 2007, ATH
00959   // Changed from 4940 and 4990, December 2007, RWH
00960   if (((fabs(curr) < fabs(limits.first)) || 
00961         fabs(curr) > fabs(limits.second)) ||
00962       (magNear->GetInterLocksComplete() == 0) ||
00963       (magNear->GetPowerSupplyOn() == 0) ||
00964       (magNear->GetGroundFault() == 1) || 
00965       (magNear->GetOverCurrentDC() == 1) || 
00966       (magNear->GetOverTemperature() == 1) ) {
00967     return false;
00968   } else {
00969     return true;
00970   }
00971 
00972 }
00973 
00974 //_____________________________________________________________________________
00975 
00976 Bool_t CoilTools::IsMagNearReverse(const VldContext& vldc)
00977 {
00978 
00979   const Dcs_Mag_Near* magNear = GetMagNear(vldc);
00980 
00981   if ( ! magNear ) {
00982     // fMagNear should now be set.  If it isn't then assume it's bad
00983     // for data, but simply "missing" (and forward) for MC.
00984     if (vldc.GetSimFlag() == SimFlag::kData) return true; 
00985     else                                     return false;
00986   }
00987 
00988   return magNear->GetPolarity();
00989 }
00990 
00991 //_____________________________________________________________________________
00992 
00993 void CoilTools::Write(VldTimeStamp start,   
00994                       VldTimeStamp end,   
00995                       Int_t sm,   
00996                       Float_t curr, 
00997                       UInt_t status,
00998                       Detector::Detector_t det) {
00999   // Ripped from DcsWriter to dump the stuff
01000   Int_t aggNo = sm;
01001   Dbi::Task task = 0;
01002   VldRange OutputRange(det,SimFlag::kData,start,end,"BfldDbiCoilState");
01003   // No creationdate argument below means use overlay times
01004   DbiWriter<BfldDbiCoilState> writer(OutputRange,aggNo,task);
01005   // writer.SetLogComment("Manual Gap Set");  // not needed for this table
01006   BfldDbiCoilState row0(curr,status,(UInt_t)sm);
01007   writer << row0;
01008   writer.Close();
01009 }
01010 
01011 //_____________________________________________________________________________

Generated on Fri Mar 28 15:30:00 2008 for loon by  doxygen 1.3.9.1