DDTOnMonPlotMaker.C
Go to the documentation of this file.
1 /* DDT Plot Maker for Nearline
2  Last Edited: Kyle Thomsen
3 
4 
5  */
6 #include <fstream>
7 #include <TH1F.h>
8 #include <TH2F.h>
9 #include <TGraph.h>
10 #include <TTree.h>
11 #include <TCanvas.h>
12 #include <TFile.h>
13 #include <TPaveText.h>
14 #include <TStyle.h>
15 #include <TSystem.h>
16 #include <TDatime.h>
17 #include <TMultiGraph.h>
18 #include <TGaxis.h>
19 #include <TMath.h>
20 // #include "DAQDataFormats/cxx/include/TriggerDefines.h"
21 
22 #include <iostream>
23 #include <iomanip>
24 #include <sstream>
25 #include <string>
26 #include <cstring>
27 #include <limits>
28 #include <map>
29 #include <vector>
30 
31 // The header file that's paired with this plot maker
32 // defines a few useful math functions. Otherwise,
33 // these expressions are bulky and only serve to
34 // obfuscate what's really being done.
36 
37 // This file defines structures for the good values
38 // associated with each metric and assigns their
39 // default values.
41 
42 // The config file included below sets the appropriate
43 // good values for each metric on a per-trigger basis.
44 // This file should be updated as trigger authors develop
45 // their triggers.
46 //
47 // It should then be committed so that an automatic update
48 // of this file on the farm where this plot maker runs can
49 // always work with the latest sets of good values.
50 #include "Commissioning/Nearline/DDTGoodValues.config"
51 
52 // This header file defines a lot of functions which perform
53 // common tasks when creating plots. This is especially useful
54 // when adding new metrics.
56 
57 //
58 // #include "Commissioning/Nearline/DDTMetric_TriggerRate.h"
59 
60 // Set the number of triggers here.
61 // One day, this will be read in from elsewhere. Today is not that day.
62 #define NTRIGS 30
63 
64 // This lets me draw the fancy OnMon-style plot labels.
65 // #include "OnlineMonitoring/viewer/HwDetLabel.cxx"
66 
67 void DDTOnMonPlotMaker(TString det_type, TString t_prd, TString mode) {
68 
69  std::cout << "\n\nMaking FD OnMon/Nearline Day plots...\n\n";
70 
71  // TODO:
72  // * make the histograms smart enough to get their binnings from the onmon-histos file
73  // (or make them smart enough to figure out how big they should be...???) In fact,
74  // make nothing hardcoded about the histos (get all info from onmon-histos.csv)
75  //
76  // * make hitmap style plot of DCM duty cycle (using the empty DCM histo)
77  //
78  // * fix this so that if one of the text files is empty, it doesn't crash
79  //
80  // * document the heck out of this code...
81  //
82  // * should I normalize the NFEBperSR histos so that each bin is the average of each subrun that contributed?
83  //
84  // * I think that I am doing the GMT to CST conversion correctly, but I also think that I'm doing it in a convoluted way. Maybe I should make this better...
85  //
86  // * I don't think that I need to count all of the things for the TGraphs every time. Maybe I only need to count them during the month loop and then
87  // just zoom each plot appropriately?
88  //
89  // * normalize Nhits per spill plot to be percentage???
90  //
91  // * figure out a better way to do the arrays (other than to have fixed sizes...)
92  //
93  // * make the rasta plot have 1 hour bins (since subruns are now ~20 minutes)???
94  //
95  // * keep track of last run/subrun (for the text boxes) by partition
96 
97 // This variable allows you to set the output location of all the plots produced.
98  TString OUTPUT_LOCATION;
99  if (mode == "test") {
100  OUTPUT_LOCATION = "/afs/fnal.gov/files/home/room3/kthomsen/plots/OnMonPlots/"; } // for local testing
101  else if (mode == "normal") {
102  OUTPUT_LOCATION = "/bluearc/nusoft/app/web/htdoc/nova/datacheck/nearline/plots/"; } // for running as part of a job
103 
104 // Define the maximum number of points to go into a TGraph (assuming a max
105 // of one subrun every minute.)
106  int t_n = 1;
107  if(t_prd == "Day") t_n = 1;
108  if(t_prd == "Week") t_n = 7;
109  if(t_prd == "Month") t_n = 30;
110  const unsigned int Npoint = 1440 * t_n;
111 
112  TDatime *TNowGMT = new TDatime; // current GMT time
113  TDatime *TNow = new TDatime; // current local time
114  TDatime *SRtime = new TDatime;
115  int XNowGMT = TNowGMT->Convert(kTRUE);
116  int XNow = TNow ->Convert(kFALSE);
117 
118  int GMToffset = XNowGMT - XNow;
119 
120  XNow = XNow - GMToffset;
121 
122  int XDayAgo = XNow - 60*60*24;
123  int XWeekAgo = XNow - 60*60*24*7;
124  int XMonthAgo = XNow - 60*60*24*30;
125 
126 ////////////////////////////////////////////////
127 // unsigned int NTRIGS = 30; // hardcoded until we can figure out how best to include contents of TriggerDefines.h
128  double Trig[NTRIGS][Npoint];
129  for (unsigned int trigger_bit = 0; trigger_bit < NTRIGS; trigger_bit++)
130  for (unsigned int i = 0; i < Npoint; i++)
131  Trig[trigger_bit][i] = 0.0;
132 ////////////////////////////////////////////////
133 
134 
135  int time_ago = 0;
138 
139  if(det_type == "FarDet"){
140  det = "FarDet";
141  if(t_prd == "Day"){
142  period = "Day";
143  time_ago = XDayAgo;
144  }
145  else if(t_prd == "Week"){
146  period = "Week";
147  time_ago = XWeekAgo;
148  }
149  else if(t_prd == "Month"){
150  period = "Month";
151  time_ago = XMonthAgo;
152  }
153  }
154  if(det_type == "NDOS"){
155  det = "NDOS";
156  if(t_prd == "Day"){
157  period = "Day";
158  time_ago = XDayAgo;
159  }
160  else if(t_prd == "Week"){
161  period = "Week";
162  time_ago = XWeekAgo;
163  }
164  else if(t_prd == "Month"){
165  period = "Month";
166  time_ago = XMonthAgo;
167  }
168  }
169  if(det_type == "NearDet"){
170  det = "NearDet";
171  if(t_prd == "Day"){
172  period = "Day";
173  time_ago = XDayAgo;
174  }
175  else if(t_prd == "Week"){
176  period = "Week";
177  time_ago = XWeekAgo;
178  }
179  else if(t_prd == "Month"){
180  period = "Month";
181  time_ago = XMonthAgo;
182  }
183  }
184 
185 
186 
187  unsigned int year = 0;
188  unsigned short int month = 0;
189  unsigned short int day = 0;
190  double Hour = 0.0;
191  double Min = 0.0;
192  int hour = 0;
193  int min = 0;
194  int sec = 0;
195 
196  unsigned int run = 0;
197  unsigned int subrun = 0;
198  UInt_t par = 0;
199 
200  unsigned int LastRun = 0;
201  unsigned int LastSR = 0;
202 
203  unsigned int yearEnd = 0;
204  unsigned short int monthEnd = 0;
205  unsigned short int dayEnd = 0;
206  double HourEnd = 0.0;
207  unsigned int SubrunsProcessed = 0; // the total number of subruns this script has currently processed
208 
209 
210 
211  // Root is stupid and you have to make it think that it is in a different time zone so that it will draw any
212  // plots with time on the X-axis correctly.
213  gSystem->Setenv("TZ","UTC");
214  gStyle->SetTimeOffset(0);
215 
216  // Make conditional standard time axis labels depending on period (Day, Week, Month)
217  std::string taxis_labels;
218  if(period == "Day"){
219  taxis_labels = "%H:%M";
220  }
221  else{
222  taxis_labels = "%m/%d";
223  }
224 
225 
226 
227 
228 // Read in lists of files.
229 // inFile contains a list of DDT OnMon files.
230 // inFile_SRLength contains a list of normal nearline files, to be used for obtaining SR lengths.
231 
232  std::ifstream inFile;
233  std::ifstream inFile_SRLength;
234  if(det_type == "FarDet"){
235  if(t_prd == "Day"){
236  inFile.open("FDDDTOnMonDayFileList.txt");
237  inFile_SRLength.open("FDSRLengthDayFileList.txt");
238  }
239  else if(t_prd == "Week"){
240  inFile.open("FDDDTOnMonWeekFileList.txt");
241  inFile_SRLength.open("FDSRLengthWeekFileList.txt");
242  }
243  else if(t_prd == "Month"){
244  inFile.open("FDDDTOnMonMonthFileList.txt");
245  inFile_SRLength.open("FDSRLengthMonthFileList.txt");
246  }
247  }
248  if(det_type == "NDOS"){
249  if(t_prd == "Day"){
250  inFile.open("NDOSDDTOnMonDayFileList.txt");
251  }
252  else if(t_prd == "Week"){
253  inFile.open("NDOSDDTOnMonWeekFileList.txt");
254  }
255  else if(t_prd == "Month"){
256  inFile.open("NDOSDDTOnMonMonthFileList.txt");
257  }
258  }
259  if(det_type == "NearDet"){
260  if(t_prd == "Day"){
261  inFile.open("NDDDTOnMonDayFileList.txt");
262  inFile_SRLength.open("NDSRLengthDayFileList.txt");
263  }
264  else if(t_prd == "Week"){
265  inFile.open("NDDDTOnMonWeekFileList.txt");
266  inFile_SRLength.open("NDSRLengthWeekFileList.txt");
267  }
268  else if(t_prd == "Month"){
269  inFile.open("NDDDTOnMonMonthFileList.txt");
270  inFile_SRLength.open("NDSRLengthMonthFileList.txt");
271  }
272  }
273 
274 
275 
276 
277  // book histos, arrays for TGraphs, etc.
278 
279  double *TriggerTime[NTRIGS];
280  double *TriggerRate[NTRIGS];
281  unsigned int TriggerTotal[NTRIGS];
282 // double SRdur;
283  int Xsrtime = 0;
284 
285  // initalize arrays
286  for(unsigned int trigger_bit = 0; trigger_bit < NTRIGS; ++trigger_bit) {
287  TriggerTotal[trigger_bit] = 0;
288  TriggerTime[trigger_bit] = new double[Npoint];
289  TriggerRate[trigger_bit] = new double[Npoint];
290  for (unsigned int i = 0; i < Npoint; i++) {
291  TriggerTime[trigger_bit][i] = 0.0;
292  TriggerRate[trigger_bit][i] = 0.0;
293  }
294  }
295 
297  if(period == "Day") time = "past 24 hrs.";
298  if(period == "Week") time = "past 7 days";
299  if(period == "Month") time = "past 30 days";
300 
301 
302 // Map for linking run/subrun and subrun length.
303  std::map<std::string,double> SRLength;
304  std::map<std::string,int> SRTime;
305 
306 // Run the function which sets the good values for each
307 // combination of metric and trigger. This function is
308 // defined in DDTGoodValues.config and uses structs
309 // which are defined in DDTGoodValues.h.
310  extern struct DDTGoodValues GoodValues_Trigger[NTRIGS];
311  SetGoodValues();
312 
313 //----------------------------------------------------------------------------------------------//
314 // Initializations above here; functions below. //
315 //----------------------------------------------------------------------------------------------//
316 
317 // Get SR lengths from normal nearline files.
318  while(inFile_SRLength.good()) {
319 
320  // Check to make sure files aren't double-counted.
321  char filenameDprevious[256];
322  char filenameD[256];
323  strcpy(filenameDprevious,filenameD);
324  inFile_SRLength >> filenameD;
325 // std::cout << "reading in " << filenameD << std::endl;
326  TFile *fileD = new TFile(filenameD,"READ");
327 // if(!fileD->IsOpen()) std::cout << "unable to open " << filenameD << std::endl;
328  // If any file is read twice, break the loop.
329  if (strcmp(filenameD, filenameDprevious) == 0) {/*std::cout << "DUPLICATE FILE DETECTED\n";*/ continue;}
330 
331 // // Get subrun info out of the header.
332  TTree *header = dynamic_cast<TTree*>(fileD->Get("Header"));
333  if(header != 0) {
334  header->SetBranchAddress("StartYear", &year);
335  header->SetBranchAddress("StartMonth", &month);
336  header->SetBranchAddress("StartDay", &day);
337  header->SetBranchAddress("StartHour", &Hour);
338  header->SetBranchAddress("EndYear", &yearEnd);
339  header->SetBranchAddress("EndMonth", &monthEnd);
340  header->SetBranchAddress("EndDay", &dayEnd);
341  header->SetBranchAddress("EndHour", &HourEnd);
342  header->SetBranchAddress("Run", &run);
343  header->SetBranchAddress("Subrun", &subrun);
344  header->SetBranchAddress("Partition", &par);
345  header->GetEntry(0);
346 
347  std::string runID = std::to_string(run) + "_" + std::to_string(subrun);
348 
349  hour = Hour;
350  Min = (Hour-hour)*60.0;
351  min = (Hour-hour)*60.0;
352  sec = (Min-min)*60.0;
353 
354  // OnMon/DAQ keeps track of GMT time, so convert to local time
355  SRtime->Set(year,month,day,hour,min,sec);
356  SRTime[runID] = SRtime->Convert() - GMToffset;
357 
358  hour = HourEnd;
359  Min = (HourEnd-hour)*60.0;
360  min = (HourEnd-hour)*60.0;
361  sec = (Min-min)*60.0;
362 
363  // Get the end time and compute subrun duration.
364  SRtime->Set(yearEnd,monthEnd,dayEnd,hour,min,sec);
365  if(dayEnd == day)
366  SRLength[runID] = 3600.0*(HourEnd-Hour);
367  else
368  SRLength[runID] = 3600.0*(HourEnd+24.0-Hour);
369 
370 
371 // std::cout << "Now adding " << runID << " with length " << SRLength[runID] << std::endl;
372  }
373  fileD->Close();
374  delete fileD;
375 }
376 
377  while(inFile.good()) {
378 
379  // Check to make sure files aren't double-counted.
380  char filenameDprevious[256];
381  char filenameD[256];
382  strcpy(filenameDprevious,filenameD);
383  inFile >> filenameD;
384 // std::cout << "reading in " << filenameD << std::endl;
385  TFile *fileD = new TFile(filenameD,"READ");
386 // if(!fileD->IsOpen()) std::cout << "unable to open " << filenameD << std::endl;
387  // If any file is read twice, break the loop.
388  if (strcmp(filenameD, filenameDprevious) == 0) {/*std::cout << "DUPLICATE FILE DETECTED\n";*/ break;}
389 
390 // // Get subrun info out of the header.
391  TTree *header = dynamic_cast<TTree*>(fileD->Get("Header"));
392  if(header != 0) {
393  header->SetBranchAddress("StartYear", &year);
394  header->SetBranchAddress("StartMonth", &month);
395  header->SetBranchAddress("StartDay", &day);
396  header->SetBranchAddress("StartHour", &Hour);
397  header->SetBranchAddress("EndYear", &yearEnd);
398  header->SetBranchAddress("EndMonth", &monthEnd);
399  header->SetBranchAddress("EndDay", &dayEnd);
400  header->SetBranchAddress("EndHour", &HourEnd);
401  header->SetBranchAddress("Run", &run);
402  header->SetBranchAddress("Subrun", &subrun);
403  header->SetBranchAddress("Partition", &par);
404  header->GetEntry(0);
405 
406  std::cout << "LOOP: adding run " << run << ", subrun " << subrun << /*", SubrunsProcessed: " << SubrunsProcessed <<*/ std::endl;
407  if (run != LastRun) {LastRun = run;}
408  if (subrun != LastSR) {LastSR = subrun;}
409 
410 // hour = Hour; // set integral hour
411 // // std::cout << "hour = " << hour << std::endl;
412 // // std::cout << "Hour = " << Hour << std::endl;
413 // // std::cout << "Hour%HourEnd = " << fmod(Hour,HourEnd) << std::endl;
414 // // std::cout << "HourEnd = " << HourEnd << std::endl;
415 // // std::cout << "HourEnd%Hour = " << fmod(HourEnd,Hour) << std::endl;
416 // // std::cout << "SRdur = " << fmod(HourEnd,Hour)*3600 << std::endl;
417 // Min = (HourEnd-hour)*60.0; // calculate decimal minute
418 // // std::cout << "Min = " << Min << std::endl;
419 // min = (Hour-hour)*60.0; // calculate integral minute
420 // // std::cout << "min = " << min << std::endl;
421 // // Sec = (Min-min)*60.0; // calculate decimal second
422 // // std::cout << "Sec = " << sec << std::endl;
423 // sec = (Min-min)*60.0; // calculate decimal second
424 // // std::cout << "sec = " << sec << std::endl;
425 //
426 // hour = HourEnd; // set integer hour
427 // min = fmod(HourEnd,1.0) * 60.0; // set integer minute
428 // sec = fmod(fmod(HourEnd,1.0),.01) * 60.0; // set integer second
429  /*
430  hour = HourEnd;
431  Min = (HourEnd-hour)*60.0;
432  min = (HourEnd-hour)*60.0;
433  sec = (Min-min)*60.0;
434  // OnMon/DAQ keeps track of GMT time, so convert to local time
435  SRtime->Set(year,month,day,hour,min,sec);
436  Xsrtime[SubrunsProcessed] = SRtime->Convert() - GMToffset;
437 
438 // hour = HourEnd;
439 // Min = (HourEnd-hour)*60.0;
440 // min = (HourEnd-hour)*60.0;
441 // sec = (Min-min)*60.0;
442 
443  // Get the end time and compute subrun duration.
444  SRtime->Set(yearEnd,monthEnd,dayEnd,hour,min,sec);*/
445 
446  hour = Hour;
447  Min = (Hour-hour)*60.0;
448  min = (Hour-hour)*60.0;
449  sec = (Min-min)*60.0;
450 
451  // OnMon/DAQ keeps track of GMT time, so convert to local time
452  SRtime->Set(year,month,day,hour,min,sec);
453  Xsrtime = SRtime->Convert() - GMToffset;
454 
455  hour = HourEnd;
456  Min = (HourEnd-hour)*60.0;
457  min = (HourEnd-hour)*60.0;
458  sec = (Min-min)*60.0;
459 
460  // Get the end time and compute subrun duration.
461  SRtime->Set(yearEnd,monthEnd,dayEnd,hour,min,sec);
462 
463 // if(dayEnd == day)
464 // SRdur[SubrunsProcessed] = 3600.0*(HourEnd-Hour);
465 // else
466 // SRdur[SubrunsProcessed] = 3600.0*(HourEnd+24.0-Hour);
467 
468 // SRdur[SubrunsProcessed] = fmod(HourEnd,Hour)*3600; // get modulus of the end decimal hour w.r.t. start decimal hour, then convert to seconds
469 
470 
471 // if(Xsrtime < time_ago) continue;
472 
473 // if(run >= LastRun) {
474 // if(run < LastRun) {
475 // LastRun = run;
476 // LastSR = subrun;
477 // }
478 // else if(subrun < LastSR) {
479 // LastRun = run;
480 // LastSR = subrun;
481 // }
482 // }
483 // if (run != LastRun) {std::cout << "new run" << std::endl;}
484 // if (subrun != LastSR) {std::cout << "new subrun" << std::endl;}
485 
486 
487 
488 
489  }
490 
491 // String for use as key for obtaining SR length.
492  std::string runID = std::to_string(run) + "_" + std::to_string(subrun);
493 
494  // Protection against subruns with only one event in them (yes, this did happen once...)
495 // if(SRdur[SubrunsProcessed] == 0.0) {std::cout << "SRdur = 0 in " << run <<", " << subrun << "\t" << Hour << "\t" << HourEnd << "\t" << 3600.0*(HourEnd - Hour) << "\t" << SRdur[SubrunsProcessed] << "\t" << SRdur[SubrunsProcessed] - 3600.0*(HourEnd - Hour)<< "\t" << (SRdur[SubrunsProcessed] < std::numeric_limits<double>::epsilon()) <<std::endl; continue;}
496 // if (subrun > LastSR) {SubrunsProcessed++; std::cout<<"subrun incremented"<<std::endl;} // increment the subrun count when we either
497  // get to a new run or get to a new subrun
498 
499  // integrating the trigger rates for each file
500 
501 // compute_trigger_rates(fileD, runID, SubrunsProcessed);
502 
503  // opening the general trigger vs time histogram from the current file
504  TH2F *hTrig = dynamic_cast<TH2F*>(fileD->FindObjectAny("TriggerVsHourGeneral"));
505 
506  // FOR FUTURE IMPLEMENTATION - AWAITING TRIGGERDEFINES.H INCLUSION
507  // getting the number of vertical bins in this histogram, which corresponds to the maximum
508  // number of triggers - it'll be the upper limit of the loop
509 
510  // loop over all possible triggers
511  for (unsigned int trigger_bit = 0; trigger_bit < NTRIGS; trigger_bit++) {
512  // do this only if there actually is a trigger vs time histogram in this file
513  if(hTrig != 0 && header != 0) {
514  Trig[trigger_bit][SubrunsProcessed] += hTrig->Integral(61,1500,trigger_bit+1,trigger_bit+1); // integrate the trigger count for this subrun
515 // if(Trig[trigger_bit][SubrunsProcessed] < std::numeric_limits<double>::epsilon()) continue; // ignore zeroes in this subrun, if they exist
516 // std::cout << run << "\t" << subrun << "\t" << trigger_bit << "\t" << SRdur[SubrunsProcessed] << std::endl;
517  TriggerTime[trigger_bit][SubrunsProcessed] = Xsrtime; // the time for this trigger for this subrun
518  if (SRLength[runID] > std::numeric_limits<double>::epsilon())
519  TriggerRate[trigger_bit][SubrunsProcessed] = Trig[trigger_bit][SubrunsProcessed]/SRLength[runID];
520 // else
521 // std::cout << "UNABLE TO DIVIDE BY ZERO\n"; // the rate for this trigger for this subrun
522 // if (SRdur[SubrunsProcessed] == 0.0) std::cout << "trigger " << trigger_bit << " with " << Trig[trigger_bit][SubrunsProcessed] << "counts\n";
523  TriggerTotal[trigger_bit] += Trig[trigger_bit][SubrunsProcessed]; // the cumulative count for this trigger
524  }
525  }
526  fileD->Close();
527  delete fileD;
528  ++SubrunsProcessed;
529 }
530 
531 
532  // make the OnMon hardware label drawer
533 // om::HwDetLabel *hwdetlbl = new om::HwDetLabel();
534 
535 //=========================================================================================//
536 // GENERAL TRIGGER RATE PLOT
537 //=========================================================================================//
538 
539 // Loop over the maximum number of triggers.
540  for (unsigned int trigger_bit = 0; trigger_bit < NTRIGS; trigger_bit++){
541  if(TriggerTotal[trigger_bit] > std::numeric_limits<double>::epsilon()) { // only do anything if this trigger has some counts
542 
543  char filename[128];
544  char title[128];
545 
546 // Initialize the canvas used in making these plots.
547  TCanvas *cTriggerRate = new TCanvas("cTriggerRate","DDT Trigger Rate vs Time",1200,800);
548  cTriggerRate->cd();
549 
550 // Set up two pads to be used in this plot.
551 //
552 // The reason two pads are needed here is because I need to
553 // be able to overlay two plots with different axes within
554 // the same canvas. I haven't found an easier way to do this,
555 // so I stuck with this method.
556  TPad *pad1 = new TPad("pad1","",0,0,1,1); // the pad for low fractions - those with an average < .50
557  TPad *pad2 = new TPad("pad2","",0,0,1,1); // the pad for fractions between .50 and 1.0
558  transparent_pad(pad2);
559  pad1->Draw();
560  pad2->Draw();
561 
562 // Initialize the graphs being used in the trigger rate plots.
563 
564 // This graph will include the rates which are in the expected range of rates. Its
565 // points are blue, as they've always been.
566  sprintf(title,"Average Trigger %.2u Rate (Hz) per Subrun",trigger_bit);
567  TGraph *gTriggerRates = new TGraph();
568  configure_tgraph(gTriggerRates, kBlue, kStar, title);
569 
570 // Any rates that fall outside the expected range will be funneled
571 // into the outliers plot. These points are red for quick identification.
572  TGraph *gTriggerRatesOutliers = new TGraph();
573  configure_tgraph(gTriggerRatesOutliers, kRed, kFullTriangleDown, title);
574 
575 // Loop over all the rates to identify and sort outliers
576 //
577 // There might be more added here when the list of problem
578 // subruns is implemented, but for now, this simple logic
579 // is all that's necessary.
580  int RateCount = 0, OutlierCount = 0;
581  for (unsigned int counter = 0; counter < SubrunsProcessed; ++counter) {
582  // Check for rates outside acceptable range.
583  if (( (TriggerRate[trigger_bit][counter] < GoodValues_Trigger[trigger_bit].TriggerRate.MinRate) ||
584  (TriggerRate[trigger_bit][counter] > GoodValues_Trigger[trigger_bit].TriggerRate.MaxRate) ) ) {
585  gTriggerRatesOutliers->SetPoint(OutlierCount, TriggerTime[trigger_bit][counter], TriggerRate[trigger_bit][counter]);
586  ++OutlierCount;}
587  else {
588  gTriggerRates->SetPoint(RateCount, TriggerTime[trigger_bit][counter], TriggerRate[trigger_bit][counter]);
589  ++RateCount;}
590  }
591 
592 
593 // Check whether or not there are actually any entries in the graphs.
594 // If there aren't any, the entire script will segfault when trying to
595 // create a graph with no points.
596  bool noRates = true;
597  if (gTriggerRates->GetN() > 0) { noRates = false; }
598  bool noOutliers = true;
599  if (gTriggerRatesOutliers->GetN() > 0) { noOutliers = false; }
600 
601 // Get the max/min of both plots for nice graphing.
602 // The default axis scaling on the outliers plot is
603 // pretty horrible, so this gets around that.
604 //
605 // Beyond that, this also allows us to automatically
606 // determine whether or not a logarithmic outlier axis
607 // is appropriate.
608  Double_t RateMaximum = 0, RateMinimum = 0, OutlierMaximum = 0, OutlierMinimum = 0;
609  if (! noRates) {
610  RateMaximum = TMath::MaxElement(gTriggerRates->GetN(), gTriggerRates->GetY());
611  RateMinimum = TMath::MinElement(gTriggerRates->GetN(), gTriggerRates->GetY()); }
612  if (! noOutliers) {
613  OutlierMaximum = TMath::MaxElement(gTriggerRatesOutliers->GetN(), gTriggerRatesOutliers->GetY());
614  OutlierMinimum = TMath::MinElement(gTriggerRatesOutliers->GetN(), gTriggerRatesOutliers->GetY()); }
615 
616 
617 
618 // Compute the ratio of maximum to minimum for both plots.
619 // This determines whether each plot will use
620 // a logarithmic or a linear vertical axis.
621 //
622 // This ratio defaults to 1 if the minimum is zero.
623  Double_t RateRatio = 1;
624  if (! noRates) {
625  if ( RateMaximum != 0 && lowest_nonzero_Y(gTriggerRates) != 0 ) { RateRatio = RateMaximum / lowest_nonzero_Y(gTriggerRates); } }
626  Double_t OutlierRatio = 1;
627  if (! noOutliers) {
628  if ( OutlierMaximum != 0 && lowest_nonzero_Y(gTriggerRatesOutliers) != 0 ) { OutlierRatio = OutlierMaximum / lowest_nonzero_Y(gTriggerRatesOutliers); } }
629 
630 
631 
632 // Set up the two plots in their respective pads and draw them.
633 // It's important to note that the outliers plot puts its y-axis
634 // on the right-hand side of the plot.
635 
636  if (! noRates) {
637  pad1->cd();
638  pad1->SetGridx();
639  // Use a logarithmic axis if there's more
640  // than 1.5 orders of magnitude between
641  // the highest and lowest acceptable rates.
642  //
643  // If there's a zero in there, it needs to
644  // be shown. It can't be shown with a logarithmic
645  // vertical axis, so disallow logarithmic
646  // axes if the minimum is zero. Note, however,
647  // that RateRatio is calculated using the smallest
648  // nonzero value to keep things from breaking.
649  if ( RateRatio > std::pow(10,1.5) && RateMinimum != 0 ) { pad1->SetLogy();}
650  gTriggerRates->Draw("AP");
651  pad1->Modified();
652  pad1->Update(); }
653 
654 // Only draw the outliers graph if there are any outliers.
655  if (! noOutliers) {
656  pad2->cd();
657  pad2->SetGridx();
658  // Use a logarithmic axis if there's more
659  // than 1.5 orders of magnitude between
660  // the highest and lowest outliers.
661  //
662  // If there's a zero in there, it needs to
663  // be shown. It can't be shown with a logarithmic
664  // vertical axis, so disallow logarithmic
665  // axes if the minimum is zero. Note, however,
666  // that OutlierRatio is calculated using the smallest
667  // nonzero value to keep things from breaking.
668  if ( OutlierRatio > std::pow(10,1.5) && OutlierMinimum != 0 ) { pad2->SetLogy();}
669  gTriggerRatesOutliers->Draw("APY+");
670  pad2->Modified();
671  pad2->Update();
672  } // end check for outliers
673 
674 // Format the axes nicely.
675 //
676 // In particular, use time formatting for the x-axis. The
677 // y-axis of the first plot will be on the left-hand side,
678 // while the y-axis of the outliers plot will be on the
679 // right-hand side and will be red.
680 
681  configure_time_axis(gTriggerRates->GetXaxis(), time_ago, XNow, taxis_labels.c_str());
682 
683  configure_time_axis(gTriggerRatesOutliers->GetXaxis(), time_ago, XNow, taxis_labels.c_str());
684  gTriggerRatesOutliers->GetYaxis()->SetAxisColor(kRed);
685  gTriggerRatesOutliers->GetYaxis()->SetLabelColor(kRed);
686 
687 // Draw the update information, last point information, and good values information
688  UpdatedText(GMToffset, LastRun, LastSR)->Draw();
689  LastPointText(gTriggerRates, gTriggerRatesOutliers)->Draw();
690  GoodValuesText(GoodValues_Trigger[trigger_bit].TriggerRate.MinRate,
691  GoodValues_Trigger[trigger_bit].TriggerRate.MaxRate)->Draw();
692 
693 // Print the entire canvas to a png.
694  sprintf(filename,OUTPUT_LOCATION+"%s-t%.2u-P1TrigRate%s.png",det.c_str(),trigger_bit,period.c_str());
695  print_plot(cTriggerRate, filename);
696  }
697  } // end check for nonzero trigger count
698  } // end loop over all triggers
699 //=========================================================================================//
700 
701 
702 // End making plots.
Double_t lowest_nonzero_Y(const TGraph *graphY)
TPaveText * GoodValuesText(const double gv_low, const double gv_high)
UInt_t LastSR
Definition: AnaPlotMaker.h:50
TPaveText * UpdatedText(const int GMToffset, const unsigned int LastRun, const unsigned int LastSR)
void configure_time_axis(TAxis *a, const int time_earlier, const int time_later, const char *time_format)
TDatime * TNow
Definition: AnaPlotMaker.h:41
TrigRateGV TriggerRate
Definition: DDTGoodValues.h:43
constexpr T pow(T x)
Definition: pow.h:75
Int_t par
Definition: SimpleIterate.C:24
string filename
Definition: shutoffs.py:106
#define NTRIGS
TDatime * SRtime
Definition: AnaPlotMaker.h:42
::xsd::cxx::tree::time< char, simple_type > time
Definition: Database.h:194
ifstream inFile
Definition: AnaPlotMaker.h:34
void DDTOnMonPlotMaker(TString det_type, TString t_prd, TString mode)
void print_plot(TCanvas *c, const char *filename)
UInt_t LastRun
Definition: AnaPlotMaker.h:49
Double_t MaxRate
Definition: DDTGoodValues.h:33
TPaveText * LastPointText(const TGraph *g1, const TGraph *g2)
Definition: run.py:1
void transparent_pad(TPad *p)
TDatime * TNowGMT
Definition: AnaPlotMaker.h:40
OStream cout
Definition: OStream.cxx:6
det_type
Definition: Constants.h:501
static float min(const float a, const float b, const float c)
Definition: absgeo.cxx:45
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
Int_t GMToffset
Definition: AnaPlotMaker.h:43
double epsilon
TPad * pad2
Definition: analysis.C:13
std::string to_string(ModuleType mt)
Definition: ModuleType.h:32
void configure_tgraph(TGraph *g, const Color_t color, const Style_t style, const char *title)
TPad * pad1
Definition: analysis.C:13
static constexpr Double_t year
Definition: Munits.h:185