Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-04-04 08:16:11

0001 #include "InttMonDraw.h"
0002 
0003 #include <TPolyLine.h>
0004 
0005 #include <limits>
0006 #include <map>
0007 
0008 namespace // anonymous
0009 {
0010   template <typename T>
0011   bool has_nan(T const& t)
0012   {
0013     return !std::isfinite(t);
0014     // return std::isnan(t);
0015     // return t != t
0016     // return std::numeric_limits<T>::has_quiet_NaN(t) || std::numeric_limits<T>::has_signaling_NaN(t);
0017   }
0018 }
0019 
0020 InttMonDraw::InttMonDraw(const std::string& name)
0021   : OnlMonDraw(name)
0022 {
0023 }
0024 
0025 InttMonDraw::~InttMonDraw()
0026 {
0027   delete m_style;
0028 
0029   for (auto& i : m_hist_felixbcofphxbco)
0030   {
0031     for (auto& j : i)
0032     {
0033       delete j;
0034     }
0035   }
0036 
0037   for (auto& i : m_hist_hitmap)
0038   {
0039     delete i;
0040   }
0041 
0042   for (auto& m_hist_hitrate : m_hist_hitrates)
0043   {
0044     delete m_hist_hitrate;
0045   }
0046 }
0047 
0048 int InttMonDraw::Init()
0049 {
0050   m_style = new TStyle("INTT_Style", "INTT_Style");
0051   m_style->SetOptStat(0);
0052 
0053   Int_t palette[3] = {kBlue, kGreen, kRed};
0054   m_style->SetPalette(3, palette);
0055   // m_style->SetNumberContours(3);
0056 
0057   return 0;
0058 }
0059 
0060 int InttMonDraw::Draw(const std::string& what)
0061 {
0062   int idraw = 0;
0063   int iret = 0;
0064 
0065   if (what == "ALL" || what == "SERVERSTATS")
0066   {
0067     iret += DrawServerStats();
0068     ++idraw;
0069   }
0070 
0071   if (what == "ALL" || what == "chip_hitmap")
0072   {
0073     iret += Draw_HitMap();
0074     ++idraw;
0075   }
0076 
0077 //  if (what == "ALL" || what == "bco_diff")
0078   if (what == "bco_diff")
0079   {
0080     iret += Draw_FelixBcoFphxBco();
0081     ++idraw;
0082   }
0083 
0084   if (what == "ALL" || what == "fphx_bco")
0085     //if (what == "fphx_bco")
0086   {
0087     iret += Draw_JustFphxBco();
0088     ++idraw;
0089   }
0090 
0091   if (what == "ALL" || what == "zoomed_fphx_bco")
0092     //if (what == "zoomed_fphx_bco")
0093   {
0094     iret += Draw_ZoomedFphxBco();
0095     ++idraw;
0096   }
0097 
0098   // if (what == "ALL" || what == "peaks")
0099   // {
0100   //   iret += Draw_Peaks(icnvs);
0101   //   ++idraw;
0102   // }
0103 
0104   if (what == "ALL" || what == "hitrates")
0105   {
0106     iret += Draw_HitRates();
0107     ++idraw;
0108   }
0109 
0110   // if (what == "ALL" || what == "history")
0111   if (what == "history")
0112   {
0113     iret += Draw_History();
0114     ++idraw;
0115   }
0116 
0117 //  if (what == "ALL" || what == "timing_okay")
0118   if (what == "timing_okay")
0119   {
0120     iret += Draw_TimingOkay();
0121     ++idraw;
0122   }
0123 
0124   if (!idraw)
0125   {
0126     std::cerr << __PRETTY_FUNCTION__ << ":" << __LINE__ << "\n"
0127               << "\tUnimplemented drawing option \"" << what << "\"" << std::endl;
0128   }
0129   if (std::fabs(iret) != idraw)  // at least one succeeded
0130   {
0131     return 0;
0132   }
0133 
0134   return iret;
0135 }
0136 
0137 int InttMonDraw::MakeHtml(const std::string& what)
0138 {
0139   int iret = Draw(what);
0140   if (iret)
0141   {
0142     return iret;
0143   }
0144 
0145   OnlMonClient* cl = OnlMonClient::instance();
0146   int icnt = 0;
0147   for (TCanvas* canvas : TC)
0148   {
0149     if (canvas == nullptr)
0150     {
0151       continue;
0152     }
0153     icnt++;
0154     // Register the canvas png file to the menu and produces the png file.
0155     std::string pngfile = cl->htmlRegisterPage(*this, canvas->GetTitle(), std::to_string(icnt), "png");
0156     cl->CanvasToPng(canvas, pngfile);
0157   }
0158 
0159   return 0;
0160 }
0161 
0162 int InttMonDraw::SavePlot(std::string const& what, std::string const& type)
0163 {
0164   OnlMonClient* cl = OnlMonClient::instance();
0165   int iret = Draw(what);
0166   if (iret)  // on error no png files please
0167   {
0168     return iret;
0169   }
0170   int icnt = 0;
0171   for (TCanvas* canvas : TC)
0172   {
0173     if (canvas == nullptr)
0174     {
0175       continue;
0176     }
0177     ++icnt;
0178     std::string filename = ThisName + "_" + std::to_string(icnt) + "_" + std::to_string(cl->RunNumber()) + "." + type;
0179     cl->CanvasToPng(canvas, filename);
0180   }
0181   return 0;
0182 }
0183 
0184 int InttMonDraw::MakeCanvas(const std::string& name)
0185 {
0186   OnlMonClient* cl = OnlMonClient::instance();
0187   int xsize = cl->GetDisplaySizeX();
0188   int ysize = cl->GetDisplaySizeY();
0189   m_cnvs_width = xsize;
0190   m_cnvs_height = ysize;
0191   if (name == "InttMonServerStats")
0192   {
0193     TC[k_server_stats] = new TCanvas(name.c_str(), "InttMon Server Stats", -1, 0, xsize, ysize);
0194     gSystem->ProcessEvents();
0195     transparent[k_server_stats] = new TPad(Form("transparent%d", k_server_stats), "this does not show", 0, 0, 1, 1);
0196     transparent[k_server_stats]->SetFillColor(kGray);
0197     transparent[k_server_stats]->Draw();
0198     TC[k_server_stats]->SetEditable(false);
0199     TC[k_server_stats]->SetTopMargin(0.05);
0200     TC[k_server_stats]->SetBottomMargin(0.05);
0201   }
0202   if (name == "InttFelixBcoFphxBco")
0203   {
0204     TC[k_felixbcofphxbco] = new TCanvas(name.c_str(), "Felix Fphx Bco (Triggered)", -1, 0, m_cnvs_width, m_cnvs_height);
0205     gSystem->ProcessEvents();
0206     transparent[k_felixbcofphxbco] = new TPad(Form("transparent%d", k_felixbcofphxbco), "this does not show", 0, 0, 1, 1);
0207     transparent[k_felixbcofphxbco]->SetFillStyle(4000);  // Transparent
0208     transparent[k_felixbcofphxbco]->Draw();
0209     MakeDispPad(k_felixbcofphxbco, 0.15);
0210     TC[k_felixbcofphxbco]->SetEditable(false);
0211     TC[k_felixbcofphxbco]->SetTopMargin(0.05);
0212     TC[k_felixbcofphxbco]->SetBottomMargin(0.05);
0213   }
0214   if (name == "InttJustFphxBco")
0215   {
0216     TC[k_justfphxbco] = new TCanvas(name.c_str(), "Just Fphx Bco (Streaming)", m_cnvs_width, m_cnvs_height);
0217     gSystem->ProcessEvents();
0218     transparent[k_justfphxbco] = new TPad(Form("transparent%d", k_justfphxbco), "this does not show", 0, 0, 1, 1);
0219     transparent[k_justfphxbco]->SetFillStyle(4000);  // Transparent
0220     transparent[k_justfphxbco]->Draw();
0221     MakeDispPad(k_justfphxbco, 0.15);
0222     TC[k_justfphxbco]->SetEditable(false);
0223     TC[k_justfphxbco]->SetTopMargin(0.05);
0224     TC[k_justfphxbco]->SetBottomMargin(0.05);
0225   }
0226   if (name == "InttZoomedFphxBco")
0227   {
0228     TC[k_zoomedfphxbco] = new TCanvas(name.c_str(), "Zoomed Fphx Bco (Streaming)", m_cnvs_width, m_cnvs_height);
0229     gSystem->ProcessEvents();
0230     transparent[k_zoomedfphxbco] = new TPad(Form("transparent%d", k_zoomedfphxbco), "this does not show", 0, 0, 1, 1);
0231     transparent[k_zoomedfphxbco]->SetFillStyle(4000);  // Transparent
0232     transparent[k_zoomedfphxbco]->Draw();
0233     MakeDispPad(k_zoomedfphxbco, 0.15);
0234     TC[k_zoomedfphxbco]->SetEditable(false);
0235     TC[k_zoomedfphxbco]->SetTopMargin(0.05);
0236     TC[k_zoomedfphxbco]->SetBottomMargin(0.05);
0237   }
0238   if (name == "InttHitMap")
0239   {
0240     TC[k_hitmap] = new TCanvas(name.c_str(), "Intt Hit Map", -1, 0, m_cnvs_width, m_cnvs_height);
0241     gSystem->ProcessEvents();
0242     transparent[k_hitmap] = new TPad(Form("transparent%d", k_hitmap), "this does not show", 0, 0, 1, 1);
0243     transparent[k_hitmap]->SetFillStyle(4000);  // Transparent
0244     transparent[k_hitmap]->Draw();
0245     MakeDispPad(k_hitmap, 0.1);
0246     TC[k_hitmap]->SetEditable(false);
0247     TC[k_hitmap]->SetTopMargin(0.05);
0248     TC[k_hitmap]->SetBottomMargin(0.05);
0249   }
0250   if (name == "InttHitRates")
0251   {
0252     TC[k_hitrates] = new TCanvas(name.c_str(), "Intt Hit Rates", -1, 0, m_cnvs_width, m_cnvs_height);
0253     gSystem->ProcessEvents();
0254     transparent[k_hitrates] = new TPad(Form("transparent%d", k_hitrates), "this does not show", 0, 0, 1, 1);
0255     transparent[k_hitrates]->SetFillStyle(4000);  // Transparent
0256     transparent[k_hitrates]->Draw();
0257     MakeDispPad(k_hitrates);
0258     TC[k_hitrates]->SetEditable(false);
0259     TC[k_hitrates]->SetTopMargin(0.05);
0260     TC[k_hitrates]->SetBottomMargin(0.05);
0261   }
0262   if (name == "InttHistory")
0263   {
0264     TC[k_history] = new TCanvas(name.c_str(), "Intt History", -1, 0, m_cnvs_width, m_cnvs_height);
0265     gSystem->ProcessEvents();
0266     transparent[k_history] = new TPad(Form("transparent%d", k_history), "this does not show", 0, 0, 1, 1);
0267     transparent[k_history]->SetFillStyle(4000);  // Transparent
0268     transparent[k_history]->Draw();
0269     MakeDispPad(k_history, 0.15);
0270     TC[k_history]->SetEditable(false);
0271     TC[k_history]->SetTopMargin(0.05);
0272     TC[k_history]->SetBottomMargin(0.05);
0273   }
0274   if (name == "InttTimingOkay")
0275   {
0276     TC[k_timing_okay] = new TCanvas(name.c_str(), "Intt Timing Okay?", -1, 0, m_cnvs_width, m_cnvs_height);
0277     gSystem->ProcessEvents();
0278     transparent[k_timing_okay] = new TPad(Form("transparent%d", k_timing_okay), "this does not show", 0, 0, 1, 1);
0279     transparent[k_timing_okay]->SetFillStyle(4000);  // Transparent
0280     transparent[k_timing_okay]->Draw();
0281     MakeDispPad(k_timing_okay);
0282     TC[k_timing_okay]->SetEditable(false);
0283     TC[k_timing_okay]->SetTopMargin(0.05);
0284     TC[k_timing_okay]->SetBottomMargin(0.05);
0285   }
0286   return 0;
0287 }
0288 
0289 int InttMonDraw::DrawServerStats()
0290 {
0291   OnlMonClient* cl = OnlMonClient::instance();
0292   if (!gROOT->FindObject("InttMonServerStats"))
0293   {
0294     MakeCanvas("InttMonServerStats");
0295   }
0296   TC[0]->Clear("D");
0297   TC[0]->SetEditable(true);
0298   transparent[0]->cd();
0299   TText PrintRun;
0300   PrintRun.SetTextFont(62);
0301   PrintRun.SetNDC();          // set to normalized coordinates
0302   PrintRun.SetTextAlign(23);  // center/top alignment
0303   PrintRun.SetTextSize(0.04);
0304   PrintRun.SetTextColor(1);
0305   PrintRun.DrawText(0.5, 0.99, "Server Statistics");
0306 
0307   PrintRun.SetTextSize(0.02);
0308   double vdist = 0.05;
0309   double vpos = 0.9;
0310   for (const auto& server : m_ServerSet)
0311   {
0312     std::ostringstream txt;
0313     auto servermapiter = cl->GetServerMap(server);
0314     if (servermapiter == cl->GetServerMapEnd())
0315     {
0316       txt << "Server " << server
0317           << " is dead ";
0318       PrintRun.SetTextColor(kRed);
0319     }
0320     else
0321     {
0322       txt << "Server " << server
0323           << ", run number " << std::get<1>(servermapiter->second)
0324           << ", event count: " << std::get<2>(servermapiter->second)
0325           << ", current time " << ctime(&(std::get<3>(servermapiter->second)));
0326       if (std::get<0>(servermapiter->second))
0327       {
0328         PrintRun.SetTextColor(kGray + 2);
0329       }
0330       else
0331       {
0332         PrintRun.SetTextColor(kRed);
0333       }
0334     }
0335     PrintRun.DrawText(0.5, vpos, txt.str().c_str());
0336     vpos -= vdist;
0337   }
0338   TC[0]->Update();
0339   TC[0]->Show();
0340   TC[0]->SetEditable(false);
0341 
0342   return 0;
0343 }
0344 
0345 int InttMonDraw::MakeDispPad(int icnvs, double lgnd_frac)
0346 {
0347   // For simplicity, set up every canvas to have all subpads for all options
0348   // then in other methods, we only use those subpads we need
0349   // It's SetFillStyle(4000) all the way down,
0350   // so this is transparent to end users
0351   std::string name = Form("intt_disp_pad_%d", icnvs);
0352   m_disp_pad[icnvs] = new TPad(
0353       name.c_str(), name.c_str(),  //
0354       0.0, 1.0 - m_disp_frac,      // Southwest x, y
0355       1.0, 1.0                     // Northeast x, y
0356   );
0357   TC[icnvs]->cd();
0358   m_disp_pad[icnvs]->SetFillStyle(4000);  // Transparent
0359   m_disp_pad[icnvs]->Range(0.0, 0.0, 1.0, 1.0);
0360   m_disp_pad[icnvs]->Draw();
0361 
0362   // Some methods do not need a legend, test this variable
0363   if (std::isfinite(lgnd_frac))
0364   {
0365     name = Form("intt_lgnd_pad_%d", icnvs);
0366     m_lgnd_pad[icnvs] = new TPad(
0367         name.c_str(), name.c_str(),  //
0368         1.0 - lgnd_frac, 0.0,        // Southwest x, y
0369         1.0, 1.0 - m_disp_frac       // Northeast x, y
0370     );
0371     TC[icnvs]->cd();
0372     m_lgnd_pad[icnvs]->SetFillStyle(4000);  // Transparent
0373     m_lgnd_pad[icnvs]->Range(0.0, 0.0, 1.0, 1.0);
0374     m_lgnd_pad[icnvs]->Draw();
0375   }
0376   else
0377   {
0378     lgnd_frac = 0.;
0379   }
0380 
0381   for (int i = 0; i < 8; ++i)
0382   {
0383     name = Form("intt_hist_pad_%d_%01d", icnvs, i);
0384     m_hist_pad[icnvs][i] = new TPad(
0385         name.c_str(), name.c_str(),                                                          //
0386         (i % 4 + 0.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 0.0) / 2.0 * (1.0 - m_disp_frac),  // Southwest x, y
0387         (i % 4 + 1.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 1.0) / 2.0 * (1.0 - m_disp_frac)   // Northeast x, y
0388     );
0389     TC[icnvs]->cd();
0390     m_hist_pad[icnvs][i]->SetFillStyle(4000);  // Transparent
0391     m_hist_pad[icnvs][i]->Range(0.0, 0.0, 1.0, 1.0);
0392     m_hist_pad[icnvs][i]->Draw();
0393 
0394     name = Form("intt_left_hist_pad_%d_%01d", icnvs, i);
0395     m_left_hist_pad[icnvs][i] = new TPad(
0396         name.c_str(), name.c_str(),                                                          //
0397         (i % 4 + 0.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 0.0) / 2.0 * (1.0 - m_disp_frac),  // Southwest x, y
0398         (i % 4 + 0.5) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 1.0) / 2.0 * (1.0 - m_disp_frac)   // Northeast x, y
0399     );
0400     TC[icnvs]->cd();
0401     m_left_hist_pad[icnvs][i]->SetFillStyle(4000);  // Transparent
0402     m_left_hist_pad[icnvs][i]->SetLeftMargin(0.15);
0403     m_left_hist_pad[icnvs][i]->SetRightMargin(0.01);
0404     m_left_hist_pad[icnvs][i]->Range(0.0, 0.0, 1.0, 1.0);
0405     m_left_hist_pad[icnvs][i]->Draw();
0406 
0407     name = Form("intt_right_hist_pad_%d_%01d", icnvs, i);
0408     m_right_hist_pad[icnvs][i] = new TPad(
0409         name.c_str(), name.c_str(),                                                          //
0410         (i % 4 + 0.5) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 0.0) / 2.0 * (1.0 - m_disp_frac),  // Southwest x, y
0411         (i % 4 + 1.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 1.0) / 2.0 * (1.0 - m_disp_frac)   // Northeast x, y
0412     );
0413     TC[icnvs]->cd();
0414     m_right_hist_pad[icnvs][i]->SetFillStyle(4000);  // Transparent
0415     m_right_hist_pad[icnvs][i]->SetLeftMargin(0.01);
0416     m_right_hist_pad[icnvs][i]->Range(0.0, 0.0, 1.0, 1.0);
0417     m_right_hist_pad[icnvs][i]->Draw();
0418 
0419     name = Form("intt_transparent_pad_%d_%01d", icnvs, i);
0420     m_transparent_pad[icnvs][i] = new TPad(
0421         name.c_str(), name.c_str(),                                                          //
0422         (i % 4 + 0.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 0.0) / 2.0 * (1.0 - m_disp_frac),  // Southwest x, y
0423         (i % 4 + 1.0) / 4.0 * (1.0 - lgnd_frac), (i / 4 + 1.0) / 2.0 * (1.0 - m_disp_frac)   // Northeast x, y
0424     );
0425     TC[icnvs]->cd();
0426     m_transparent_pad[icnvs][i]->SetFillStyle(4000);  // Transparent
0427     m_transparent_pad[icnvs][i]->Range(0.0, 0.0, 1.0, 1.0);
0428     m_transparent_pad[icnvs][i]->Draw();
0429   }
0430 
0431   name = Form("intt_single_hist_pad_%d", icnvs);
0432   m_single_hist_pad[icnvs] = new TPad(
0433       name.c_str(), name.c_str(),        //
0434       0.0,             0.0,              // Southwest x, y
0435       1.0 - lgnd_frac, 1.0 - m_disp_frac // Southwest x, y
0436 
0437   );
0438   TC[icnvs]->cd();
0439   m_single_hist_pad[icnvs]->SetFillStyle(4000);  // Transparent
0440   m_single_hist_pad[icnvs]->Range(0.0, 0.0, 1.0, 1.0);
0441   m_single_hist_pad[icnvs]->Draw();
0442 
0443   name = Form("intt_timing_okay_%d", icnvs);
0444   m_timing_okay_pad[icnvs] = new TPad(
0445       name.c_str(), name.c_str(),        //
0446       0.0,             0.0,              // Southwest x, y
0447       1.0 - lgnd_frac, 1.0 - m_disp_frac // Southwest x, y
0448 
0449   );
0450   TC[icnvs]->cd();
0451   m_timing_okay_pad[icnvs]->SetFillStyle(4000);  // Transparent
0452   m_timing_okay_pad[icnvs]->Range(0.0, 0.0, 1.0, 1.0);
0453   m_timing_okay_pad[icnvs]->Draw();
0454 
0455   name = Form("intt_single_transparent_pad_%d", icnvs);
0456   m_single_transparent_pad[icnvs] = new TPad(
0457       name.c_str(), name.c_str(),        //
0458       0.0,             0.0,              // Southwest x, y
0459       1.0 - lgnd_frac, 1.0 - m_disp_frac // Southwest x, y
0460 
0461   );
0462   TC[icnvs]->cd();
0463   m_single_transparent_pad[icnvs]->SetFillStyle(4000);  // Transparent
0464   m_single_transparent_pad[icnvs]->Range(0.0, 0.0, 1.0, 1.0);
0465   m_single_transparent_pad[icnvs]->Draw();
0466 
0467   return 0;
0468 }
0469 
0470 int InttMonDraw::DrawDispPad_Generic(int icnvs, const std::string& title)
0471 {
0472   m_disp_pad[icnvs]->Clear();
0473   m_disp_pad[icnvs]->cd();
0474 
0475   OnlMonClient* cl = OnlMonClient::instance();
0476 
0477   // Get the "event" count from the first server we can
0478   TH1* evt_hist{nullptr};
0479   for (int i = 0; i < 8; ++i)
0480   {
0481     if ((evt_hist = cl->getHisto(Form("INTTMON_%d", i), "InttEvtHist")))
0482     {
0483       break;
0484     }
0485   }
0486 
0487   // If we can't find any, there is a problem
0488   if (!evt_hist)
0489   {
0490     DrawDeadServer(transparent[icnvs]);
0491     TC[icnvs]->SetEditable(false);
0492     if (isHtml())
0493     {
0494       delete TC[icnvs];
0495       TC[icnvs] = nullptr;
0496     }
0497     return -1;
0498   }
0499 
0500   // Title
0501   TText title_text;
0502   title_text.SetTextAlign(22);
0503   title_text.SetTextSize(m_disp_text_size);
0504   title_text.DrawText(0.5, 0.75, title.c_str());
0505 
0506   // Display text
0507   std::pair<time_t,int> evttime = cl->EventTime("CURRENT");  // BOR, CURRENT, or EOR
0508   std::string text = "Run " + std::to_string(cl->RunNumber()) + ", Events: " + std::to_string((int) evt_hist->GetBinContent(1)) + ", " + ctime(&evttime.first);
0509   TText disp_text;
0510   disp_text.SetTextColor(evttime.second);
0511   disp_text.SetTextAlign(22);
0512   disp_text.SetTextSize(m_disp_text_size);
0513   disp_text.DrawText(0.5, 0.5, text.c_str());
0514 
0515   // Disclaimer if not enough events
0516   if (m_min_events > evt_hist->GetBinContent(1))
0517   {
0518     TText warn_text;
0519     warn_text.SetTextAlign(22);
0520     warn_text.SetTextSize(m_warn_text_size);
0521     warn_text.SetTextColor(kRed);
0522     warn_text.DrawText(0.5, 0.25, Form("Not statistically significant (fewer than  %0.E events)", m_min_events));
0523   }
0524   return 0;
0525 }
0526 
0527 //====== FelixBcoFphxBco ======//
0528 
0529 int InttMonDraw::Draw_FelixBcoFphxBco()
0530 {
0531   if (!gROOT->FindObject("InttFelixBcoFphxBco"))
0532   {
0533     MakeCanvas("InttFelixBcoFphxBco");
0534   }
0535 
0536   TC[k_felixbcofphxbco]->SetEditable(true);
0537   m_style->cd();
0538   if(DrawDispPad_Generic(k_felixbcofphxbco, TC[k_felixbcofphxbco]->GetTitle()) == -1)
0539   {
0540     return -1;
0541   }
0542 
0543   // Draw Legend
0544   double lgnd_text_size = 0.08;
0545   double lgnd_box_width = 0.16;
0546   // double lgnd_box_height = 0.01;
0547 
0548   std::string name;
0549 
0550   m_lgnd_pad[k_felixbcofphxbco]->Clear();
0551   m_lgnd_pad[k_felixbcofphxbco]->cd();
0552 
0553   double x0, y0; // , x[4], y[4];
0554   for (int fee = 0; fee < 14; ++fee)
0555   {
0556     x0 = 0.5 - lgnd_box_width;
0557     y0 = (2.0 * fee + 1.0) / (2.0 * 14);
0558 
0559     TText lgnd_text;
0560     lgnd_text.SetTextAlign(12);
0561     lgnd_text.SetTextSize(lgnd_text_size);
0562     lgnd_text.SetTextColor(kBlack);
0563     lgnd_text.DrawText(x0 + 1.5 * lgnd_box_width, y0, Form("FChn %2d", fee));
0564 
0565     // x[0] = -1, x[1] = +1, x[2] = +1, x[3] = -1;
0566     // y[0] = -1, y[1] = -1, y[2] = +1, y[3] = +1;
0567     // for (int i = 0; i < 4; ++i)
0568     // {
0569     //   x[i] *= 0.5 * lgnd_box_width;
0570     //   x[i] += x0;
0571 
0572     //   y[i] *= 0.5 * lgnd_box_height;
0573     //   y[i] += y0;
0574     // }
0575 
0576     // TPolyLine box;
0577     // box.SetFillColor(GetFeeColor(fee));
0578     // box.SetLineColor(kBlack);
0579     // box.SetLineWidth(1);
0580     // box.DrawPolyLine(4, x, y, "f");
0581     TLine line;
0582     line.SetLineColor(GetFeeColor(fee));
0583     line.SetLineStyle(GetFeeStyle(fee));
0584     line.SetLineWidth(3);
0585     line.DrawLine (
0586         x0 - 0.5 * lgnd_box_width, y0,
0587         x0 + 0.5 * lgnd_box_width, y0
0588     );
0589   }
0590 
0591   int iret = 1;
0592   for (int i = 0; i < 8; ++i)
0593   {
0594     // If any subdraw succeeds, say the entire call succeeds
0595     iret = DrawHistPad_FelixBcoFphxBco(i, k_felixbcofphxbco) && iret;
0596   }
0597 
0598   TC[k_felixbcofphxbco]->Update();
0599   TC[k_felixbcofphxbco]->Show();
0600   TC[k_felixbcofphxbco]->SetEditable(false);
0601 
0602   return iret;
0603 }
0604 
0605 int InttMonDraw::DrawHistPad_FelixBcoFphxBco(
0606     int i, int icnvs)
0607 {
0608   for (int fee = 0; fee < 14; ++fee)
0609   {
0610     std::string name = Form("intt_hist_%d_%02d_%02d", icnvs, i, fee);
0611     if (!m_hist_felixbcofphxbco[i][fee])
0612     {
0613       TC[icnvs]->cd();
0614       m_hist_felixbcofphxbco[i][fee] = new TH1D(
0615           name.c_str(), name.c_str(),  //
0616           128, 0, 128                  //
0617       );
0618       m_hist_felixbcofphxbco[i][fee]->SetTitle(Form("intt%01d;Felix BCO - FPHX BCO;Counts (Hits)", i));
0619       m_hist_felixbcofphxbco[i][fee]->GetXaxis()->SetNdivisions(16);  //, true);
0620       m_hist_felixbcofphxbco[i][fee]->SetLineColor(GetFeeColor(fee));
0621       m_hist_felixbcofphxbco[i][fee]->SetLineStyle(GetFeeStyle(fee));
0622       m_hist_felixbcofphxbco[i][fee]->SetFillStyle(4000);  // Transparent
0623     }
0624     m_hist_pad[k_felixbcofphxbco][i]->SetLogy();
0625     m_hist_pad[k_felixbcofphxbco][i]->cd();
0626 
0627     m_hist_felixbcofphxbco[i][fee]->Reset();
0628     m_hist_felixbcofphxbco[i][fee]->Draw("same");
0629   }
0630 
0631   // Access client
0632   OnlMonClient* cl = OnlMonClient::instance();
0633 
0634   TH1* bco_hist = cl->getHisto(Form("INTTMON_%d", i), "InttBcoHist");
0635   m_transparent_pad[k_felixbcofphxbco][i]->Clear();
0636   if (!bco_hist)
0637   {
0638     m_transparent_pad[k_felixbcofphxbco][i]->cd();
0639     TText dead_text;
0640     dead_text.SetTextColor(kBlue);
0641     dead_text.SetTextAlign(22);
0642     dead_text.SetTextSize(0.1);
0643     dead_text.SetTextAngle(45);
0644     dead_text.DrawText(0.5, 0.5, "Dead Server");
0645     return 1;
0646   }
0647 
0648   // Fill
0649   double max = 0;
0650   for (int fee = 0; fee < NFEES; ++fee)
0651   {
0652     for (int bco = 0; bco < NBCOS; ++bco)
0653     {
0654       int bincont = bco_hist->GetBinContent(bco_hist->GetBin(1, fee * NBCOS + bco + 1));
0655 
0656       if (has_nan(bincont))
0657       {
0658         continue;
0659       }
0660 
0661       if (bincont > max)
0662       {
0663         max = bincont;
0664       }
0665 
0666       m_hist_felixbcofphxbco[i][fee]->SetBinContent(bco + 1, bincont);  // + 1 is b/c the 0th bin is an underflow bin
0667     }
0668   }
0669 
0670   if(0 == max) // max was unset
0671   {
0672     max = 10;
0673   }
0674   else if(max < 0 || (max *= 10) < 0 || has_nan(max)) // max underflowed in the server or underflowed when mutliplying by 10
0675   {
0676     max = std::numeric_limits<int>::max();
0677   }
0678 
0679   // Noramlize ranges
0680   for (int fee = 0; fee < NFEES; ++fee)
0681   {
0682     m_hist_felixbcofphxbco[i][fee]->GetYaxis()->SetRangeUser(1, max);
0683   }
0684 
0685   return 0;
0686 }
0687 
0688 //====== JustFphxBco ======//
0689 
0690 int InttMonDraw::Draw_JustFphxBco()
0691 {
0692   if (!gROOT->FindObject("InttJustFphxBco"))
0693   {
0694     MakeCanvas("InttJustFphxBco");
0695   }
0696 
0697   TC[k_justfphxbco]->SetEditable(true);
0698   m_style->cd();
0699   if(DrawDispPad_Generic(k_justfphxbco, TC[k_justfphxbco]->GetTitle()) == -1)
0700   {
0701     return -1;
0702   }
0703 
0704   // Draw Legend
0705   double lgnd_text_size = 0.08;
0706   double lgnd_box_width = 0.16;
0707   // double lgnd_box_height = 0.01;
0708 
0709   std::string name;
0710 
0711   m_lgnd_pad[k_justfphxbco]->Clear();
0712   m_lgnd_pad[k_justfphxbco]->cd();
0713 
0714   double x0, y0; // , x[4], y[4];
0715   for (int fee = 0; fee < 14; ++fee)
0716   {
0717     x0 = 0.5 - lgnd_box_width;
0718     y0 = (2.0 * fee + 1.0) / (2.0 * 14);
0719 
0720     TText lgnd_text;
0721     lgnd_text.SetTextAlign(12);
0722     lgnd_text.SetTextSize(lgnd_text_size);
0723     lgnd_text.SetTextColor(kBlack);
0724     lgnd_text.DrawText(x0 + 1.5 * lgnd_box_width, y0, Form("FChn %2d", fee));
0725 
0726     // x[0] = -1, x[1] = +1, x[2] = +1, x[3] = -1;
0727     // y[0] = -1, y[1] = -1, y[2] = +1, y[3] = +1;
0728     // for (int i = 0; i < 4; ++i)
0729     // {
0730     //   x[i] *= 0.5 * lgnd_box_width;
0731     //   x[i] += x0;
0732 
0733     //   y[i] *= 0.5 * lgnd_box_height;
0734     //   y[i] += y0;
0735     // }
0736 
0737     // TPolyLine box;
0738     // box.SetFillColor(GetFeeColor(fee));
0739     // box.SetLineColor(kBlack);
0740     // box.SetLineWidth(1);
0741     // box.DrawPolyLine(4, x, y, "f");
0742     TLine line;
0743     line.SetLineColor(GetFeeColor(fee));
0744     line.SetLineStyle(GetFeeStyle(fee));
0745     line.SetLineWidth(3);
0746     line.DrawLine (
0747         x0 - 0.5 * lgnd_box_width, y0,
0748         x0 + 0.5 * lgnd_box_width, y0
0749     );
0750   }
0751 
0752   int iret = 1;
0753   for (int i = 0; i < 8; ++i)
0754   {
0755     // If any subdraw succeeds, say the entire call succeeds
0756     iret = DrawHistPad_JustFphxBco(i, k_justfphxbco) && iret;
0757   }
0758 
0759   TC[k_justfphxbco]->Update();
0760   TC[k_justfphxbco]->Show();
0761   TC[k_justfphxbco]->SetEditable(false);
0762 
0763   return iret;
0764 }
0765 
0766 int InttMonDraw::DrawHistPad_JustFphxBco(
0767     int i, int icnvs)
0768 {
0769   for (int fee = 0; fee < 14; ++fee)
0770   {
0771     std::string name = Form("intt_hist_%d_%02d_%02d", icnvs, i, fee);
0772     if (!m_hist_justfphxbco[i][fee])
0773     {
0774       TC[icnvs]->cd();
0775       m_hist_justfphxbco[i][fee] = new TH1D(
0776           name.c_str(), name.c_str(),  //
0777           128, 0, 128                  //
0778       );
0779       m_hist_justfphxbco[i][fee]->SetTitle(Form("intt%01d;FPHX BCO;Counts (Hits)", i));
0780       m_hist_justfphxbco[i][fee]->GetXaxis()->SetNdivisions(16);  //, true);
0781       m_hist_justfphxbco[i][fee]->SetLineColor(GetFeeColor(fee));
0782       m_hist_justfphxbco[i][fee]->SetLineStyle(GetFeeStyle(fee));
0783       m_hist_justfphxbco[i][fee]->SetFillStyle(4000);  // Transparent
0784     }
0785     m_hist_pad[k_justfphxbco][i]->SetLogy();
0786     m_hist_pad[k_justfphxbco][i]->cd();
0787 
0788     m_hist_justfphxbco[i][fee]->Reset();
0789     m_hist_justfphxbco[i][fee]->Draw("same");
0790   }
0791 
0792   // Access client
0793   OnlMonClient* cl = OnlMonClient::instance();
0794 
0795   TH1* bco_hist = cl->getHisto(Form("INTTMON_%d", i), "InttBcoHist");
0796   m_transparent_pad[k_justfphxbco][i]->Clear();
0797   if (!bco_hist)
0798   {
0799     m_transparent_pad[k_justfphxbco][i]->cd();
0800     TText dead_text;
0801     dead_text.SetTextColor(kBlue);
0802     dead_text.SetTextAlign(22);
0803     dead_text.SetTextSize(0.1);
0804     dead_text.SetTextAngle(45);
0805     dead_text.DrawText(0.5, 0.5, "Dead Server");
0806     return 1;
0807   }
0808 
0809   // Fill
0810   double max = 0;
0811   for (int fee = 0; fee < NFEES; ++fee)
0812   {
0813     for (int bco = 0; bco < NBCOS; ++bco)
0814     {
0815       int bincont = bco_hist->GetBinContent(bco_hist->GetBin(2, fee * NBCOS + bco + 1));
0816 
0817       if(has_nan(bincont))
0818       {
0819         continue;
0820       }
0821 
0822       if (bincont > max)
0823       {
0824         max = bincont;
0825       }
0826       m_hist_justfphxbco[i][fee]->SetBinContent(bco + 1, bincont);  // + 1 is b/c the 0th bin is an underflow bin
0827     }
0828   }
0829 
0830   if(0 == max) // max was unset
0831   {
0832     max = 10;
0833   }
0834   else if(max < 0 || (max *= 10) < 0 || has_nan(max)) // max underflowed in the server or underflowed when mutliplying by 10
0835   {
0836     max = std::numeric_limits<int>::max();
0837   }
0838 
0839   // Noramlize ranges
0840   for (int fee = 0; fee < NFEES; ++fee)
0841   {
0842     m_hist_justfphxbco[i][fee]->GetYaxis()->SetRangeUser(1, max);
0843   }
0844 
0845   return 0;
0846 }
0847 
0848 //====== ZoomedFphxBco ======//
0849 
0850 int InttMonDraw::Draw_ZoomedFphxBco()
0851 {
0852   if (!gROOT->FindObject("InttZoomedFphxBco"))
0853   {
0854     MakeCanvas("InttZoomedFphxBco");
0855   }
0856 
0857   TC[k_zoomedfphxbco]->SetEditable(true);
0858   m_style->cd();
0859   if(DrawDispPad_Generic(k_zoomedfphxbco, TC[k_zoomedfphxbco]->GetTitle()) == -1)
0860   {
0861     return -1;
0862   }
0863 
0864   // Draw Legend
0865   double lgnd_text_size = 0.08;
0866   double lgnd_box_width = 0.16;
0867   // double lgnd_box_height = 0.01;
0868 
0869   std::string name;
0870 
0871   m_lgnd_pad[k_zoomedfphxbco]->Clear();
0872   m_lgnd_pad[k_zoomedfphxbco]->cd();
0873 
0874   double x0, y0; //, x[4], y[4];
0875   for (int fee = 0; fee < 14; ++fee)
0876   {
0877     x0 = 0.5 - lgnd_box_width;
0878     y0 = (2.0 * fee + 1.0) / (2.0 * 14);
0879 
0880     TText lgnd_text;
0881     lgnd_text.SetTextAlign(12);
0882     lgnd_text.SetTextSize(lgnd_text_size);
0883     lgnd_text.SetTextColor(kBlack);
0884     lgnd_text.DrawText(x0 + 1.5 * lgnd_box_width, y0, Form("FChn %2d", fee));
0885 
0886     // x[0] = -1, x[1] = +1, x[2] = +1, x[3] = -1;
0887     // y[0] = -1, y[1] = -1, y[2] = +1, y[3] = +1;
0888     // for (int i = 0; i < 4; ++i)
0889     // {
0890     //   x[i] *= 0.5 * lgnd_box_width;
0891     //   x[i] += x0;
0892 
0893     //   y[i] *= 0.5 * lgnd_box_height;
0894     //   y[i] += y0;
0895     // }
0896 
0897     // TPolyLine box;
0898     // box.SetFillColor(GetFeeColor(fee));
0899     // box.SetLineColor(kBlack);
0900     // box.SetLineWidth(1);
0901     // box.DrawPolyLine(4, x, y, "f");
0902     TLine line;
0903     line.SetLineColor(GetFeeColor(fee));
0904     line.SetLineStyle(GetFeeStyle(fee));
0905     line.SetLineWidth(3);
0906     line.DrawLine (
0907         x0 - 0.5 * lgnd_box_width, y0,
0908         x0 + 0.5 * lgnd_box_width, y0
0909     );
0910 
0911   }
0912 
0913   int iret = 1;
0914   for (int i = 0; i < 8; ++i)
0915   {
0916     // If any subdraw succeeds, say the entire call succeeds
0917     iret = DrawHistPad_ZoomedFphxBco(i, k_zoomedfphxbco) && iret;
0918   }
0919 
0920   TC[k_zoomedfphxbco]->Update();
0921   TC[k_zoomedfphxbco]->Show();
0922   TC[k_zoomedfphxbco]->SetEditable(false);
0923 
0924   return iret;
0925 }
0926 
0927 int InttMonDraw::DrawHistPad_ZoomedFphxBco(
0928     int i, int icnvs)
0929 {
0930   int num_fphx_bins = 20;
0931   for (int fee = 0; fee < NFEES; ++fee)
0932   {
0933     std::string name = Form("intt_left_hist_%d_%02d_%02d", icnvs, i, fee);
0934     if (!m_left_hist_zoomedfphxbco[i][fee])
0935     {
0936       TC[icnvs]->cd();
0937       m_left_hist_zoomedfphxbco[i][fee] = new TH1D(
0938           name.c_str(), name.c_str(),  //
0939           num_fphx_bins, 0, num_fphx_bins
0940       );
0941       m_left_hist_zoomedfphxbco[i][fee]->SetTitle(Form("intt%01d;FPHX BCO;Counts (Hits)", i));
0942       m_left_hist_zoomedfphxbco[i][fee]->SetTitleSize(0.04);
0943       m_left_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetNdivisions(10);
0944       // m_left_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetLabelSize(0);
0945       // m_left_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetLabelOffset(999);
0946       m_left_hist_zoomedfphxbco[i][fee]->GetYaxis()->SetLabelSize(0.04);
0947       m_left_hist_zoomedfphxbco[i][fee]->SetLineColor(GetFeeColor(fee));
0948       m_left_hist_zoomedfphxbco[i][fee]->SetLineStyle(GetFeeStyle(fee));
0949       m_left_hist_zoomedfphxbco[i][fee]->SetFillStyle(4000);  // Transparent
0950     }
0951     m_left_hist_pad[k_zoomedfphxbco][i]->SetLogy();
0952     m_left_hist_pad[k_zoomedfphxbco][i]->cd();
0953     m_left_hist_zoomedfphxbco[i][fee]->Reset();
0954     m_left_hist_zoomedfphxbco[i][fee]->Draw("same");
0955    
0956     name = Form("intt_right_hist_%d_%02d_%02d", icnvs, i, fee);
0957     if (!m_right_hist_zoomedfphxbco[i][fee])
0958     {
0959       TC[icnvs]->cd();
0960       m_right_hist_zoomedfphxbco[i][fee] = new TH1D(
0961           name.c_str(), name.c_str(),  //
0962           num_fphx_bins, 128 - num_fphx_bins, 128
0963       );
0964       m_right_hist_zoomedfphxbco[i][fee]->SetTitle(Form("intt%01d;FPHX BCO;Counts (Hits)", i));
0965       m_right_hist_zoomedfphxbco[i][fee]->SetTitleSize(0.0);
0966       m_right_hist_zoomedfphxbco[i][fee]->SetTitleOffset(999);
0967       m_right_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetNdivisions(10);
0968       // m_right_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetLabelSize(0);
0969       // m_right_hist_zoomedfphxbco[i][fee]->GetXaxis()->SetLabelOffset(999);
0970       m_right_hist_zoomedfphxbco[i][fee]->GetYaxis()->SetLabelSize(0);
0971       m_right_hist_zoomedfphxbco[i][fee]->GetYaxis()->SetLabelOffset(999);
0972       m_right_hist_zoomedfphxbco[i][fee]->SetLineColor(GetFeeColor(fee));
0973       m_right_hist_zoomedfphxbco[i][fee]->SetLineStyle(GetFeeStyle(fee));
0974       m_right_hist_zoomedfphxbco[i][fee]->SetFillStyle(4000);  // Transparent
0975     } 
0976     m_right_hist_pad[k_zoomedfphxbco][i]->SetLogy();
0977     m_right_hist_pad[k_zoomedfphxbco][i]->cd();
0978     m_right_hist_zoomedfphxbco[i][fee]->Reset();
0979     m_right_hist_zoomedfphxbco[i][fee]->Draw("same");
0980   }
0981 
0982   // Access client
0983   OnlMonClient* cl = OnlMonClient::instance();
0984 
0985   TH1* bco_hist = cl->getHisto(Form("INTTMON_%d", i), "InttBcoHist");
0986   m_transparent_pad[k_zoomedfphxbco][i]->Clear();
0987   if (!bco_hist)
0988   {
0989     m_transparent_pad[k_zoomedfphxbco][i]->cd();
0990     TText dead_text;
0991     dead_text.SetTextColor(kBlue);
0992     dead_text.SetTextAlign(22);
0993     dead_text.SetTextSize(0.1);
0994     dead_text.SetTextAngle(45);
0995     dead_text.DrawText(0.5, 0.5, "Dead Server");
0996     return 1;
0997   }
0998 
0999   // Fill
1000   double max = 0;
1001   for (int fee = 0; fee < NFEES; ++fee)
1002   {
1003     for (int bco = 0; bco < num_fphx_bins; ++bco)
1004     {
1005       int bincont = bco_hist->GetBinContent(bco_hist->GetBin(2, fee * NBCOS + bco + 1));
1006 
1007       if(has_nan(bincont))
1008       {
1009         continue;
1010       }
1011 
1012       if (bincont > max)
1013       {
1014         max = bincont;
1015       }
1016       m_left_hist_zoomedfphxbco[i][fee]->SetBinContent(bco + 1, bincont);  // + 1 is b/c the 0th bin is an underflow bin
1017     }
1018 
1019     for (int bco = 128 - num_fphx_bins; bco < 128; ++bco)
1020     {
1021       int bincont = bco_hist->GetBinContent(bco_hist->GetBin(2, fee * NBCOS + bco + 1));
1022 
1023       if(has_nan(bincont))
1024       {
1025         continue;
1026       }
1027 
1028       if (bincont > max)
1029       {
1030         max = bincont;
1031       }
1032       m_right_hist_zoomedfphxbco[i][fee]->SetBinContent(bco - (128 - num_fphx_bins) + 1, bincont);  // + 1 is b/c the 0th bin is an underflow bin
1033     }
1034   }
1035 
1036   if(0 == max) // max was unset
1037   {
1038     max = 10;
1039   }
1040   else if(max < 0 || (max *= 10) < 0 || has_nan(max)) // max underflowed in the server or underflowed when mutliplying by 10
1041   {
1042     max = std::numeric_limits<int>::max();
1043   }
1044 
1045   // Noramlize ranges
1046   for (int fee = 0; fee < NFEES; ++fee)
1047   {
1048     m_left_hist_zoomedfphxbco[i][fee]->GetYaxis()->SetRangeUser(1, max);
1049     m_right_hist_zoomedfphxbco[i][fee]->GetYaxis()->SetRangeUser(1, max);
1050 
1051     // TLines
1052     TLine line;
1053     line.SetLineWidth(6);
1054     line.SetLineColor(kMagenta);
1055     line.SetLineStyle(2);
1056   
1057     m_left_hist_pad[k_zoomedfphxbco][i]->cd();
1058     line.DrawLine(5, 0, 5, max);
1059   
1060     m_right_hist_pad[k_zoomedfphxbco][i]->cd();
1061     line.DrawLine(116, 0, 116, max);
1062     line.DrawLine(120, 0, 120, max);
1063   }
1064 
1065   return 0;
1066 }
1067 
1068 Color_t
1069 InttMonDraw::GetFeeColor(
1070     int const& fee)
1071 {
1072   switch (fee % 7)
1073   {
1074   case 0:
1075     return kBlack;
1076   case 1:
1077     return kRed;
1078   case 2:
1079     return kViolet;
1080   case 3:
1081     return kGreen;
1082   case 4:
1083     return kCyan;
1084   case 5:
1085     return kBlue;
1086   case 6:
1087     return kMagenta;
1088   }
1089   return kBlack;
1090 }
1091 
1092 int
1093 InttMonDraw::GetFeeStyle(
1094     int const& fee)
1095 {
1096     return (fee % 2 == 0) ?
1097         kSolid:
1098         kDotted;
1099 }
1100 
1101 
1102 //====== HitMap ======//
1103 
1104 int InttMonDraw::Draw_HitMap()
1105 {
1106   // Set member variables we use to what they should be at beginning of each call
1107   if (!gROOT->FindObject("InttHitMap"))
1108   {
1109     MakeCanvas("InttHitMap");
1110   }
1111 
1112   TC[k_hitmap]->SetEditable(true);
1113   m_style->cd();
1114   if(DrawDispPad_Generic(k_hitmap, TC[k_hitmap]->GetTitle()) == -1)
1115   {
1116     return -1;
1117   }
1118 
1119   // Legend Pad
1120   double lgnd_box_width = 0.16;
1121   double lgnd_box_height = 0.03;
1122   double lgnd_text_size = 0.12;
1123 
1124   m_lgnd_pad[k_hitmap]->Clear();
1125   m_lgnd_pad[k_hitmap]->cd();
1126 
1127   int color;
1128   std::string label;
1129   double x0, y0, x[4], y[4];
1130   for (int c = 0; c < 3; ++c)
1131   {
1132     x0 = 0.5 - lgnd_box_width;
1133     y0 = (2.0 * c + 1.0) / (2.0 * 3);
1134 
1135     switch (c)
1136     {
1137     case 0:
1138       label = "Cold";
1139       color = kBlue;
1140       break;
1141     case 1:
1142       label = "Good";
1143       color = kGreen;
1144       break;
1145     case 2:
1146       label = "Hot";
1147       color = kRed;
1148       break;
1149     default:
1150       label = "Unknown";
1151       color = kOrange;
1152       break;
1153     }
1154 
1155     TText lgnd_text;
1156     lgnd_text.SetTextAlign(12);
1157     lgnd_text.SetTextSize(lgnd_text_size);
1158     lgnd_text.SetTextColor(kBlack);
1159     lgnd_text.DrawText(
1160         x0 + 1.5 * lgnd_box_width, y0,  //
1161         label.c_str()                   //
1162     );
1163 
1164     x[0] = -1, x[1] = +1, x[2] = +1, x[3] = -1;
1165     y[0] = -1, y[1] = -1, y[2] = +1, y[3] = +1;
1166     for (int i = 0; i < 4; ++i)
1167     {
1168       x[i] *= 0.5 * lgnd_box_width;
1169       x[i] += x0;
1170 
1171       y[i] *= 0.5 * lgnd_box_height;
1172       y[i] += y0;
1173     }
1174 
1175     TPolyLine box;
1176     box.SetFillColor(color);
1177     box.SetLineColor(kBlack);
1178     box.SetLineWidth(1);
1179     box.DrawPolyLine(4, x, y, "f");
1180   }
1181 
1182   // Draw histograms
1183   int iret = 0;
1184   for (int i = 0; i < 8; ++i)
1185   {
1186     // If any subdraw succeeds, say the entire call succeeds
1187     iret = DrawHistPad_HitMap(i, k_hitmap) && iret;
1188   }
1189 
1190   TC[k_hitmap]->Update();
1191   TC[k_hitmap]->Show();
1192   TC[k_hitmap]->SetEditable(false);
1193 
1194   return iret;
1195 }
1196 
1197 int InttMonDraw::DrawHistPad_HitMap(int i, int icnvs)
1198 {
1199   std::string name = Form("intt_hist_%d_%01d", icnvs, i);
1200   if (!m_hist_hitmap[i])
1201   {
1202     TC[icnvs]->cd();
1203     m_hist_hitmap[i] = new TH2D(
1204         name.c_str(), name.c_str(),
1205         26, -0.5, 25.5, //
1206         14, -0.5, 13.5  //
1207     );
1208     m_hist_hitmap[i]->SetTitle(Form("intt%01d;Chip ID (0-base);Felix Channel", i));
1209 
1210     m_hist_hitmap[i]->GetXaxis()->SetNdivisions(13, true);
1211     m_hist_hitmap[i]->GetYaxis()->SetNdivisions(14, true);
1212     m_hist_hitmap[i]->GetZaxis()->SetRangeUser(0, 3);
1213     m_hist_hitmap[i]->SetFillStyle(4000);  // Transparent
1214 
1215     Double_t levels[4] = {0, 1, 2, 3};
1216     m_hist_hitmap[i]->SetContour(4, levels);
1217   }
1218   m_hist_pad[k_hitmap][i]->SetGrid(1);
1219   m_hist_pad[k_hitmap][i]->cd();
1220 
1221   m_hist_hitmap[i]->Reset();
1222   m_hist_hitmap[i]->Draw("COL");  // "COLZ" for a legend, "COL" for no legend; no legend is preferrable here
1223 
1224   // Access client
1225   OnlMonClient* cl = OnlMonClient::instance();
1226 
1227   TH1* evt_hist = cl->getHisto(Form("INTTMON_%d", i), "InttEvtHist");
1228   TH1* hit_hist = cl->getHisto(Form("INTTMON_%d", i), "InttHitHist");
1229   m_transparent_pad[k_hitmap][i]->Clear();
1230   if (!evt_hist || !hit_hist)
1231   {
1232     m_transparent_pad[k_hitmap][i]->cd();
1233     TText dead_text;
1234     dead_text.SetTextColor(kBlue);
1235     dead_text.SetTextAlign(22);
1236     dead_text.SetTextSize(0.1);
1237     dead_text.SetTextAngle(45);
1238     dead_text.DrawText(0.5, 0.5, "Dead Server");
1239     return 1;
1240   }
1241 
1242   // Fill
1243   for (int fee = 0; fee < NFEES; ++fee)
1244   {
1245     for (int chp = 0; chp < NCHIPS; ++chp)
1246     {
1247       double bincont = hit_hist->GetBinContent(fee * NCHIPS + chp + 1);
1248       if(!bincont)
1249       {
1250         continue;
1251       }
1252       bincont /= evt_hist->GetBinContent(2); // Normalize by number of unique BCOs
1253 
1254       if (has_nan(bincont))
1255       {
1256         continue;
1257       }
1258 
1259       // Assign a value to this bin
1260       // that will give it the appropriate color
1261       // based on how it compares to the hot/cold thresholds
1262       if (bincont < m_lower)
1263       {
1264         bincont = 0.4;  // 0.4 Cold/Dead
1265       }
1266       else if (m_upper < bincont)
1267       {
1268         bincont = 3.0;  // 3.0 Hot
1269       }
1270       else
1271       {
1272         bincont = 1.7;  // 1.7 Good
1273       }
1274 
1275       m_hist_hitmap[i]->SetBinContent(chp + 1, fee + 1, bincont);  // +1 to start at first bin
1276     }
1277   }
1278 
1279   return 0;
1280 }
1281 
1282 //====== HitRates ======//
1283 
1284 int InttMonDraw::Draw_HitRates()
1285 {
1286   if (!gROOT->FindObject("InttHitRates"))
1287   {
1288     MakeCanvas("InttHitRates");
1289   }
1290 
1291   TC[k_hitrates]->SetEditable(true);
1292   m_style->cd();
1293   if(DrawDispPad_Generic(k_hitrates, TC[k_hitrates]->GetTitle()) == -1)
1294   {
1295     return -1;
1296   }
1297 
1298   int iret = 1;
1299   for (int i = 0; i < 8; ++i)
1300   {
1301     // If any subdraw succeeds, say the entire call succeeds
1302     iret = DrawHistPad_HitRates(i, k_hitrates) && iret;
1303   }
1304 
1305   TC[k_hitrates]->Update();
1306   TC[k_hitrates]->Show();
1307   TC[k_hitrates]->SetEditable(false);
1308 
1309   return iret;
1310 }
1311 
1312 int InttMonDraw::DrawHistPad_HitRates(
1313     int i, int icnvs)
1314 {
1315   // Access client
1316   OnlMonClient* cl = OnlMonClient::instance();
1317 
1318   TH1* evt_hist = cl->getHisto(Form("INTTMON_%d", i), "InttEvtHist");
1319   TH1* hit_hist = cl->getHisto(Form("INTTMON_%d", i), "InttHitHist");
1320   m_transparent_pad[k_hitrates][i]->Clear();
1321   if (!evt_hist || !hit_hist)
1322   {
1323     m_transparent_pad[k_hitrates][i]->cd();
1324     TText dead_text;
1325     dead_text.SetTextColor(kBlue);
1326     dead_text.SetTextAlign(22);
1327     dead_text.SetTextSize(0.1);
1328     dead_text.SetTextAngle(45);
1329     dead_text.DrawText(0.5, 0.5, "Dead Server");
1330     return 1;
1331   }
1332 
1333   Long64_t counts = 0;
1334   std::map<Float_t, Long64_t> hitrate_pdf;
1335 
1336   // Fill
1337   for (int fee = 0; fee < NFEES; ++fee)
1338   {
1339     for (int chp = 0; chp < NCHIPS; ++chp)
1340     {
1341       double bincont = hit_hist->GetBinContent(fee * NCHIPS + chp + 1);
1342       bincont /= evt_hist->GetBinContent(2); // Normalize by number of events
1343 
1344       if(has_nan(bincont))
1345       {
1346         continue;
1347       }
1348 
1349       ++hitrate_pdf[bincont];
1350       ++counts;
1351     }
1352   }
1353 
1354   // For upper bound of plot, get 95th percentile hitrate and double it
1355   float max_hitrate = 0;
1356   Long64_t integrated = 0;
1357   for (std::map<Float_t, Long64_t>::reverse_iterator itr = hitrate_pdf.rbegin(); itr != hitrate_pdf.rend(); ++itr)
1358   {
1359     max_hitrate = itr->first;
1360     integrated += itr->second;
1361     if (1.0 * integrated / counts < 0.05) // reverse iterator, 0.05 really means .95
1362     {
1363       break;
1364     }
1365   }
1366   max_hitrate *= 2.0;
1367 
1368   m_hist_pad[k_hitrates][i]->Clear();
1369   delete m_hist_hitrates[i];
1370   std::string name = Form("intt_hitrate_hist_%d_%01d", icnvs, i);
1371   m_hist_hitrates[i] = new TH1D(
1372       name.c_str(), name.c_str(), //
1373       112, 0.0, max_hitrate       //
1374   );
1375   m_hist_hitrates[i]->SetTitle(Form("intt%01d;Hits/Event;Entries (One Hitrate per Chip)", i));
1376   m_hist_hitrates[i]->GetXaxis()->SetNdivisions(8, true);
1377   m_hist_hitrates[i]->SetFillStyle(4000); // Transparent
1378   m_hist_pad[k_hitrates][i]->cd();
1379 
1380   // Fill
1381   for (auto const& [rate, count] : hitrate_pdf)
1382   {
1383     // using Fill(rate, count) directly causes ROOT to track and draw errors that don't make sense
1384     int bin = m_hist_hitrates[i]->FindBin(rate);
1385     if (max_hitrate < rate)
1386     {
1387       bin = m_hist_hitrates[i]->GetNbinsX();
1388     }
1389     m_hist_hitrates[i]->SetBinContent(bin, m_hist_hitrates[i]->GetBinContent(bin) + count);
1390   }
1391   m_hist_hitrates[i]->Draw("");
1392 
1393   return 0;
1394 }
1395 
1396 //====== History ======//
1397 
1398 int InttMonDraw::Draw_History()
1399 {
1400   if (!gROOT->FindObject("InttHistory"))
1401   {
1402     MakeCanvas("InttHistory");
1403   }
1404 
1405   TC[k_history]->SetEditable(true);
1406   m_style->cd();
1407   if(DrawDispPad_Generic(k_history, TC[k_history]->GetTitle()) == -1)
1408   {
1409     return -1;
1410   }
1411 
1412   // hist
1413   double max = 0.0;
1414   int num_dead = 0;
1415 
1416   int oldest = std::numeric_limits<int>::max();
1417   int newest = std::numeric_limits<int>::min();
1418 
1419   for(int i = 0; i < 8; ++i)
1420   {
1421     // Access client
1422     OnlMonClient* cl = OnlMonClient::instance();
1423 
1424     TH1I* evt_hist = dynamic_cast<TH1I*>(cl->getHisto(Form("INTTMON_%d", i), "InttEvtHist"));
1425     if(!evt_hist)
1426     {
1427       m_single_transparent_pad[k_history]->cd();
1428       TText dead_text;
1429       dead_text.SetTextColor(kBlue);
1430       dead_text.SetTextAlign(22);
1431       dead_text.SetTextSize(0.1);
1432       dead_text.SetTextAngle(45);
1433       // dead_text.DrawText(0.5, 0.5, "Dead Onlmon Server");
1434       ++num_dead;
1435       continue;
1436     }
1437 
1438     TH1* log_hist = cl->getHisto(Form("INTTMON_%d", i), "InttLogHist");
1439     if(!log_hist)
1440     {
1441       m_single_transparent_pad[k_history]->cd();
1442       TText dead_text;
1443       dead_text.SetTextColor(kBlue);
1444       dead_text.SetTextAlign(22);
1445       dead_text.SetTextSize(0.1);
1446       dead_text.SetTextAngle(45);
1447       // dead_text.DrawText(0.5, 0.5, "Dead Onlmon Server");
1448       ++num_dead;
1449       continue;
1450     }
1451     int N = log_hist->GetNbinsX();
1452     double w = log_hist->GetXaxis()->GetBinWidth(0);
1453 
1454     // Step through most recent 180 seconds of the histogram
1455     // if the rate is identically 0, say it is dead
1456     bool is_dead = true;
1457     int buff_index = log_hist->GetBinContent(N);
1458     for(double duration = 0; duration < 90; duration += w)
1459     {
1460       double rate = log_hist->GetBinContent(buff_index);
1461       if(0 < rate)
1462       {
1463         is_dead = false;
1464         break;
1465       }
1466 
1467       // N + 1 bin stores how many times the data has been wrapped
1468       // if it's not wrapped and we're at bin 0, break b/c we don't have the duration of data yet
1469       if(buff_index == 0 && (log_hist->GetBinContent(N + 1) == 0))
1470       {
1471         is_dead = false;
1472         break;
1473       }
1474 
1475       buff_index = (buff_index + N - 1) % N;
1476     }
1477 
1478     if(is_dead)
1479     {
1480       ++num_dead;
1481     }
1482 
1483     // Get the time frame of server relative to Unix Epoch
1484     // stored in bins 4 and 5 of EvtHist
1485     if(evt_hist->GetBinContent(4) < oldest)
1486     {
1487       oldest = evt_hist->GetBinContent(4); // SOR time relative to epoch
1488     }
1489     if(newest < evt_hist->GetBinContent(5))
1490     {
1491       newest = evt_hist->GetBinContent(5); // present or EOR time relative to epoch
1492     }
1493   }
1494 
1495   for(int i = 0; i < 8; ++i)
1496   {
1497     // Access client
1498     OnlMonClient* cl = OnlMonClient::instance();
1499 
1500     TH1I* evt_hist = dynamic_cast<TH1I*>(cl->getHisto(Form("INTTMON_%d", i), "InttEvtHist"));
1501     if(!evt_hist)
1502     {
1503       continue;
1504     }
1505 
1506     TH1* log_hist = cl->getHisto(Form("INTTMON_%d", i), "InttLogHist");
1507     if(!log_hist)
1508     {
1509       continue;
1510     }
1511 
1512     // Validate member histos
1513     int N = log_hist->GetNbinsX();
1514     double w = log_hist->GetXaxis()->GetBinWidth(0);
1515     std::string name = Form("intt_history_hist_%d", i);
1516     if (!m_hist_history[i])
1517     {
1518       m_hist_history[i] = new TH1D(
1519           name.c_str(), name.c_str(), //
1520           N, 0.0, w * N //
1521       );
1522       m_hist_history[i]->SetTitle(Form("Rate of BCO decoding;Most recent %.0lf seconds;Decoded BCOs / s", (double)(w * N)));
1523       m_hist_history[i]->SetFillStyle(4000); // Transparent
1524       m_hist_history[i]->SetLineColor(GetFeeColor(i));
1525       m_hist_history[i]->SetLineStyle(GetFeeStyle(i));
1526     }
1527     m_single_hist_pad[k_history]->cd();
1528 
1529     m_hist_history[i]->Reset();
1530     m_hist_history[i]->Draw("Same");
1531 
1532     // Fill
1533     if(w * N < newest - oldest)
1534     {
1535       // Draw it conventionally
1536       // Present/EOR is aligned on right edge
1537       int buff_index = log_hist->GetBinContent(N);
1538       for(int n = 0; n < N; ++n)
1539       {
1540         double rate = log_hist->GetBinContent(buff_index) / w;
1541         double time = (evt_hist->GetBinContent(5) - newest) + w * (N - n);
1542         int bin = m_hist_history[i]->FindBin(time);
1543 
1544         if(has_nan(rate))
1545         {
1546           continue;
1547         }
1548 
1549         m_hist_history[i]->SetBinContent(bin, rate);
1550         if(max < rate)
1551         {
1552           max = rate;
1553         }
1554 
1555         // N + 1 bin stores how many times the data has been wrapped
1556         // if it's not wrapped and we're at bin 0, break b/c we don't have the duration of data yet
1557         if(buff_index == 0 && (log_hist->GetBinContent(N + 1) == 0))
1558         {
1559           break;
1560         }
1561         buff_index = (buff_index + N - 1) % N;
1562       }
1563     }
1564     else
1565     {
1566       // I don't know why people want this but here it is
1567       // SOR is aligned with left edge
1568       int buff_index = log_hist->GetBinContent(N);
1569       for(int n = 0; n < N; ++n)
1570       {
1571         double rate = log_hist->GetBinContent(buff_index % N) / w;
1572         double time = evt_hist->GetBinContent(5) - oldest - w * n;
1573         int bin = m_hist_history[i]->FindBin(time);
1574 
1575         if(has_nan(rate))
1576         {
1577           continue;
1578         }
1579 
1580         m_hist_history[i]->SetBinContent(bin, rate);
1581         if(max < rate)
1582         {
1583           max = rate;
1584         }
1585 
1586         // N + 1 bin stores how many times the data has been wrapped
1587         // if it's not wrapped and we're at bin 0, break b/c we don't have the duration of data yet
1588         if(buff_index == 0 && (log_hist->GetBinContent(N + 1) == 0))
1589         {
1590           break;
1591         }
1592         buff_index = (buff_index + N - 1) % N;
1593       }
1594     }
1595   }
1596 
1597   m_single_transparent_pad[k_history]->Clear();
1598   if(0 < num_dead)
1599   {
1600     m_single_transparent_pad[k_history]->cd();
1601     TText dead_text;
1602     dead_text.SetTextColor(kRed);
1603     dead_text.SetTextAlign(22);
1604     dead_text.SetTextSize(0.06);
1605     // dead_text.SetTextAngle(45);
1606     dead_text.DrawText(0.5, 0.65, "Dead Felix Servers");
1607     dead_text.DrawText(0.5, 0.50, "Check server stats");
1608     dead_text.DrawText(0.5, 0.35, "If no dead OnlMon servers, restart run");
1609   }
1610 
1611   if(0 == max) // max was unset
1612   {
1613     max = 1;
1614   }
1615   else if(max < 0 || (max *= 1.2) < 0 || has_nan(max)) // max underflowed in the server or underflowed when mutliplying by 10
1616   {
1617     max = std::numeric_limits<int>::max();
1618   }
1619 
1620   for(int i = 0; i < 8; ++i)
1621   {
1622     if(!m_hist_history[i])
1623     {
1624       continue;
1625     }
1626     m_hist_history[i]->GetYaxis()->SetRangeUser(-0.2 * max,  1.2 * max);
1627   }
1628 
1629   // Draw Legend
1630   double lgnd_text_size = 0.08;
1631   double lgnd_box_width = 0.16;
1632   // double lgnd_box_height = 0.01;
1633 
1634   std::string name;
1635 
1636   m_lgnd_pad[k_history]->Clear();
1637   m_lgnd_pad[k_history]->cd();
1638 
1639   double x0, y0; //, x[4], y[4];
1640   for (int i = 0; i < 8; ++i)
1641   {
1642     x0 = 0.5 - lgnd_box_width;
1643     y0 = (2.0 * i + 1.0) / (2.0 * 8);
1644 
1645     TText lgnd_text;
1646     lgnd_text.SetTextAlign(12);
1647     lgnd_text.SetTextSize(lgnd_text_size);
1648     lgnd_text.SetTextColor(kBlack);
1649     lgnd_text.DrawText(x0 + 1.5 * lgnd_box_width, y0, Form("intt%01d", i));
1650 
1651     // x[0] = -1, x[1] = +1, x[2] = +1, x[3] = -1;
1652     // y[0] = -1, y[1] = -1, y[2] = +1, y[3] = +1;
1653     // for (int j = 0; j < 4; ++j)
1654     // {
1655     //   x[j] *= 0.5 * lgnd_box_width;
1656     //   x[j] += x0;
1657 
1658     //   y[j] *= 0.5 * lgnd_box_height;
1659     //   y[j] += y0;
1660     // }
1661 
1662     // TPolyLine box;
1663     // box.SetFillColor(GetFeeColor(i));
1664     // box.SetLineColor(kBlack);
1665     // box.SetLineWidth(1);
1666     // box.DrawPolyLine(4, x, y, "f");
1667     TLine line;
1668     line.SetLineColor(GetFeeColor(i));
1669     line.SetLineStyle(GetFeeStyle(i));
1670     line.SetLineWidth(3);
1671     line.DrawLine (
1672         x0 - 0.5 * lgnd_box_width, y0,
1673         x0 + 0.5 * lgnd_box_width, y0
1674     );
1675   }
1676 
1677   TC[k_history]->Update();
1678   TC[k_history]->Show();
1679   TC[k_history]->SetEditable(false);
1680 
1681   return 0;
1682 }
1683 
1684 //====== Timing Okay ======//
1685 
1686 int InttMonDraw::Draw_TimingOkay()
1687 {
1688   if (!gROOT->FindObject("InttTimingOkay"))
1689   {
1690     MakeCanvas("InttTimingOkay");
1691   }
1692 
1693   TC[k_timing_okay]->SetEditable(true);
1694   m_style->cd();
1695   if(DrawDispPad_Generic(k_timing_okay, TC[k_timing_okay]->GetTitle()) == -1)
1696   {
1697     return -1;
1698   }
1699 
1700   // for getting the modal peak position by felix server
1701   // (this map has only one key if the servers are aligned)
1702   std::map<int, int> server_peak_positions;
1703   for (int i = 0; i < 8; ++i)
1704   {
1705     OnlMonClient* cl = OnlMonClient::instance();
1706     TH1* bco_hist = cl->getHisto(Form("INTTMON_%d", i), "InttBcoHist");
1707     if (!bco_hist)
1708     {
1709       // continue;
1710       m_single_transparent_pad[k_timing_okay]->cd();
1711       TText dead_text;
1712       dead_text.SetTextColor(kBlue);
1713       dead_text.SetTextAlign(22);
1714       dead_text.SetTextSize(0.1);
1715       dead_text.SetTextAngle(45);
1716       dead_text.DrawText(0.5, 0.5, "Dead OnlMon Server");
1717       return 1;
1718     }
1719 
1720     // for getting the modal peak position by felix channel
1721     // (this map has only one key if the felix channels are aligned)
1722     std::map<int, int> fee_peak_positions;
1723 
1724     for (int fee = 0; fee < NFEES; ++fee)
1725     {
1726       // for each felix channel, get its peak
1727       int max_count = -1;
1728       int fee_peak = -1;
1729       for (int bco = 0; bco < NBCOS; ++bco)
1730       {
1731         int bincont = bco_hist->GetBinContent(bco_hist->GetBin(1, fee * NBCOS + bco + 1));
1732         if (bincont < max_count) continue;
1733         max_count = bincont;
1734         fee_peak = bco;
1735       }
1736 
1737       // increment the count of this position
1738       fee_peak_positions[fee_peak]++;
1739       // std::cout
1740       //   << "  server: " << i
1741       //   << "  fee: " << fee
1742       //   << "  peak position: " << max_bin
1743       //   << std::endl;
1744     }
1745 
1746     // go back through the map of [peak_position, count] for this server
1747     // and figure out what the mode of the fee_peak_positions distribution is
1748     int max_count = -1;
1749     int server_peak = -1;
1750     for (auto const& [peak_position, count] : fee_peak_positions)
1751     {
1752       if (count < max_count) continue;
1753       max_count = count;
1754       server_peak = peak_position;
1755     }
1756     // std::cout
1757     //   << " server: " << i
1758     //   << " peak position: " << server_peak
1759     //   << std::endl;
1760     server_peak_positions[server_peak]++;
1761   }
1762 
1763   // should only be 1 unique peak/key for all felix servers if their timing is aligned
1764   // for (auto const& [peak_position, count] : server_peak_positions)
1765   // {
1766   //   std::cout
1767   //     << " peak position: " << peak_position
1768   //     << " number of servers with this peak: " << count
1769   //     << std::endl;
1770   // }
1771   bool timing_okay = (server_peak_positions.size() == 1);
1772 
1773   m_timing_okay_pad[k_timing_okay]->cd();
1774   TText timing_text;
1775   timing_text.SetTextColor(timing_okay ? kGreen : kRed);
1776   timing_text.SetTextAlign(22);
1777   timing_text.SetTextSize(0.1);
1778   timing_text.DrawText(0.5, 0.5, timing_okay ? "Timing Okay" : "Timing NOT Okay");
1779 
1780   TC[k_timing_okay]->Update();
1781   TC[k_timing_okay]->Show();
1782   TC[k_timing_okay]->SetEditable(false);
1783 
1784   return 0;
1785 }