/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #include "DybChannelQualitySvc.h" 00002 #include "HardCodedNoisyChannels.h" 00003 #include "ChannelPacked.h" 00004 00005 #include "DatabaseInterface/DbiResultPtr.h" 00006 #include "Conventions/Detectors.h" 00007 #include "Conventions/Electronics.h" 00008 00009 #include "genDbi/GAdWpHvMap.h" 00010 #include "genDbi/GAdWpHvSetting.h" 00011 #include "genDbi/GAdWpHvToFee.h" 00012 #include "genDbi/GDcsAdWpHv.h" 00013 00014 00015 /* From Gassing Li, re channel quality status table: 00016 00017 The final strategy we adopted for the GDqChannelPacked table, for 00018 which the new channel quality service would query, is to pack the 00019 192 status bits ordered by their corresponding FeeChannelId into 7 00020 integers and saved in one payload record. Only the lower 31 bits for 00021 each integer are used for packing status. The packing details are in 00022 the pack method at 00023 00024 http://dayawane.ihep.ac.cn/tracs/dybsvn/browser/dybgaudi/trunk/Database/Scraper/python/Scraper/dq/CQPacker.py 00025 00026 see also 00027 00028 http://dayabay.ihep.ac.cn/DocDB/0090/009090/001/CQ_Service_Status_20130710.pdf 00029 00030 Update: this is augmented with the ability to set bad channels via a 00031 configurable list. Items in this list will override the 00032 GdqChannelPacked table. 00033 00034 */ 00035 #include "genDbi/GDqChannelPacked.h" 00036 // needed to determine ordering of DqChannelPacked bits 00037 #include "genDbi/GCableMap.h" 00038 00039 #include <string> 00040 #include <cmath> 00041 00042 #include <iostream> 00043 #include <sstream> 00044 using namespace std; 00045 00046 DybChanQualCache::DybChanQualCache(const ServiceMode& sm, bool usehv, bool usenoisy) 00047 : m_timelessSM(Context(sm.context().GetSite(), 00048 sm.context().GetSimFlag(), 00049 TimeStamp(0,0), 00050 sm.context().GetDetId()), 00051 sm.task()) 00052 , m_hvlocKey(0) 00053 , m_hvfeeKey(0) 00054 , m_hvgetKey(0) 00055 , m_hvsetKey(0) 00056 , m_dqcpKey(0) 00057 , m_cmapKey(0) 00058 , m_useHV(usehv) 00059 , m_useNoisy(usenoisy) 00060 { 00061 this->update(sm.context().GetTimeStamp()); 00062 } 00063 00064 template<class GTable> 00065 bool update_table(const std::string& name, 00066 const Context& ctx, int task, 00067 DbiResultKey *&kept_key, 00068 DbiResultPtr<GTable> *&resptr) 00069 { 00070 resptr = new DbiResultPtr<GTable>(name.c_str(), ctx, ctx.GetDetId(), task); 00071 const DbiResultKey* key= resptr->GetKey(); 00072 00073 if (key && kept_key) { 00074 if (key->IsEqualTo(kept_key)) { 00075 return false; 00076 } 00077 delete kept_key; 00078 kept_key = new DbiResultKey(key); 00079 return true; 00080 } 00081 00082 if (!key && !kept_key) { 00083 return false; 00084 } 00085 00086 00087 if (key) { 00088 kept_key = new DbiResultKey(key); 00089 return true; 00090 } 00091 00092 delete kept_key; 00093 kept_key = 0; 00094 return true; 00095 } 00096 00097 00098 bool DybChanQualCache::empty() 00099 { 00100 bool full = m_dqcp.size()>0 && m_chlist.size()>0; 00101 if (m_useHV) { 00102 full = full && m_hvset.size()>0 && m_hvget.size()>0; 00103 } 00104 return !full; 00105 } 00106 00107 void DybChanQualCache::check_hvchid(DayaBay::HvChannelId hvch, const std::string& who) 00108 { 00109 if (!hvch.bogus()) { return; } 00110 00111 stringstream ss; 00112 ss << " bogus HvChannelId: " << hvch.asString(); 00113 throw GaudiException(ss.str().c_str(), who, StatusCode::FAILURE); 00114 } 00115 00116 bool DybChanQualCache::update_hvloc(Context& ctx) 00117 { 00118 DbiResultPtr<GAdWpHvMap>* res = 0; 00119 bool updated = update_table<GAdWpHvMap>("AdWpHvMap", 00120 ctx, m_timelessSM.task(), m_hvlocKey, res); 00121 if (updated) { 00122 m_loc2hv.clear(); 00123 unsigned int ind, nrows = res->GetNumRows(); 00124 //cerr << "Updating from AdWpHvMap with " << nrows << " rows @ " << ctx.AsString("E") << endl; 00125 if (!nrows) { 00126 throw GaudiException("DybChannelQualitySvc no AdWpHvMap entries", 00127 "DybChanQualCache",StatusCode::FAILURE); 00128 } 00129 00130 for (ind=0; ind < nrows; ++ind) { 00131 const GAdWpHvMap* row = res->GetRowByIndex(ind); 00132 DayaBay::HvChannelId hvch = row->GetHvChannelId(); 00133 check_hvchid(hvch,"AdWpHvMap"); 00134 std::string loc = row->GetLocationId(); 00135 m_loc2hv[loc] = hvch; 00136 } 00137 } 00138 00139 delete res; 00140 return updated; 00141 } 00142 00143 bool DybChanQualCache::update_hvfee(Context& ctx) 00144 { 00145 DbiResultPtr<GAdWpHvToFee>* res = 0; 00146 bool updated = update_table<GAdWpHvToFee>("AdWpHvToFee", 00147 ctx, m_timelessSM.task(), m_hvfeeKey, res); 00148 if (updated) { 00149 m_hv2fee.clear(); 00150 unsigned int ind, nrows = res->GetNumRows(); 00151 //cerr << "Updating from AdWpHvToFee with " << nrows << " rows @ " << ctx.AsString("E") << endl; 00152 if (!nrows) { 00153 throw GaudiException("DybChannelQualitySvc no AdWpHvToFee entries", 00154 "DybChanQualCache",StatusCode::FAILURE); 00155 } 00156 00157 for (ind=0; ind < nrows; ++ind) { 00158 const GAdWpHvToFee* row = res->GetRowByIndex(ind); 00159 DayaBay::HvChannelId hvch = row->GetHvChannelId(); 00160 check_hvchid(hvch,"AdWpHvToFee"); 00161 DayaBay::FeeChannelId chid = row->GetFeeChannelId(); 00162 m_hv2fee[hvch] = chid; 00163 } 00164 } 00165 delete res; 00166 return updated; 00167 } 00168 00169 DayaBay::FeeChannelId DybChanQualCache::hv2fee(DayaBay::HvChannelId hvch) 00170 { 00171 DayaBay::FeeChannelId feech = m_hv2fee[hvch]; 00172 if (feech.bogus()) { 00173 stringstream ss; 00174 // ss << "Got bogus FeeChannelId out of " << m_hv2fee.size() 00175 // << " from HvChannelId=" << hvch 00176 // << ", crate=" << hvch.crate() 00177 // << ", board=" << hvch.slot() 00178 // << ", channel=" << hvch.channel(); 00179 throw GaudiException(ss.str().c_str(), 00180 "DybChanQualCache",StatusCode::FAILURE); 00181 } 00182 return feech; 00183 } 00184 00185 00186 bool DybChanQualCache::update_hvset(Context& ctx, bool force) 00187 { 00188 DbiResultPtr<GAdWpHvSetting>* res = 0; 00189 bool updated = update_table<GAdWpHvSetting>("AdWpHvSetting", 00190 ctx, m_timelessSM.task(), m_hvsetKey, res); 00191 if (!updated) { updated = force; } 00192 if (updated) { 00193 m_hvset.clear(); 00194 unsigned int ind, nrows = res->GetNumRows(); 00195 //cerr << "Updating from AdWpHvToSetting with " << nrows << " rows @ " << ctx.AsString("E") << endl; 00196 if (!nrows) { 00197 throw GaudiException("DybChannelQualitySvc no AdWpHvSetting entries", 00198 "DybChanQualCache",StatusCode::FAILURE); 00199 } 00200 00201 for (ind=0; ind < nrows; ++ind) { 00202 const GAdWpHvSetting* row = res->GetRowByIndex(ind); 00203 DayaBay::HvChannelId hvch = row->GetHvChannelId(); 00204 check_hvchid(hvch,"AdWpHvSetting"); 00205 DayaBay::FeeChannelId feech = hv2fee(hvch); 00206 m_hvset[feech] = row->GetHvSetting(); 00207 } 00208 } 00209 delete res; 00210 return updated; 00211 } 00212 00213 bool DybChanQualCache::update_hvget(Context& ctx, bool force) 00214 { 00215 DbiResultPtr<GDcsAdWpHv>* res = 0; 00216 bool updated = update_table<GDcsAdWpHv>("DcsAdWpHv", 00217 ctx, m_timelessSM.task(), m_hvgetKey, res); 00218 if (!updated) { updated = force; } 00219 if (updated) { 00220 m_hvget.clear(); 00221 unsigned int ind, nrows = res->GetNumRows(); 00222 //cerr << "Updating from DcsAdWpHv with " << nrows << " rows @ " << ctx.AsString("E") << endl; 00223 if (!nrows) { 00224 throw GaudiException("DybChannelQualitySvc no DcsAdWpHv entries", 00225 "DybChanQualCache",StatusCode::FAILURE); 00226 } 00227 00228 for (ind=0; ind < nrows; ++ind) { 00229 const GDcsAdWpHv* row = res->GetRowByIndex(ind); 00230 std::string loc = row->GetLocationId(); 00231 DayaBay::HvChannelId hvch = m_loc2hv[loc]; 00232 check_hvchid(hvch,loc); 00233 DayaBay::FeeChannelId feech = hv2fee(hvch); 00234 m_hvget[feech] = row->GetVoltage(); 00235 } 00236 } 00237 delete res; 00238 return updated; 00239 } 00240 00241 bool DybChanQualCache::update_cmap(Context& ctx) 00242 { 00243 DbiResultPtr<GCableMap>* res = 0; 00244 bool updated = update_table<GCableMap>("CableMap", 00245 ctx, m_timelessSM.task(), m_cmapKey, res); 00246 if (updated) { 00247 m_chlist.clear(); 00248 unsigned int ind=0, nrows = res->GetNumRows(); 00249 if (!nrows) { 00250 throw GaudiException("DybChannelQualitySvc no CableMap entries", 00251 "DybChanQualCache",StatusCode::FAILURE); 00252 } 00253 00254 for (ind=0; ind<nrows; ++ind) { 00255 const GCableMap* row = res->GetRowByIndex(ind); 00256 DayaBay::AdPmtSensor pmt(row->GetSensorId().fullPackedData()); 00257 if (! pmt.is8inch()) { 00258 continue; 00259 } 00260 m_chlist.push_back(row->GetChannelId().fullPackedData()); 00261 } 00262 m_chlist.sort(); 00263 } 00264 delete res; 00265 return updated; 00266 } 00267 bool DybChanQualCache::update_dqcp(Context& ctx) 00268 { 00269 DbiResultPtr<GDqChannelPacked>* res = 0; 00270 bool updated = update_table<GDqChannelPacked>("DqChannelPacked", 00271 ctx, m_timelessSM.task(), m_dqcpKey, res); 00272 if (updated) { 00273 unsigned int nrows = res->GetNumRows(); 00274 if (!nrows) { 00275 throw GaudiException("DybChannelQualitySvc no DqChannelPacked entries", 00276 "DybChanQualCache",StatusCode::FAILURE); 00277 } 00278 00279 if (nrows > 1) { 00280 cerr << "Got ignoring additional ("<<nrows-1<<") DqChannelPacked results for " << ctx.AsString() << endl; 00281 } 00282 const GDqChannelPacked* row = res->GetRowByIndex(0); 00283 ChannelPacked::CQpacked packed; 00284 packed.push_back(row->GetMask0()); 00285 packed.push_back(row->GetMask1()); 00286 packed.push_back(row->GetMask2()); 00287 packed.push_back(row->GetMask3()); 00288 packed.push_back(row->GetMask4()); 00289 packed.push_back(row->GetMask5()); 00290 packed.push_back(row->GetMask6()); 00291 00292 ChannelPacked::CQbits channel_quality = ChannelPacked::unpack(packed); 00293 00294 ChList_t::iterator it, done = m_chlist.end(); 00295 int cqind = 0; 00296 m_dqcp.clear(); 00297 for (it=m_chlist.begin(); it != done; ++it, ++cqind) { 00298 DayaBay::FeeChannelId chid(*it); 00299 m_dqcp[chid] = channel_quality[cqind]; // whew 00300 } 00301 } 00302 delete res; 00303 return updated; 00304 00305 } 00306 00307 00308 // FIXME: see where called below, for now, always update 00309 bool DybChanQualCache::update_noise(Context& ctx, bool /*force*/) 00310 { 00311 //cerr << "update_noise("<<ctx.AsString("E")<<") clearing " << m_noise.size() << " channels" << endl; 00312 m_noise.clear(); 00313 00314 for (int ind=0; Dyb::noisy_channels[ind].channel.fullPackedData(); ++ind) { 00315 Dyb::NoisyChannel& nc = Dyb::noisy_channels[ind]; 00316 //cerr << "update_noise() checking: " << nc.channel << " from " << nc.start.AsString("E") << " to " << nc.stop.AsString("E") << endl; 00317 00318 if (! nc.covered(ctx)) { continue; } 00319 //cerr << "Caching based on " << ctx.AsString("E") << endl; 00320 m_noise[nc.channel] = nc.noise; 00321 } 00322 00323 //cerr << "update_noise(): cached " << m_noise.size() << " noisy channels" << endl; 00324 return true; 00325 } 00326 00327 // Maybe update cache based on a low level DBI update. Return 00328 // true if an update happened 00329 bool DybChanQualCache::update(const TimeStamp& ts) 00330 { 00331 // Progressively check more expensively if this timestamp is "new" 00332 00333 if (ts.GetSec() == m_lastTS.GetSec() && ts.GetNanoSec() == m_lastTS.GetNanoSec()) { 00334 //cerr << "Cache clean on timestamp value: " << ts.AsString() << endl; 00335 return false; 00336 } 00337 m_lastTS = ts; 00338 00339 Context ctx = m_timelessSM.context(); 00340 ctx.SetTimeStamp(ts); 00341 00342 //cerr << "Checking cache for " << ctx.AsString("E") << endl; 00343 00344 bool updated_hv = false; 00345 if (m_useHV) { 00346 bool updated_hvloc = update_hvloc(ctx); 00347 bool updated_hvfee = update_hvfee(ctx); 00348 bool updated_hvset = update_hvset(ctx, updated_hvfee); 00349 bool updated_hvget = update_hvget(ctx, updated_hvfee|updated_hvloc); 00350 updated_hv = updated_hvset || updated_hvget; 00351 } 00352 00353 /*bool updated_cmap =*/ update_cmap(ctx); 00354 bool updated_dqcp = update_dqcp(ctx); 00355 00356 if (m_useNoisy) { 00357 update_noise(ctx, true); 00358 } 00359 00360 return updated_hv || updated_dqcp; 00361 } 00362 00363 00364 bool DybChanQualCache::covers(const TimeStamp& start, const TimeStamp& stop) 00365 { 00366 return start <= m_lastTS && m_lastTS < stop; 00367 } 00368 00369 00370 // 00371 // DybChannelQuality view (with ownership) into the cache 00372 // 00373 00374 DybChannelQuality::DybChannelQuality(DybChanQualCache* cdc, std::vector<Dyb::ChannelOverride>& chor, 00375 float delta_hv, 00376 bool usehv, bool usenoisy) 00377 : m_cdc(cdc) 00378 , m_deltaHV(delta_hv) 00379 , m_useHV(usehv) 00380 , m_useNoisy(usenoisy) 00381 , m_chor(chor) 00382 { 00383 00384 } 00385 00386 DybChannelQuality::~DybChannelQuality() 00387 { 00388 delete m_cdc; 00389 m_cdc = 0; 00390 } 00391 00392 bool DybChannelQuality::good(DayaBay::FeeChannelId chid) const 00393 { 00394 size_t nchors = m_chor.size(); 00395 if (nchors) { 00396 //cerr << "Looking for " << chid.asString() << " out of " << nchors << endl; 00397 for (size_t ind=0; ind < nchors; ++ind) { 00398 const Dyb::ChannelOverride& chor = m_chor[ind]; 00399 if (chor.channel != chid) { 00400 //cerr << "\twrong channel != " << chor.channel.asString() << endl; 00401 continue; 00402 } 00403 if (!m_cdc->covers(chor.start, chor.stop)) { 00404 //cerr << "\tdoes not cover " << chor.start.AsString() << " -- " << chor.stop.AsString() << endl; 00405 continue; 00406 } 00407 //cerr << "\tgot it, qual = " << chor.good << endl; 00408 return chor.good; 00409 } 00410 } 00411 else { 00412 //cerr << "No overrides " << chid.asString() << endl; 00413 } 00414 00415 if (m_useHV) { 00416 float requested = hvRequested(chid); 00417 if (requested < m_deltaHV) { 00418 return false; 00419 } 00420 00421 float measured = hvMeasured(chid); 00422 if (measured < m_deltaHV) { 00423 return false; 00424 } 00425 00426 if (fabs(requested-measured) > m_deltaHV) { 00427 return false; 00428 } 00429 } 00430 00431 if (m_useNoisy) { 00432 if (noise(chid) > Dyb::noisy_channel_cut) { 00433 return false; 00434 } 00435 } 00436 00437 // Return bad if channel is bad or not found (-1). If not found 00438 // something is really wrong! We should really assert that it's 00439 // not negative but the desired strategy from the calib group is 00440 // to fail towards acceptance. So the impossible is merely 00441 // considered bad here. 00442 if (goodDqCp(chid) <= 0) { 00443 return false; 00444 } 00445 00446 // Hurrah! 00447 return true; 00448 } 00449 00450 int DybChannelQuality::goodDqCp(DayaBay::FeeChannelId chid) const 00451 { 00452 DybChanQualCache::DqCpMap_t& dqcp = m_cdc->channel_quality(); 00453 DybChanQualCache::DqCpMap_t::iterator it = dqcp.find(chid); 00454 if (it == dqcp.end()) { return -1; } 00455 return it->second; 00456 } 00457 00458 float DybChannelQuality::hvRequested(DayaBay::FeeChannelId chid) const 00459 { 00460 return m_cdc->setted_hv()[chid]; 00461 } 00462 00463 float DybChannelQuality::hvMeasured(DayaBay::FeeChannelId chid) const 00464 { 00465 return m_cdc->getted_hv()[chid]; 00466 } 00467 00468 float DybChannelQuality::noise(DayaBay::FeeChannelId chid) const 00469 { 00470 DybChanQualCache::HvValMap_t& n = m_cdc->noise(); 00471 00472 DybChanQualCache::HvValMap_t::iterator it = n.find(chid); 00473 if (it == n.end()) { return 0.0; } // no noise is good noise 00474 return it->second; 00475 } 00476 00477 00478 00480 IChannelQuality::ChannelSet_t DybChannelQuality::channels() const 00481 { 00482 IChannelQuality::ChannelSet_t ret; 00483 00484 DybChanQualCache::DqCpMap_t& cqmap = m_cdc->channel_quality(); 00485 DybChanQualCache::DqCpMap_t::iterator it, done = cqmap.end(); 00486 00487 for (it=cqmap.begin(); it != done; ++it) { 00488 ret.push_back(it->first); 00489 } 00490 return ret; 00491 } 00492 00493 // 00494 // DybChannelQualitySvc 00495 // 00496 00497 DybChannelQualitySvc::DybChannelQualitySvc(const std::string& name, ISvcLocator *svc) 00498 : Service(name,svc) 00499 , m_lastSM() 00500 { 00501 declareProperty("UseHV", m_useHV=false,"Consider HV tables"); 00502 declareProperty("UseNoisy", m_useNoisy=false,"Consider hard coded noisy channels"); 00503 00504 declareProperty("ChannelOverride", m_chor_strings, 00505 "List of channel override strings."); 00506 00507 } 00508 00509 00510 DybChannelQualitySvc::~DybChannelQualitySvc() 00511 { 00512 } 00513 00514 StatusCode DybChannelQualitySvc::initialize() 00515 { 00516 StatusCode sc = this->Service::initialize(); 00517 if( sc.isFailure() ) return sc; 00518 00519 size_t nchor = m_chor_strings.size(); 00520 //cerr << "DybChannelQualitySvc::initialize() with #chor = " << nchor << endl; 00521 for (size_t ind=0; ind<nchor; ++ind) { 00522 string chor = m_chor_strings[ind]; 00523 m_chor.push_back(Dyb::ChannelOverride(chor)); 00524 //cerr << "\tchor: " << chor << endl; 00525 } 00526 return StatusCode::SUCCESS; 00527 } 00528 00529 const IChannelQuality* DybChannelQualitySvc::get(const ServiceMode& sm) 00530 { 00531 ServiceMode timeless(Context(sm.context().GetSite(), 00532 sm.context().GetSimFlag(), 00533 TimeStamp(0,0), 00534 sm.context().GetDetId()), 00535 sm.task()); 00536 CacheMap_t::iterator it = m_cache.find(timeless); 00537 if (it == m_cache.end()) { 00538 return 0; 00539 } 00540 return it->second; 00541 } 00542 00543 void DybChannelQualitySvc::clearChannel(const ServiceMode& timeless_sm) 00544 { 00545 CacheMap_t::iterator it = m_cache.find(timeless_sm); 00546 if (it == m_cache.end()) { 00547 return; // can't clear what we don't have 00548 } 00549 00550 delete it->second; 00551 m_cache.erase(it); 00552 } 00553 00554 const IChannelQuality* DybChannelQualitySvc::channelQuality(const ServiceMode& sm) 00555 { 00556 // First to trivial tests in case users is lazy and re-calls us 00557 00558 if (sm.context() == m_lastSM.context() && sm.task() == m_lastSM.task()) { 00559 //cerr << "Clean on ServiceMode value" << endl; 00560 return this->get(sm); 00561 } 00562 m_lastSM = sm; 00563 00564 00565 // Fresh SM, got to dig deeper 00566 00567 //cerr << "Checking cache based on " << sm.context().AsString("E") << endl; 00568 00569 Context ctx = sm.context(); 00570 ctx.SetTimeStamp(TimeStamp::GetBOT()); 00571 ServiceMode timeless_sm(ctx,sm.task()); 00572 00573 // Get, and make if needed, the DCQ for the given SM, neglecting 00574 // the time. 00575 DybChannelQuality* dcq = 0; 00576 CacheMap_t::iterator it = m_cache.find(timeless_sm); 00577 00578 try { 00579 00580 if (it == m_cache.end()) { // first time to see this SM 00581 DybChanQualCache* dcq_cache = new DybChanQualCache(sm, m_useHV, m_useNoisy); 00582 // full SM here! 00583 dcq = new DybChannelQuality(dcq_cache, m_chor, 15.0, m_useHV, m_useNoisy); 00584 m_cache[timeless_sm] = dcq; 00585 //cerr << "New cache based on " << sm.context().AsString("E") << endl; 00586 } 00587 else { // been there, done that 00588 dcq = it->second; 00589 bool upped = dcq->cache().update(sm.context().GetTimeStamp()); 00590 if (upped) { 00591 //cerr << "Updated cache based on " << sm.context().AsString("E") << endl; 00592 } 00593 00594 } 00595 00596 } 00597 catch (const GaudiException& ge) { 00598 //cerr << "Exception during update: " << ge << " at " << sm.context().AsString("E") << endl; 00599 this->clearChannel(timeless_sm); 00600 dcq = 0; 00601 return 0; 00602 } 00603 00604 if (dcq && dcq->cache().empty()) { 00605 //cerr << "Got ChannelQuality but it is empty: at " << sm.context().AsString("E") << endl; 00606 this->clearChannel(timeless_sm); 00607 dcq = 0; 00608 return 0; 00609 } 00610 00611 return dcq; 00612 } 00613 00614 StatusCode DybChannelQualitySvc::queryInterface(const InterfaceID& riid, 00615 void** ppvInterface) 00616 { 00617 StatusCode sc = StatusCode::FAILURE; 00618 if (ppvInterface) { 00619 *ppvInterface = 0; 00620 00621 if (IChannelQualitySvc::interfaceID().versionMatch(riid)) { 00622 *ppvInterface = static_cast<IChannelQualitySvc*>(this); 00623 sc = StatusCode::SUCCESS; 00624 addRef(); 00625 } 00626 else sc = Service::queryInterface( riid, ppvInterface ); 00627 } 00628 return sc; 00629 } 00630