50 const TObject&
object,
51 const dqm_core::AlgorithmConfig&
config ) {
54 if(
object.
IsA()->InheritsFrom(
"TH1" ) ) {
57 throw dqm_core::BadConfig( ERS_HERE, name,
"dimension > 2 " );
60 throw dqm_core::BadConfig( ERS_HERE, name,
"does not inherit from TH1" );
73 bool reverseConvention = TString(
histogram->GetYaxis()->GetTitle()).EndsWith(
"+y");
75 std::map<std::string,std::set<std::pair<int,int>>> knownBins;
77 auto knownBinParser = [&](
const std::string& cutName) {
81 while (i <
known.length() && !std::isdigit(
known[i])) {
87 while(i != std::string::npos) {
88 size_t j =
known.find(
";");
89 knownBins[cutName].insert({TString(
known.substr(0,i)).Atoi(),TString(
known.substr(i+1,j-i-1)).Atoi()});
95 std::vector<std::pair<double,std::string>> orderedCuts;
96 double mostNegativeCut = 0;
97 for(
auto& [k,v] :
config.getParameters()) {
99 if(!kk.EndsWith(
"Cut"))
continue;
100 kk = kk(0,kk.Length()-3);
101 orderedCuts.push_back({v,kk.Data()});
102 mostNegativeCut = std::min(mostNegativeCut,v);
103 knownBinParser(kk.Data());
105 knownBinParser(
"Dead");
108 std::sort(orderedCuts.begin(),orderedCuts.end(),[](
const auto& v1,
const auto& v2) { return std::abs(v1.first) > std::abs(v2.first); });
110 if (
histogram->GetEntries() < minstat ) {
111 dqm_core::Result *
result =
new dqm_core::Result(dqm_core::Result::Undefined);
112 result->status_ = dqm_core::Result::Yellow;
120 std::map<int,dqm_core::Result*> resultsByTimeBin;
121 std::map<std::string,int> counts;
122 dqm_core::Result* lastFilledResult =
nullptr;
124 for(
int t=(nBinsZ>0 ? range[0] : -1) ; t <= (nBinsZ>0 ? range[1] : -1); t++) {
125 int xmin = range[0],
xmax = range[1];
126 int ymin = range[2],
ymax = range[3];
135 std::set<int> filledRows;
138 std::vector<double> stripsMedian;
139 std::vector<double> stripsAvg;
140 std::vector<double> stripsVariance;
141 std::vector<size_t> stripsN;
142 std::vector<double> stripsProb;
144 for (
int i =
xmin; i <=
xmax; ++i ) {
145 std::vector<double> onestrip;
147 for (
int j =
ymin; j <=
ymax; ++j ) {
149 if (binvalue < ignoreBelow)
continue;
150 if(binvalue>0) filledRows.insert(j);
152 bool knownAnomaly=
false;
153 for(
auto& [k,v] : knownBins) {
154 if(v.find({i,j})!=v.end()) {
155 knownAnomaly =
true;
break;
159 onestrip.push_back(binvalue);
160 stripSum += binvalue;
164 stripsAvg.push_back(stripSum/onestrip.size());
169 std::sort(onestrip.begin(),onestrip.end());
171 stripsMedian.push_back( onestrip.at(onestrip.size()/2) );
173 stripsVariance.push_back( std::pow((onestrip.at(onestrip.size()*0.84) - onestrip.at(onestrip.size()*0.16))/2.,2) );
174 stripsN.push_back(onestrip.size());
176 if(stripsVariance.back() > 0) {
177 std::vector<double> stripRef;
178 for (
size_t i = 0; i < onestrip.size(); i++) {
183 nextVal = (stripsVariance.back()>=100) ?
r.Gaus(stripsAvg.back(), std::sqrt(stripsVariance.back())) :
r.Poisson(stripsAvg.back());
184 }
while(nextVal<ignoreBelow);
185 stripRef.push_back(nextVal);
187 std::sort(stripRef.begin(),stripRef.end());
188 stripsProb.push_back( TMath::KolmogorovTest(onestrip.size(),&onestrip[0],stripRef.size(),&stripRef[0],
"") );
190 stripsProb.push_back(1);
193 if(nBinsZ>0 && filledRows.empty()) {
197 dqm_core::Result*
result =
new dqm_core::Result();
198 std::map<std::pair<int,int>,
bin>
bins;
199 for (
int k =
xmin; k <=
xmax; ++k ) {
200 double strip_median = stripsMedian[k -
xmin];
201 double strip_variance = stripsVariance[k -
xmin];
202 for (
int l =
ymin; l <=
ymax; ++l) {
204 if (binvalue < ignoreBelow)
continue;
205 double residual = (strip_variance) ? ((binvalue - strip_median) / std::sqrt(strip_variance)) : 0;
206 bins[{k,l}] = { k, l,
212 bool testDeadStrips = (filledRows.size() ==
size_t(
ymax-
ymin+1));
217 counts[
"NDeadStrip"]= (testDeadStrips) ? 0 : -1;
219 counts[
"NWrongKnown"]=0;
220 counts[
"NConsecUnlikelyStrip"]=0;
221 for(
auto& [cut,k] : orderedCuts) {
226 int nUnlikelyStrips = 0;
227 for(
size_t i = 0;i<stripsVariance.size();i++) {
228 if (testDeadStrips && stripsVariance.at(i) == 0 && stripsAvg.at(i) == 0) {
230 if( (i>0 && (stripsAvg.at(i-1)*stripsN.at(i-1))>=minstat) || (i<stripsVariance.size()-1 && (stripsAvg.at(i+1)*stripsN.at(i+1))>=minstat)) {
231 result->tags_[TString::Format(
"_DeadStrip%02ld", i+1).Data()] =
histogram->GetXaxis()->GetBinCenter(
xmin + i);
232 counts[
"NDeadStrip"]++;
236 if (stripsProb.at(i) < probThreshold) {
237 result->tags_[TString::Format(
"_UnlikelyStrip%02ld", i+1).Data()] = -log(stripsProb.at(i));
239 if(nUnlikelyStrips > counts[
"NConsecUnlikelyStrip"]) counts[
"NConsecUnlikelyStrip"] = nUnlikelyStrips;
243 if(publishDetail & 0x1) {
244 result->tags_[TString::Format(
"_Median%02ld", i+1).Data()] = stripsMedian.at(i);
246 if(publishDetail & 0x2) {
247 result->tags_[TString::Format(
"_StdDev%02ld", i+1).Data()] = sqrt(stripsVariance.at(i));
249 if(publishDetail & 0x4) {
250 result->tags_[TString::Format(
"_Prob%02ld", i+1).Data()] = stripsProb.at(i);
252 if(publishDetail & 0x8) {
254 result->tags_[TString::Format(
"_Noise%02ld", i+1).Data()] = sqrt(std::abs(stripsVariance.at(i) - stripsMedian.at(i)));
268 if( (publishDetail & 0x10) &&
bin.
m_value==0) {
273 for(
auto& [cut,k] : orderedCuts) {
278 result->tags_[TString::Format(
"_%s(%d,%d)", k.c_str(),
bin.
m_ix,
283 result->tags_[TString::Format(
"_Known%s(%d,%d)",k.c_str(),
bin.
m_ix,
291 if(
bin.
m_value>0 && knownBins[
"Dead"].find({bin.m_ix,bin.m_iy})!=knownBins[
"Dead"].end()) {
292 counts[
"NWrongKnown"]++;
295 }
else if(classCut != 0) {
297 for(
auto& [cut,k] : orderedCuts) {
299 if(cut*classCut < 0) {
300 counts[
"NWrongKnown"]++;
301 result->tags_[TString::Format(
"_Un%s(%d,%d)",k.c_str(),
bin.
m_ix,
309 resultsByTimeBin[t] =
result;
310 lastFilledResult =
result;
317 counts[
"NDeadStrip"]= 0;
319 counts[
"NWrongKnown"]=0;
320 counts[
"NConsecUnlikelyStrip"]=0;
321 for(
auto& [cut,k] : orderedCuts) {
324 dqm_core::Result* lastResult =
nullptr;
325 result =
new dqm_core::Result();
327 std::map<std::string,int> anomalies;
328 for(
int t=range[0];t<=range[1]+1;t++) {
329 if(resultsByTimeBin.find(t)==resultsByTimeBin.end()) {
331 for(
auto& [k,v] : anomalies) {
333 if(printLevel<=2) std::cout <<
" Got anomaly: " << k <<
" duration: " << v <<
" end: " << t << std::endl;
334 int lbStart =
histogram->GetXaxis()->GetBinLowEdge(t-v);
335 int lbEnd =
histogram->GetXaxis()->GetBinLowEdge(t);
339 result->tags_[k] = lastResult->tags_[k];
342 TString::Format(
"_LB%d-%d", lbStart, lbEnd).Data()] = lastResult->tags_[k];
346 if(k.find(
"_DeadStrip")==0) {
347 counts[
"NDeadStrip"]++;
348 }
else if(k.find(
"_Dead")==0) {
350 }
else if(k.find(
"_UnlikelyStrip")==0) {
352 }
else if(k.find(
"_Un")==0) {
353 counts[
"NWrongKnown"]++;
355 for(
auto& [cut,k2] : orderedCuts) {
356 if(k.find(
"_" + k2)==0) {
365 auto thisResult = resultsByTimeBin[t];
366 if(liveMode && thisResult==lastFilledResult) {
373 for(
auto& [k,v] : thisResult->tags_) {
375 if(k.find(
"_DeadStrip")==0) {
377 }
else if(k.find(
"_Dead")==0) {
379 }
else if(k.find(
"_UnlikelyStrip")==0) {
381 }
else if(k.find(
"_Un")==0) {
384 for(
auto& [cut,k2] : orderedCuts) {
385 if(k.find(
"_" + k2)==0) {
394 for(
auto& [k,v] : anomalies) {
395 if(thisResult->tags_.find(k) != thisResult->tags_.end())
continue;
397 int lbStart =
histogram->GetXaxis()->GetBinLowEdge(t-v);
398 int lbEnd =
histogram->GetXaxis()->GetBinLowEdge(t);
402 result->tags_[k+TString::Format(
"_LB%d-%d",lbStart,lbEnd).Data()]=lastResult->tags_[k];
406 if(k.find(
"_DeadStrip")==0) {
407 counts[
"NDeadStrip"]++;
408 }
else if(k.find(
"_Dead")==0) {
410 }
else if(k.find(
"_UnlikelyStrip")==0) {
412 }
else if(k.find(
"_Un")==0) {
413 counts[
"NWrongKnown"]++;
415 for(
auto& [cut,k2] : orderedCuts) {
416 if(k.find(
"_" + k2)==0) {
425 if(lastResult)
delete lastResult;
426 lastResult = thisResult;
429 if(lastResult)
delete lastResult;
434 result = resultsByTimeBin[-1];
441 const auto& redThresholds =
config.getRedThresholds();
442 const auto& greenThresholds =
config.getGreenThresholds();
443 result->status_ = dqm_core::Result::Undefined;
444 if(publishDetail & 0x20) {
445 result->tags_[
"StatusCode"] = 0;
447 for(
auto& [k,v] : counts) {
448 if(nBinsZ>0 && k==
"NConsecUnlikelyStrip")
continue;
451 result->status_ = dqm_core::Result::Red;
452 if(publishDetail & 0x20) {
453 result->tags_[
"StatusCode"] = 3;
456 result->status_ = dqm_core::Result::Yellow;
457 if(publishDetail & 0x20) {
458 result->tags_[
"StatusCode"] = 2;
460 }
else if(
result->status_==dqm_core::Result::Undefined && greenThresholds.find(k)!=greenThresholds.end()) {
461 result->status_ = dqm_core::Result::Green;
462 if(publishDetail & 0x20) {
463 result->tags_[
"StatusCode"] = 1;