OnlinePlotter.cpp
Go to the documentation of this file.
1 //File: OnlinePlotter.cpp
2 //Brief: An "algorithm" class for creating online monitoring plots in a way that works
3 // either with or without LArSoft. Should start out by plotting diagnostics from
4 // perl plotting code, then branch out as we identify more pathologies.
5 //Author: Andrew Olivier aolivier@ur.rochester.edu
6 
7 #ifndef CRT_ONLINEPLOTTER_CPP
8 #define CRT_ONLINEPLOTTER_CPP
9 
10 //crt-core includes
12 
13 //ROOT includes
14 #include "TH2D.h"
15 #include "TProfile.h"
16 #include "TProfile2D.h"
17 
18 //c++ includes
19 #include <unordered_map>
20 #include <string>
21 #include <iostream> //TODO: Remove me
22 
23 namespace CRT
24 {
25  template <class TFS>
26  //TFS is an object that defines a function like:
27  //
28  //template <class HIST, class ARGS...> HIST* make(ARGS... args)
29  //
30  //Looks like ART's TFileService.
32  {
33  public:
34 
35  OnlinePlotter(TFS& tfs, const double tickLength = 16): fFileService(tfs), fWholeJobPlots(tfs->mkdir("PerJob")),
36  fRunStartTime(std::numeric_limits<uint64_t>::max()),
37  fRunStopTime(0), fStartTotalTime(std::numeric_limits<uint64_t>::max()),
38  fRunCounter(0),
39  fModuleToUSB ({{0, 13},
40  {1, 13},
41  {2, 13},
42  {3, 13},
43  {4, 13},
44  {5, 13},
45  {6, 13},
46  {7, 13},
47  {8, 14},
48  {9, 14},
49  {10, 14},
50  {11, 14},
51  {12, 14},
52  {13, 14},
53  {14, 14},
54  {15, 14},
55  {16, 3},
56  {17, 3},
57  {18, 3},
58  {19, 3},
59  {20, 22},
60  {21, 22},
61  {22, 22},
62  {23, 22},
63  {24, 22},
64  {25, 22},
65  {26, 22},
66  {27, 22},
67  {28, 3},
68  {29, 3},
69  {30, 3},
70  {31, 3}}), fClockTicksToNs(tickLength)
71  {
72  //TODO: Get unordered_mapping from module to USB from some parameter passed to constructor
73  //TODO: Get tick length from parameter passed to constructor
74  }
75 
76  virtual ~OnlinePlotter()
77  {
78  const auto deltaT = (fRunStopTime - fStartTotalTime)*fClockTicksToNs*1.e-9;
79  if(deltaT > 0)
80  {
81  fWholeJobPlots.fMeanRate->Scale(1./deltaT);
82  fWholeJobPlots.fMeanRatePerBoard->Scale(1./deltaT);
83  }
84  }
85 
86  void ReactEndRun(const std::string& /*fileName*/)
87  {
88  //Scale all rate histograms here with total elapsed time in run
89  const auto deltaT = (fRunStopTime-fRunStartTime)*1e-9*fClockTicksToNs; //Convert ticks from timestamp into seconds
90  //TODO: Use tick length from constructor
91  const auto totalDeltaTInSeconds = (fRunStopTime - fStartTotalTime)*fClockTicksToNs*1.e-9; //TODO: replace with tick length from constructor
92  if(deltaT > 0)
93  {
94  //TODO: Remove cout for LArSoft compatibility
95  std::cout << "Elapsed time for this run is " << deltaT << " seconds. Total elapsed time is " << totalDeltaTInSeconds << " seconds.\n";
96  std::cout << "Beginning of all time was " << (uint64_t)(fStartTotalTime*fClockTicksToNs*1.e-9) << ", beginning of run was "
97  << (uint64_t)(fRunStartTime*fClockTicksToNs*1.e-9) << ", and end of run was " << (uint64_t)(fRunStopTime*fClockTicksToNs*1.e-9) << "\n";
98  const auto timeInv = 1./deltaT;
99  fCurrentRunPlots->fMeanRate->Scale(timeInv);
100  fCurrentRunPlots->fMeanRatePerBoard->Scale(timeInv);
101  }
102 
103  //Fill histograms that profile over board or USB number
104  const auto nChannels = fCurrentRunPlots->fMeanRate->GetXaxis()->GetNbins();
105  const auto nModules = fCurrentRunPlots->fMeanRate->GetYaxis()->GetNbins();
106  std::unordered_map<unsigned int, size_t> usbToHits; //USB bins of number of hits
107  for(auto channel = 0; channel < nChannels; ++channel)
108  {
109  for(auto module = 0; module < nModules; ++module)
110  {
111  const auto count = fCurrentRunPlots->fMeanRate->GetBinContent(fCurrentRunPlots->fMeanRate->GetBin(channel, module));
112 
113  const auto foundUSB = fModuleToUSB.find(module);
114  if(foundUSB != fModuleToUSB.end())
115  {
116  const auto usb = foundUSB->second;
117  auto found = fUSBToForeverPlots.find(usb);
118  if(found == fUSBToForeverPlots.end())
119  {
120  found = fUSBToForeverPlots.emplace(usb, fFileService->mkdir("USB"+std::to_string(usb))).first;
121  }
122 
123  auto& forever = found->second;
124  usbToHits[usb] += count;
125  forever.fMeanADC->Fill(totalDeltaTInSeconds,
126  fCurrentRunPlots->fMeanADC->GetBinContent(fCurrentRunPlots->fMeanADC->GetBin(channel, module)));
127  } //If found a USB for this module
128  } //For each module in mean rate/ADC plots
129  } //For each channel in mean rate/ADC plots
130  if(deltaT > 0)
131  {
132  for(const auto bin: usbToHits)
133  {
134  const auto found = fUSBToForeverPlots.find(bin.first);
135  if(found != fUSBToForeverPlots.end()) found->second.fMeanRate->Fill(totalDeltaTInSeconds, bin.second);
136  }
137  }
138  }
139 
140  void ReactBeginRun(const std::string& /*fileName*/)
141  {
142  //const uint64_t totalDeltaTInSeconds = (fRunStopTime - fStartTotalTime)*fClockTicksToNs*1.e-9; //TODO: replace with tick length from constructor
143  fCurrentRunPlots.reset(new PerRunPlots(fFileService->mkdir("Run"+std::to_string(++fRunCounter))));
144  //TODO: The above directory name is not guaranteed to be unique, and art::TFileDirectory's only mechanism for
145  // reacting to that situation seems to be catching a cet::exception from whenver the internal cd() method is
146  // called. I need to either find a way to deal with this problem or stop making plots per-file.
147  // One way to deal with this is by going back to "run number" directory labels.
148 
150  fRunStopTime = 0;
151  }
152 
153  void AnalyzeEvent(const std::vector<CRT::Trigger>& triggers) //Make plots from CRT::Triggers
154  {
155  for(const auto& trigger: triggers)
156  {
157  const auto timestamp = trigger.Timestamp();
158  if(timestamp > 1e16)
159  {
160  //Update time bounds based on this timestamp
161  if(timestamp < fRunStartTime)
162  {
163  //std::cout << "fRunStartTime=" << fRunStartTime << " is >= " << timestamp << ", so setting fRunStartTime.\n";
164  fRunStartTime = timestamp;
165  }
166  if(timestamp > fRunStopTime)
167  {
168  //std::cout << "fRunStopTime=" << fRunStopTime << " is <= " << timestamp << ", so setting fRunStopTime.\n";
169  fRunStopTime = timestamp;
170  }
171  if(timestamp < fStartTotalTime)
172  {
173  //std::cout << "fStartTotalTime=" << fStartTotalTime << " is >= " << timestamp << ", so setting fStartTotalTime.\n";
174  fStartTotalTime = timestamp;
175  }
176 
177  const auto module = trigger.Channel();
178  const auto& hits = trigger.Hits();
179  for(const auto& hit: hits)
180  {
181  const auto channel = hit.Channel();
182  fCurrentRunPlots->fMeanRate->Fill(channel, module);
183  fCurrentRunPlots->fMeanADC->Fill(channel, module, hit.ADC());
184  fCurrentRunPlots->fMeanADCPerBoard->Fill(module, hit.ADC());
185 
186  fWholeJobPlots.fMeanRate->Fill(channel, module);
187  fWholeJobPlots.fMeanADC->Fill(channel, module, hit.ADC());
188  fWholeJobPlots.fMeanADCPerBoard->Fill(module, hit.ADC());
189  }
190  fCurrentRunPlots->fMeanRatePerBoard->Fill(module);
191  fWholeJobPlots.fMeanRatePerBoard->Fill(module);
192  } //If UNIX timestamp is not 0
193  }
194  }
195 
196  private:
197  //Keep track of the current run number
198  size_t fRunNum;
199 
200  TFS fFileService; //Handle to tool for writing out files
201  using DIRECTORY=decltype(fFileService->mkdir("test"));
202 
203  //Plots I want for each USB board for each Run
204  struct PerRunPlots
205  {
207  {
208  fMeanRate = dir.template make<TH2D>("MeanRate", "Mean Rates;Channel;Module;Rate", 64, 0, 64, 32, 0, 32);
209  fMeanRate->SetStats(false);
210 
211  fMeanADC = dir.template make<TProfile2D>("MeanADC", "Mean ADC Values;Channel;Module;Rate [Hz]", 64, 0, 64, 32, 0, 32, 0., 4096);
212  fMeanADC->SetStats(false);
213 
214  fMeanRatePerBoard = dir.template make<TH1D>("MeanRateBoard", "Mean Rate per Board;Board;Rate [Hz]",
215  32, 0, 32);
216  fMeanADCPerBoard = dir.template make<TProfile>("MeanADCBoard", "Mean ADC Value per Board;Board;ADC",
217  32, 0, 32);
218  }
219 
221  {
222  fMeanRate->SetMinimum(0);
223  //fMeanRate->SetMaximum(60); //TODO: Maybe tune this one day. When using the board reader, it really depends
224  // on the trigger rate.
225  }
226 
227  DIRECTORY fDir; //Directory for the current run where these plots are kept
228  TH2D* fMeanRate; //Plot of mean hit rate per channel
229  TProfile2D* fMeanADC; //Plot of mean ADC per channel
230  TH1D* fMeanRatePerBoard; //Plot of mean rate for each board
231  TProfile* fMeanADCPerBoard; //Plot of mean ADC per board
232  };
233 
234  std::unique_ptr<PerRunPlots> fCurrentRunPlots; //Per run plots for the current run
235  PerRunPlots fWholeJobPlots; //Fill some PerRunPlots with the whole job
236  uint64_t fRunStartTime; //Earliest timestamp in run
237  uint64_t fRunStopTime; //Latest timestamp in run
238  uint64_t fStartTotalTime; //Earliest timestamp stamp in entire job
239  size_t fRunCounter; //Number of times ReactBeginRun() has been called so far. Used
240  //to generate unique TDirectory names.
241 
242  //Plots I want for each USB board integrated over all(?) Runs
244  {
246  {
247  fMeanRate = dir.template make<TH1D>("MeanRateHistory", "Mean Rate History;Time [s];Rate [Hz]",
248  1000, 0, 3600);
249  fMeanADC = dir.template make<TProfile>("MeanADCHistory", "Mean ADC History;Time [s];ADC",
250  1000, 0, 3600);
251  }
252 
253  DIRECTORY fDir; //Directory for this USB's overall plots
254  TH1D* fMeanRate; //Mean hit rate in time
255  TProfile* fMeanADC; //Mean hit ADC in time
256  };
257 
258  std::unordered_map<unsigned int, ForeverPlots> fUSBToForeverPlots; //Mapping from USB number to ForeverPlots.
259 
260  //Configuration parameters
261  std::unordered_map<unsigned int, unsigned int> fModuleToUSB; //Mapping from module number to USB
262  const double fClockTicksToNs; //Length of a clock tick in nanoseconds
263  };
264 }
265 
266 #endif //CRT_ONLINEPLOTTER_CPP
OnlinePlotter(TFS &tfs, const double tickLength=16)
void ReactEndRun(const std::string &)
def mkdir(path, mode=0o777)
std::unordered_map< unsigned int, ForeverPlots > fUSBToForeverPlots
std::string string
Definition: nybbler.cc:12
const double fClockTicksToNs
STL namespace.
uint8_t channel
Definition: CRTFragment.hh:201
void ReactBeginRun(const std::string &)
string dir
const double e
void AnalyzeEvent(const std::vector< CRT::Trigger > &triggers)
static int max(int a, int b)
Detector simulation of raw signals on wires.
std::unordered_map< unsigned int, unsigned int > fModuleToUSB
std::unique_ptr< PerRunPlots > fCurrentRunPlots
virtual ~OnlinePlotter()
QTextStream & bin(QTextStream &s)
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
PerRunPlots fWholeJobPlots