Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:21:02

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