11 #include <dqm_core/AlgorithmConfig.h>
14 #include <dqm_core/AlgorithmManager.h>
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" );
72 bool reverseConvention = TString(
histogram->GetYaxis()->GetTitle()).EndsWith(
"+y");
74 std::map<std::string,std::set<std::pair<int,int>>> knownBins;
76 auto knownBinParser = [&](
const std::string& cutName) {
86 while(
i != std::string::npos) {
87 size_t j =
known.find(
";");
88 knownBins[cutName].insert({TString(
known.substr(0,
i)).Atoi(),TString(
known.substr(
i+1,j-
i-1)).Atoi()});
94 std::vector<std::pair<double,std::string>> orderedCuts;
95 double mostNegativeCut = 0;
96 for(
auto& [
k,
v] :
config.getParameters()) {
98 if(!
kk.EndsWith(
"Cut"))
continue;
100 orderedCuts.push_back({
v,
kk.Data()});
101 mostNegativeCut =
std::min(mostNegativeCut,
v);
102 knownBinParser(
kk.Data());
104 knownBinParser(
"Dead");
107 std::sort(orderedCuts.begin(),orderedCuts.end(),[](
const auto& v1,
const auto&
v2) { return std::abs(v1.first) > std::abs(v2.first); });
109 if (
histogram->GetEntries() < minstat ) {
111 result->status_ = dqm_core::Result::Yellow;
119 std::map<int,dqm_core::Result*> resultsByTimeBin;
120 std::map<std::string,int> counts;
123 for(
int t=(nBinsZ>0 ?
range[0] : -1) ;
t <= (nBinsZ>0 ?
range[1] : -1);
t++) {
133 std::set<int> filledRows;
136 std::vector<double> stripsMedian;
137 std::vector<double> stripsAvg;
138 std::vector<double> stripsVariance;
139 std::vector<size_t> stripsN;
140 std::vector<double> stripsProb;
143 std::vector<double> onestrip;
144 double stripSum=0, stripSum2=0;
145 for (
int j =
ymin; j <=
ymax; ++j ) {
147 if (binvalue < ignoreBelow)
continue;
148 if(binvalue>0) filledRows.insert(j);
149 onestrip.push_back(binvalue);
150 stripSum += binvalue;
151 stripSum2 += binvalue*binvalue;
153 stripsAvg.push_back(stripSum/onestrip.size());
158 std::sort(onestrip.begin(),onestrip.end());
160 stripsMedian.push_back( onestrip.at(onestrip.size()/2) );
162 stripsVariance.push_back(
std::pow((onestrip.at(onestrip.size()*0.84) - onestrip.at(onestrip.size()*0.16))/2.,2) );
163 stripsN.push_back(onestrip.size());
165 if(stripsVariance.back() > 0) {
166 std::vector<double> stripRef;
167 for (
size_t i = 0;
i < onestrip.size();
i++) {
172 nextVal = (stripsVariance.back()>=100) ?
r.Gaus(stripsAvg.back(), std::sqrt(stripsVariance.back())) :
r.Poisson(stripsAvg.back());
173 }
while(nextVal<ignoreBelow);
174 stripRef.push_back(nextVal);
176 std::sort(stripRef.begin(),stripRef.end());
177 stripsProb.push_back( TMath::KolmogorovTest(onestrip.size(),&onestrip[0],stripRef.size(),&stripRef[0],
"") );
179 stripsProb.push_back(1);
182 if(nBinsZ>=0 && filledRows.empty()) {
187 std::map<std::pair<int,int>,
bin>
bins;
189 double strip_median = stripsMedian[
k -
xmin];
190 double strip_variance = stripsVariance[
k -
xmin];
193 if (binvalue < ignoreBelow)
continue;
194 double residual = (strip_variance) ? ((binvalue - strip_median) / std::sqrt(strip_variance)) : 0;
201 bool testDeadStrips = (filledRows.size() == size_t(
ymax-
ymin+1));
206 counts[
"NDeadStrip"]= (testDeadStrips) ? 0 : -1;
208 counts[
"NWrongKnown"]=0;
209 counts[
"NConsecUnlikelyStrip"]=0;
210 for(
auto& [
cut,
k] : orderedCuts) {
215 int nUnlikelyStrips = 0;
216 for(
size_t i = 0;
i<stripsVariance.size();
i++) {
217 if (testDeadStrips && stripsVariance.at(
i) == 0 && stripsAvg.at(
i) == 0) {
219 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)) {
221 counts[
"NDeadStrip"]++;
225 if (stripsProb.at(
i) < probThreshold) {
228 if(nUnlikelyStrips > counts[
"NConsecUnlikelyStrip"]) counts[
"NConsecUnlikelyStrip"] = nUnlikelyStrips;
232 if(publishDetail & 0
x1) {
235 if(publishDetail & 0
x2) {
238 if(publishDetail & 0x4) {
241 if(publishDetail & 0x8) {
243 result->tags_[
TString::Format(
"_Noise%02ld",
i+1).Data()] = sqrt(std::abs(stripsVariance.at(
i) - stripsMedian.at(
i)));
257 if( (publishDetail & 0x10) &&
bin.
m_value==0) {
262 for(
auto& [
cut,
k] : orderedCuts) {
275 if(
bin.
m_value>0 && knownBins[
"Dead"].find({bin.m_ix,bin.m_iy})!=knownBins[
"Dead"].end()) {
276 counts[
"NWrongKnown"]++;
279 }
else if(classCut != 0) {
281 for(
auto& [
cut,
k] : orderedCuts) {
283 if(
cut*classCut < 0) {
284 counts[
"NWrongKnown"]++;
294 lastFilledResult =
result;
301 counts[
"NDeadStrip"]= 0;
303 counts[
"NWrongKnown"]=0;
304 counts[
"NConsecUnlikelyStrip"]=0;
305 for(
auto& [
cut,
k] : orderedCuts) {
311 std::map<std::string,int> anomalies;
313 if(resultsByTimeBin.find(
t)==resultsByTimeBin.end()) {
315 for(
auto& [
k,
v] : anomalies) {
317 int lbStart =
histogram->GetXaxis()->GetBinLowEdge(
t-
v);
318 int lbEnd =
histogram->GetXaxis()->GetBinLowEdge(
t);
321 result->tags_[
k] = lastResult->tags_[
k];
327 if(
k.find(
"_DeadStrip")==0) {
328 counts[
"NDeadStrip"]++;
329 }
else if(
k.find(
"_Dead")==0) {
331 }
else if(
k.find(
"_UnlikelyStrip")==0) {
333 }
else if(
k.find(
"_Un")==0) {
334 counts[
"NWrongKnown"]++;
336 for(
auto& [
cut,k2] : orderedCuts) {
337 if(
k.find(
"_" + k2)==0) {
346 auto thisResult = resultsByTimeBin[
t];
347 if(liveMode && thisResult==lastFilledResult) {
354 for(
auto& [
k,
v] : thisResult->tags_) {
356 if(
k.find(
"_DeadStrip")==0) {
358 }
else if(
k.find(
"_Dead")==0) {
360 }
else if(
k.find(
"_UnlikelyStrip")==0) {
362 }
else if(
k.find(
"_Un")==0) {
365 for(
auto& [
cut,k2] : orderedCuts) {
366 if(
k.find(
"_" + k2)==0) {
375 for(
auto& [
k,
v] : anomalies) {
376 if(thisResult->tags_.find(
k) != thisResult->tags_.end())
continue;
378 int lbStart =
histogram->GetXaxis()->GetBinLowEdge(
t-
v);
379 int lbEnd =
histogram->GetXaxis()->GetBinLowEdge(
t);
387 if(
k.find(
"_DeadStrip")==0) {
388 counts[
"NDeadStrip"]++;
389 }
else if(
k.find(
"_Dead")==0) {
391 }
else if(
k.find(
"_UnlikelyStrip")==0) {
393 }
else if(
k.find(
"_Un")==0) {
394 counts[
"NWrongKnown"]++;
396 for(
auto& [
cut,k2] : orderedCuts) {
397 if(
k.find(
"_" + k2)==0) {
406 if(lastResult)
delete lastResult;
407 lastResult = thisResult;
410 if(lastResult)
delete lastResult;
415 result = resultsByTimeBin[-1];
422 const auto& redThresholds =
config.getRedThresholds();
423 const auto& greenThresholds =
config.getGreenThresholds();
425 if(publishDetail & 0x20) {
426 result->tags_[
"StatusCode"] = 0;
428 for(
auto& [
k,
v] : counts) {
429 if(nBinsZ>=0 &&
k==
"NConsecUnlikelyStrip")
continue;
433 if(publishDetail & 0x20) {
434 result->tags_[
"StatusCode"] = 3;
437 result->status_ = dqm_core::Result::Yellow;
438 if(publishDetail & 0x20) {
439 result->tags_[
"StatusCode"] = 2;
443 if(publishDetail & 0x20) {
444 result->tags_[
"StatusCode"] = 1;
458 out<<
"L1Calo_BinsDiffFromStripMedian: Calculates strip median and then find out bins which are aliens "<<std::endl;
459 out<<
"Specify cuts with parameters named <cutName>Cut will generate a result of form Nxxx" << std::endl;
460 out<<
"Specify known anomalies with Known<cutName> string argument - note any leading non-numeric char will be stripped" << std::endl;
461 out<<
"Special results are: NDead (number of 0 bins below most negative cut), NDeadStrip (strips that are all 0 .. will be -1 if not got an entry in every row of plot), NConsecUnlikelyStrip (most consecutive strips that are below ProbThreshold)" << std::endl;
462 out<<
"Thresholds can be set on any of the results\n"<<std::endl;
464 out<<
"Optional Parameter: MinStat: Minimum histogram statistics needed to perform Algorithm, also min entries for warm/hot spots (cuts > 0), and min entries in neighbour strip to declare a strip dead"<<std::endl;
465 out<<
"Optional Parameter: IgnoreBelow: values below which the bins wont be considered (default 0)"<<std::endl;
466 out<<
"Optional Parameter: ProbThreshold: cutoff for strip k-test probabilities for strip to be considered unlikely (default 0.05)"<<std::endl;
467 out<<
"Optional Parameter: PublishDetail: Bitmask of what extra info to publish about strips. Starting with MSB: AlgStatusCode,Zeros,Noise,Prob,StdDev,Median (default 000000)"<<std::endl;