AdcTickModViewer_tool.cc
Go to the documentation of this file.
1 // AdcTickModViewer_tool.cc
2 
3 #include "AdcTickModViewer.h"
10 #include <iostream>
11 #include <fstream>
12 #include <sstream>
13 #include <iomanip>
14 #include "TDirectory.h"
15 #include "TFile.h"
16 #include "TH1F.h"
17 #include "TF1.h"
18 #include "TTree.h"
19 #include "TROOT.h"
20 #include "TError.h"
21 #include "TGraph.h"
22 
23 using std::string;
24 using std::cout;
25 using std::endl;
26 using std::ofstream;
27 using std::ostream;
28 using std::ostringstream;
29 using std::setw;
30 using std::fixed;
31 using std::setprecision;
32 using std::vector;
33 
36 
37 
38 //**********************************************************************
39 // Private definitions.
40 //**********************************************************************
41 
42 namespace {
43 
44 void copyAcd(const AdcChannelData& acdin, AdcChannelData& acdout) {
45  acdout.setEventInfo(acdin.getEventInfoPtr());
46  acdout.setChannelInfo(acdin.getChannelInfoPtr());
47  acdout.pedestal = acdin.pedestal;
48 }
49 
50 // Class to hold the adc counts for a tickmod.
51 class TickModData {
52 public:
54  AdcCount adcMin = 0;
55  AdcCount adcMax = 0;
56  long adcSum = 0;
57  bool dbg = false;
58  void add(AdcCount adc) {
59  if ( data.size() ) {
60  if ( adc < adcMin ) adcMin = adc;
61  if ( adc > adcMax ) adcMax = adc;
62  } else {
63  adcMin = adc;
64  adcMax = adc;
65  }
66  data.push_back(adc);
67  adcSum += adc;
68  if ( dbg ) cout << "... " << adc << " (" << adcMin << ", " << adcMax << ")" << endl;
69  }
70  AdcCount min() const { return adcMin; }
71  AdcCount max() const { return adcMax; }
72  double mean() const {
73  return double(adcSum)/double(data.size());
74  }
75 };
76 
77 } // end unnamed namespace
78 
79 //**********************************************************************
80 // Class methods.
81 //**********************************************************************
82 
84 : m_LogLevel(ps.get<int>("LogLevel")),
85  m_TickModPeriod(ps.get<Index>("TickModPeriod")),
86  m_TimeOffsetTool(ps.get<Name>("TimeOffsetTool")),
87  m_FitSigmaMin(ps.get<float>("FitSigmaMin")),
88  m_FitSigmaMax(ps.get<float>("FitSigmaMax")),
89  m_HistName(ps.get<string>("HistName")),
90  m_HistTitle(ps.get<string>("HistTitle")),
91  m_HistChannelCount(ps.get<Index>("HistChannelCount")),
92  m_AllPlotFileName(ps.get<string>("AllPlotFileName")),
93  m_MinPlotFileName(ps.get<string>("MinPlotFileName")),
94  m_MaxPlotFileName(ps.get<string>("MaxPlotFileName")),
95  m_PhasePlotFileName(ps.get<string>("PhasePlotFileName")),
96  m_PhaseVariable(ps.get<string>("PhaseVariable")),
97  m_RootFileName(ps.get<string>("RootFileName")),
98  m_TreeFileName(ps.get<string>("TreeFileName")),
99  m_PlotChannels(ps.get<IndexVector>("PlotChannels")),
100  m_PlotSizeX(ps.get<Index>("PlotSizeX")),
101  m_PlotSizeY(ps.get<Index>("PlotSizeY")),
102  m_PlotShowFit(ps.get<Index>("PlotShowFit")),
103  m_PlotSplitX(ps.get<Index>("PlotSplitX")),
104  m_PlotSplitY(ps.get<Index>("PlotSplitY")),
105  m_PlotFrequency(ps.get<Index>("PlotFrequency")),
106  m_PhaseGrouping(ps.get<Name>("PhaseGrouping")),
107  m_PhasePlotSizeX(ps.get<Index>("PhasePlotSizeX")),
108  m_PhasePlotSizeY(ps.get<Index>("PhasePlotSizeY")),
109  m_PhasePlotSplitX(ps.get<Index>("PhasePlotSplitX")),
110  m_PhasePlotSplitY(ps.get<Index>("PhasePlotSplitY")),
111  m_tickOffsetTool(nullptr),
112  m_varPhase(m_PhaseVariable == "phase"),
113  m_varEvent(m_PhaseVariable == "event"),
114  m_varTick0(m_PhaseVariable == "tick0"),
115  m_varNchan(m_PhaseVariable == "nchan"),
116  m_plotAll(m_AllPlotFileName.size()),
117  m_plotMin(m_MinPlotFileName.size()),
118  m_plotMax(m_MaxPlotFileName.size()),
119  m_plotAny(m_plotAll || m_plotMin || m_plotMax),
120  m_plotPhase(m_PhasePlotFileName.size()),
121  m_makeTree(m_TreeFileName.size()),
122  m_groupByChannel(m_PhaseGrouping == "channel"),
123  m_groupByFemb(m_PhaseGrouping == "femb"),
124  m_state(new State)
125 {
126  const string myname = "AdcTickModViewer::ctor: ";
128  string stringBuilder = "adcStringBuilder";
129  m_adcStringBuilder = ptm->getShared<AdcChannelStringTool>(stringBuilder);
130  if ( m_adcStringBuilder == nullptr ) {
131  cout << myname << "WARNING: AdcChannelStringTool not found: " << stringBuilder << endl;
132  }
133  string tname = m_TimeOffsetTool;
134  if ( tname.size() ) {
136  if ( m_tickOffsetTool == nullptr ) {
137  cout << myname << "WARNING: Requested TimeOffsetTool not found: " << tname << endl;
138  }
139  }
140  if ( m_plotPhase ) {
141  if ( ! m_groupByChannel && ! m_groupByFemb ) {
142  cout << myname << "ERROR: Invalid phase grouping: " << m_PhaseGrouping << endl;
143  m_plotPhase = false;
144  }
145  if ( !m_varPhase && !m_varEvent && !m_varTick0 && !m_varNchan ) {
146  cout << myname << "ERROR: Invalid phase variable: " << m_PhaseVariable << endl;
147  m_plotPhase = false;
148  }
149  }
150  if ( m_LogLevel >= 1 ) {
151  cout << myname << "Configuration parameters:" << endl;
152  cout << myname << " LogLevel: " << m_LogLevel << endl;
153  cout << myname << " TickModPeriod: " << m_TickModPeriod << endl;
154  cout << myname << " TimeOffsetTool: " << m_TimeOffsetTool << endl;
155  cout << myname << " FitSigmaMin: " << m_FitSigmaMin << endl;
156  cout << myname << " FitSigmaMax: " << m_FitSigmaMax << endl;
157  cout << myname << " HistName: " << m_HistName << endl;
158  cout << myname << " HistTitle: " << m_HistTitle << endl;
159  cout << myname << " HistChannelCount: " << m_HistChannelCount << endl;
160  cout << myname << " AllPlotFileName: " << m_AllPlotFileName << endl;
161  cout << myname << " MinPlotFileName: " << m_MinPlotFileName << endl;
162  cout << myname << " MaxPlotFileName: " << m_MaxPlotFileName << endl;
163  cout << myname << " PhasePlotFileName: " << m_PhasePlotFileName << endl;
164  cout << myname << " PhaseVariable: " << m_PhaseVariable << endl;
165  cout << myname << " PhaseGrouping: " << m_PhaseGrouping << endl;
166  cout << myname << " RootFileName: " << m_RootFileName << endl;
167  cout << myname << " TreeFileName: " << m_TreeFileName << endl;
168  cout << myname << " PlotChannels: [";
169  bool first = true;
170  for ( Index icha : m_PlotChannels ) {
171  if ( !first ) cout << ", ";
172  else first = false;
173  cout << icha;
174  }
175  cout << "]" << endl;
176  cout << myname << " PlotSizeX: " << m_PlotSizeX << endl;
177  cout << myname << " PlotSizeY: " << m_PlotSizeY << endl;
178  cout << myname << " PlotShowFit: " << m_PlotShowFit << endl;
179  cout << myname << " PlotSplitX: " << m_PlotSplitX << endl;
180  cout << myname << " PlotSplitY: " << m_PlotSplitY << endl;
181  cout << myname << " PlotFrequency: " << m_PlotFrequency << endl;
182  cout << myname << " PhasePlotSizeX: " << m_PhasePlotSizeX << endl;
183  cout << myname << " PhasePlotSizeY: " << m_PhasePlotSizeY << endl;
184  cout << myname << " PhasePlotSplitX: " << m_PhasePlotSplitX << endl;
185  cout << myname << " PhasePlotSplitY: " << m_PhasePlotSplitY << endl;
186  cout << myname << " NTimingPhase: " << m_NTimingPhase << endl;
187  }
188  if ( m_LogLevel >=4 ) {
189  cout << myname << "INFO: Checking state." << endl;
190  cout << myname << "INFO: Full hist map size: " << state().ChannelTickModFullHists.size() << endl;
191  cout << myname << "INFO: Proc hist map size: " << state().ChannelTickModProcHists.size() << endl;
192  }
193 }
194 
195 //**********************************************************************
196 
198  const string myname = "AdcTickModViewer::dtor: ";
199  if ( m_LogLevel >= 1 ) cout << myname << "Closing." << endl;
200  Index nplot = 0;
201  processAccumulation(nplot);
202  if ( m_LogLevel >= 1 ) cout << myname << "Plot count: " << nplot << endl;
203  if ( m_LogLevel >= 1 ) cout << myname << "TM initial hist count: " << state().tickModHistogramInitialCount << endl;
204  if ( m_LogLevel >= 1 ) cout << myname << "TM rebuild hist count: " << state().tickModHistogramRebuildCount << endl;
205  if ( m_LogLevel >= 1 ) cout << myname << "Plot count: " << nplot << endl;
206 }
207 
208 //**********************************************************************
209 
211  DataMap ret;
212  if ( acds.size() == 0 ) return ret.setStatus(0);
213  // Save channel count.
214  //Index eventID = acds.begin()->second.event;
215  //state().eventIDs.push_back(eventID);
216  //state().nchans.push_back(acds.size());
217  return AdcChannelTool::viewMap(acds);
218 }
219 
220 //**********************************************************************
221 
223  const string myname = "AdcTickModViewer::view: ";
224  DataMap res;
225  Index icha = acd.channel();
226  if ( m_LogLevel >= 3 ) cout << myname << "Processing channel " << icha << endl;
227  setChannelData(acd);
228  HistVector& tmhsFull = state().ChannelTickModFullHists[icha];
229  Index ntkm = m_TickModPeriod;
230  if ( tmhsFull.size() == 0 ) tmhsFull.resize(ntkm, nullptr);
231  Index eventID = acd.event();
232  Index ndigi = 0;
233  if ( m_varNchan ) {
234  if ( acd.hasMetadata("ndigi") ) {
235  ndigi = acd.getMetadata("ndigi");
236  } else {
237  cout << myname << "WARNING: Metadata not found in ADC data: " << "digi" << endl;
238  }
239  }
240  double tick0 = 0.0; // Tick number in this run/job
241  Index itkm0 = 0;
242  Index timingPhase = 0;
243  if ( m_tickOffsetTool != nullptr ) {
245  dat.run = acd.run();
246  dat.subrun = acd.subRun();
247  dat.event = acd.event();
248  dat.channel = acd.channel();
249  dat.triggerClock = acd.triggerClock();
251  if ( ! off.isValid() ) {
252  cout << myname << "Error finding tick offset: " << off.status << endl;
253  return res.setStatus(1);
254  }
255  if ( off.unit != "tick" ) {
256  cout << myname << "Time offset has wrong unit: " << off.unit << endl;
257  return res.setStatus(2);
258  }
259  long toff = off.value;
260  if ( ! state().haveTick0Job ) {
261  state().tick0Job = toff;
262  state().haveTick0Job = true;
263  }
264  tick0 = toff - state().tick0Job;
265  while ( toff < 0.0 ) toff += m_TickModPeriod;
266  itkm0 = toff % m_TickModPeriod;
267  if ( m_LogLevel >= 3 ) cout << myname << " Tick0: " << tick0 << endl;
268  if ( m_LogLevel >= 3 ) cout << myname << " Tickmod0: " << itkm0 << endl;
269  // Get timing phase.
270  if ( m_NTimingPhase ) {
271  double delta = 0.01/m_NTimingPhase;
272  timingPhase = m_NTimingPhase*(off.rem + delta);
273  if ( m_LogLevel >= 3 ) cout << myname << " Timing phase: " << timingPhase << endl;
274  }
275  }
276  // Set the event variables, the first time an event ID is encountered.
277  if ( state().eventIDs.size() == 0 || state().eventIDs.back() != eventID ) {
278  state().eventIDs.push_back(eventID);
279  state().nchans.push_back(ndigi);
280  state().tick0s.push_back(tick0);
281  if ( m_LogLevel >= 3 ) cout << myname << "Creating event entry: EventID=" << eventID
282  << ", ndigi=" << ndigi << ", tick0=" << std::fixed << tick0 << endl;
283  }
284  // Process each tickmod for this channel.
285  FloatVector sigs(ntkm, 0.0);
286  Index itkmMax = 0;
287  float sigMax = -1.e20;
288  FloatVector sigMeans(ntkm, 0.0);
289  for ( Index itkm=0; itkm<ntkm; ++itkm ) {
290  float& sig = sigMeans[itkm];
291  processChannelTickMod(acd, itkm0, itkm, sig);
292  if ( sig > sigMax || itkm == 0 ) {
293  itkmMax = itkm;
294  sigMax = sig;
295  }
296  }
297  // Find and record the tickmod position of the signal peak.
298  // The peak position is found with three-point interpolation.
299  if ( true ) {
300  FloatVVector& mtmsForAllPhases = state().MaxTickMods[icha];
301  Index ivar = timingPhase;
302  if ( m_varPhase ) {
303  if ( mtmsForAllPhases.size() < m_NTimingPhase ) mtmsForAllPhases.resize(m_NTimingPhase);
304  } else {
305  ivar = state().eventIDs.size() - 1; // For now, assume no overlap in event processing.
306  if ( mtmsForAllPhases.size() < ivar+1 ) mtmsForAllPhases.resize(ivar+1);
307  }
308  FloatVector& mtms = mtmsForAllPhases[ivar];
309  float ym = itkmMax > 0 ? sigMeans[itkmMax-1] : sigMeans[ntkm-1];
310  float y0 = sigMeans[itkmMax];
311  float yp = itkmMax+1 < ntkm ? sigMeans[itkmMax+1] : sigMeans[0];
312  float den = 2.0*y0 - yp - ym;
313  if ( den <= 0.0 ) {
314  cout << myname << "WARNING: " << "Peak not found for channel " << icha << endl;
315  cout << myname << "itkmMax: " << itkmMax << endl;
316  cout << myname << "sigs: " << ym << ", " << y0 << ", " << yp << endl;
317  } else {
318  float xrem = 0.5*(yp - ym)/den;
319  float itkmPeak = itkmMax + xrem;
320 //cout << "XXX: " << itkmMax << ": (" << ym << ", " << y0 << ", " << yp << "): " << xrem << ", " << itkmPeak << endl;
321  mtms.push_back(itkmPeak);
322  }
323  }
324  // If requested, make the plots of accumulated data for this channel.
325  Index nplot = 0;
326  if ( m_PlotFrequency ) {
327  processAccumulation(nplot);
329  if ( ctmprocs.find(icha) == ctmprocs.end() ) {
330  static HistVector empty;
331  res.setHistVector("tmHists", empty);
332  } else {
333  res.setHistVector("tmHists", ctmprocs[icha]);
334  }
335  }
336  res.setHistVector("tmHists", tmhsFull); // Passing out hist that will be updated!
337  res.setInt("tmCount", ntkm);
338  return res;
339 }
340 
341 //**********************************************************************
342 
344  const string myname = "AdcTickModViewer::setChannelData: ";
345  Index icha = acd.channel();
346  if ( icha == AdcChannelData::badIndex() ) {
347  cout << myname << "WARNING: Invalid channel index." << endl;
348  icha = 0;
349  }
350  // Find the index of the variable that provides the grouping
351  // for phase plots.
353  if ( m_groupByChannel ) igrp = icha;
354  if ( m_groupByFemb ) igrp = acd.fembID();
355  if ( igrp == AdcChannelData::badIndex() ) {
356  cout << myname << "WARNING: Invalid phase channel grouping: " << m_PhaseGrouping << endl;
357  }
358  state().channel = icha;
359  // First call with this channel, we copy the channel data and record
360  // the channel-grouping mappings.
361  if ( state().acdMap.find(icha) == state().acdMap.end() ) {
362  if ( m_LogLevel >= 3 ) {
363  cout << myname << "Adding ADC channel state for channel " << icha << endl;
364  }
365  AdcChannelData& newacd = state().acdMap[icha];
366  copyAcd(acd, newacd);
367  state().phaseIndexMap[icha] = igrp;
368  state().phaseChannels[igrp].push_back(icha);
369  }
370 }
371 
372 //**********************************************************************
373 
375  const string myname = "AdcTickModViewer::setChannel: ";
376  if ( icha == AdcChannelData::badIndex() ) {
377  cout << myname << "ERROR: Invalid channel index." << endl;
378  icha = 0;
379  }
380  if ( state().acdMap.find(icha) == state().acdMap.end() ) {
381  cout << myname << "ERROR: There is no description for channel " << icha << endl;
382  state().currentAcd.clear();
383  } else {
384  copyAcd(state().acdMap[icha], state().currentAcd);
385  }
386  state().channel = icha;
387  return icha;
388 }
389 
390 //**********************************************************************
391 
393  const string myname = "AdcTickModViewer::getChannelIndex: ";
395  state().currentAcd.clear();
396 }
397 
398 //**********************************************************************
399 
401  const string myname = "AdcTickModViewer::getChannelIndex: ";
402  Index icha = state().channel;
403  if ( icha == AdcChannelData::badIndex() ) {
404  cout << myname << "ERROR: Channel index requested before being set." << endl;
405  return setChannel(0);
406  }
407  return icha;
408 }
409 
410 //**********************************************************************
411 
412 Name AdcTickModViewer::nameReplace(Name nameIn, const AdcChannelData& acd, Index itkm) const {
413  const string myname = "AdcTickModViewer::nameReplace: ";
414  DataMap dm;
415  string nameOut = m_adcStringBuilder->build(acd, dm, nameIn);
416  string stkm = std::to_string(itkm);
417  string::size_type stkm0Len = std::to_string(m_TickModPeriod-1).size();
418  string stkm0 = stkm;
419  while ( stkm0.size() < stkm0Len ) stkm0 = "0" + stkm0;
420  StringManipulator sman(nameOut, false);
421  sman.replace("%TICKMOD%", stkm);
422  sman.replace("%0TICKMOD%", stkm0);
423  return nameOut;
424 }
425 
426 //**********************************************************************
427 
428 int
429 AdcTickModViewer::processChannelTickMod(const AdcChannelData& acd, Index itkm0, Index itkm, float& sigMean) const {
430  const string myname = "AdcTickModViewer::processChannelTickMod: ";
431  const AdcCount border = 20;
432  const AdcCount adcLim = 4096;
433  DataMap res;
434  Index nsam = acd.raw.size();
435  if ( nsam == 0 ) {
436  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: Raw data is empty." << endl;
437  return 1;
438  }
439  // Extract the data for this tickmod.
440  Index period = m_TickModPeriod;
441  TickModData adcData;
442  Index isam0 = (itkm + period - itkm0) % period;
443  for ( Index isam=isam0; isam<nsam; isam+=period ) adcData.add(acd.raw[isam]);
444  // Fetch the histogram pointer.
445  Index icha = getChannelIndex();
446  HistPtr& ph = state().ChannelTickModFullHists[icha][itkm];
447  bool haveHist(ph);
448  // Check if we need new histogram. I.e. if not present or insufficient range.
449  bool needHist = ! haveHist;
450  if ( ! needHist ) {
451  AdcCount hstMin = ph->GetXaxis()->GetXmin() + 0.001;
452  AdcCount hstMax = ph->GetXaxis()->GetXmax() + -0.999;
453  needHist |= adcData.min() < hstMin;
454  needHist |= adcData.max() > hstMax;
455  }
456  // If needed, create histogram.
457  if ( needHist ) {
458  string hname = nameReplace(m_HistName, acd, itkm);
459  string htitl = nameReplace(m_HistTitle, acd, itkm);
460  htitl += "; ADC count; # samples";
461  AdcCount adcMin = adcData.min() < 2*border ? 0.0 : adcData.min() - border;
462  AdcCount adcMax = (adcData.max() + 2*border > adcLim) ? adcLim : (adcData.max() + border);
463  if ( haveHist ) {
464  AdcCount hstMin = ph->GetXaxis()->GetXmin() + 0.001;
465  AdcCount hstMax = ph->GetXaxis()->GetXmax() + -0.999;
466  if ( hstMin < adcMin ) adcMin = hstMin;
467  if ( hstMax > adcMax ) adcMax = hstMax;
468  }
469  float xmin = adcMin;
470  float xmax = adcMax + 1.0;
471  int nbin = xmax - xmin + 0.001;
472  HistPtr phold = ph;
473  if ( m_LogLevel >= 4 ) cout << myname << (haveHist ? "Re-c" : "C")
474  << "reating histogram " << hname
475  << " for channel " << acd.channel()
476  << " tickmod " << itkm
477  << ": " << nbin << ": [" << xmin << ", " << xmax << ")" << endl;
478  if ( nbin <= 0 ) {
479  cout << myname << " adcData.min(): " << adcData.min() << endl;
480  cout << myname << " adcData.max(): " << adcData.max() << endl;
481  cout << myname << " adcMin: " << adcMin << endl;
482  cout << myname << " adcMax: " << adcMax << endl;
483  abort();
484  }
485  ph.reset(new TH1F(hname.c_str(), htitl.c_str(), nbin, xmin, xmax));
486  ph->SetDirectory(0);
487  if ( haveHist ) {
488  for ( int ibin=1; ibin<=phold->GetNbinsX(); ++ibin ) {
489  int adc = phold->GetXaxis()->GetXmin() - 0.999 + ibin;
490  for ( int icnt=0; icnt<phold->GetBinContent(ibin); ++icnt ) {
491  ph->Fill(adc);
492  }
493  }
494  if ( m_LogLevel > 4 ) cout << myname << "Check new hist: " << phold->GetMean() << " ?= " << ph->GetMean() << endl;
496  } else {
498  }
499  }
500  // Add the new data to the histogram.
501  for ( AdcCount adc : adcData.data ) ph->Fill(adc);
502  sigMean = adcData.mean();
503  return 0;
504 }
505 
506 //**********************************************************************
507 
508 // Process the accumulated data for the current channel/femb.
509 // A StickyCodeMetric is created from the full ADC-range frequency histogram
510 // for each tickmod and from each of these:
511 // 1. The limited-range histogram is cached and optionally plotted and/or written
512 // to the root file.
513 // 2. An entry with metrics is added to the metric tree.
515  const string myname = "AdcTickModViewer::processAccumulatedChannel: ";
516  nplot = 0;
517  Index icha = getChannelIndex();
518  if ( state().ChannelTickModFullHists.find(icha) == state().ChannelTickModFullHists.end() ) return 1;
519  const HistVector& tmhsFull = state().ChannelTickModFullHists[icha];
520  HistVector& tmhsProc = state().ChannelTickModProcHists[icha];
521  Index ntkm = tmhsFull.size();
522  if ( m_LogLevel >= 3 ) {
523  cout << myname << "Tickmod hist count: " << ntkm << endl;
524  }
525  if ( tmhsProc.size() == 0 ) tmhsProc.resize(ntkm, nullptr);
526  if ( m_plotAny || m_makeTree ) {
527  // Fetch the tree.
528  TTree* ptree = state().tickmodTree;
530  if ( ptree != nullptr ) {
531  data.run = state().currentAcd.run();
532  data.chan = state().currentAcd.channel();
533  data.femb = state().currentAcd.fembID();
536  }
537  // Loop over tickmods and, for each, create metrics and limited-range ADC
538  // frequency histo and fill metric tree.
539  for ( Index itkm=0; itkm<ntkm; ++itkm ) {
540  const HistPtr& ph = tmhsFull[itkm];
541  // Process histograms with the sticky code utility.
542  Index chmod = 10;
543  StickyCodeMetrics scm(ph->GetName(), ph->GetTitle(), m_HistChannelCount, chmod, m_FitSigmaMin, m_FitSigmaMax);
544  if ( scm.evaluate(ph.get()) ) {
545  cout << myname << "Sticky code evaluation failed for channel " << icha
546  << " tickmod " << itkm << endl;
547  //tmhsProc[itkm].reset(ph);
548  } else {
549  tmhsProc[itkm] = scm.getSharedHist();
550  if ( ptree != nullptr ) {
551  data.itkm = itkm;
552  data.fill(scm);
553  ptree->Fill();
554  }
555  }
556  }
557  }
558  if ( m_plotAny ) {
559  // Draw the ADC frequency histogram for each tickmod.
560  makeTickModPlots(nplot);
561  if ( m_LogLevel >= 3 ) {
562  cout << myname << " Plot file count for channel " << icha
563  << ": " << nplot << endl;
564  }
565  }
566  return 0;
567 }
568 
569 //**********************************************************************
570 
571 // Process the accumulated data for all channels.
572 // The metric tree is created, processAccumulatedChannel is called for
573 // each channel and phase plots are created.
574 
576  const string myname = "AdcTickModViewer::processAccumulation: ";
577  Index ncha = state().ChannelTickModFullHists.size();
578  if ( ncha == 0 ) return 0;
579  // Set currentAcd for tree file name.
580  setChannel(state().ChannelTickModFullHists.begin()->first);
581  // Create tree to hold results.
582  TTree*& ptree = state().tickmodTree;
583  TFile*& pfile = state().pfile;
584  if ( m_TreeFileName.size() ) {
585  if ( m_LogLevel >= 2 ) cout << myname << "Creating tickmod tree." << endl;
586  TDirectory* psavdir = gDirectory;
587  string tfname = nameReplace(m_TreeFileName, state().currentAcd, 0);
588  pfile = TFile::Open(tfname.c_str(), "RECREATE");
589  if ( pfile->IsOpen() ) {
590  ptree = new TTree("tickmod", "TickMod tree");
591  ptree->Branch("data", &(state().treedata), 64000, 1);
592  } else {
593  cout << myname << "Unable to open file " << m_TreeFileName << endl;
594  }
595  psavdir->cd();
596  }
597  Index nplotTot = 0;
598  int rstat = 0;
599  if ( m_LogLevel >= 2 ) cout << myname << "Processing " << ncha << " channels" << endl;
600  for ( HistVectorMap::value_type icvm : state().ChannelTickModFullHists ) {
601  Index icha = setChannel(icvm.first);
602  if ( m_LogLevel >= 3 ) {
603  cout << myname << "Processing channel " << icha << endl;
604  }
605  Index nplot = 0;
606  rstat += processAccumulatedChannel(nplot);
607  nplotTot += nplot;
608  }
610  if ( m_LogLevel >= 2 ) {
611  cout << myname << " Total plot file count: " << nplotTot << endl;
612  }
613  if ( pfile != nullptr ) {
614  if ( m_LogLevel >= 2 ) {
615  cout << myname << "Tree size: " << ptree->GetEntries() << endl;
616  }
617  pfile->Write();
618  pfile->Close();
619  delete pfile;
620  pfile = nullptr;
621  ptree = nullptr;
622  }
623  // Make phase graphs and plots.
624  makePhaseGraphs();
625  plotPhaseGraphs();
626  return rstat;
627 }
628 
629 //**********************************************************************
630 
632  const string myname = "AdcTickModViewer::makeTickModPlots: ";
633  nplot = 0;
634  // Exit if no plots are requested.
635  if ( !m_plotAll && !m_plotMin && !m_plotMax ) return 0;
636  if ( !m_plotAll && !m_plotMin && !m_plotMax && !m_plotPhase ) return 0;
637  Index icha = getChannelIndex();
638  // Exit if this channel should not be plotted.
639  if ( m_PlotChannels.size() ) {
640  if ( find(m_PlotChannels.begin(), m_PlotChannels.end(), icha) == m_PlotChannels.end() ) {
641  if ( m_LogLevel >= 3 ) cout << myname << "Skipping channel not in PlotChannels: " << icha << endl;
642  return 0;
643  }
644  }
645  // Find the pad counts. Plot has npady x npadx pads with one tickmod plot per pad.
646  Index npad = 0;
647  Index npadx = 0;
648  Index npady = 0;
649  if ( m_PlotSplitX > 0 ) {
650  npadx = m_PlotSplitX;
652  npad = npadx*npady;
653  }
654  // Find the min and max ticks.
655  Index ntkm = m_TickModPeriod;
656  const HistVector& tmhs = state().ChannelTickModProcHists[icha];
657  Index itkmMin = 9999;
658  Index itkmMax = 9999;
659  if ( true ) {
660  double meanMin = tmhs[0]->GetMean();
661  double meanMax = meanMin;
662  for ( Index itkm=0; itkm<ntkm; ++itkm ) {
663  double mean = tmhs[itkm]->GetMean();
664  if ( mean > meanMax ) {
665  meanMax = mean;
666  itkmMax = itkm;
667  }
668  if ( mean < meanMin ) {
669  meanMin = mean;
670  itkmMin = itkm;
671  }
672  }
673  }
674  if ( m_LogLevel >= 3 ) cout << myname << "Processing channel " << icha << endl;
675  // Build the vectors describing the plots.
676  // showTickModVectors - Vector of tickmods included in each tickmod plot.
677  // showPlotNames - Name for each tickmod plot file.
678  vector<IndexVector> showTickModVectors; // Vectors of tickmods to plot
679  vector<Name> showPlotNames;
680  // Add plot descriptions for all tickmods.
681  if ( m_plotAll ) {
682  if ( m_LogLevel >= 3 ) cout << myname << "Add full vector of "
683  << ntkm << " tickmods." << endl;
684  showTickModVectors.emplace_back(ntkm);
685  for ( Index itkm=0; itkm<ntkm; ++itkm ) showTickModVectors.back()[itkm] = itkm;
686  showPlotNames.push_back(m_AllPlotFileName);
687  }
688  // Add plot descriptions for min and max plots.
689  if ( m_plotMin || m_plotMax ) {
690  IndexVector tkmsMin;
691  IndexVector tkmsMax;
692  //int idel1 = npad/2;
693  int idel1 = 0.4*npad;
694  idel1 *= -1;
695  int idel2 = idel1 + npad;
696  if ( npad > ntkm ) {
697  idel1 = 0;
698  idel2 = ntkm;
699  }
700  if ( m_LogLevel >= 3 ) cout << myname << "Tick delta range: [" << idel1
701  << ", " << idel2 << ")" << endl;
702  for ( int idel=idel1; idel<idel2; ++idel ) {
703  Index itkm = (itkmMin + ntkm + idel) % ntkm;
704  tkmsMin.push_back(itkm);
705  itkm = (itkmMax + ntkm + idel) % ntkm;
706  tkmsMax.push_back(itkm);
707  }
708  if ( m_plotMin ) {
709  if ( m_LogLevel >= 3 ) cout << myname << "Adding min vector of " << tkmsMin.size()
710  << " tickmods." << endl;
711  showTickModVectors.push_back(tkmsMin);
712  showPlotNames.push_back(m_MinPlotFileName);
713  }
714  if ( m_plotMax ) {
715  if ( m_LogLevel >= 3 ) cout << myname << "Adding max vector of " << tkmsMax.size()
716  << " tickmods." << endl;
717  showTickModVectors.push_back(tkmsMax);
718  showPlotNames.push_back(m_MaxPlotFileName);
719  }
720  }
721  // Loop over descriptions and build plots.
722  TPadManipulator* pmantop = nullptr;
723  for ( Index ihv=0; ihv<showTickModVectors.size(); ++ihv ) {
724  Name plotFileName;
725  const IndexVector tkms = showTickModVectors[ihv];
726  Name pfname = showPlotNames[ihv];
727  if ( m_LogLevel >= 3 ) cout << myname << "Plotting " << tkms.size() << " tickmods with name "
728  << pfname << endl;
729  Index ipad = 0;
730  Index icount = 0;
731  vector<TObject*> managedObjects;
732  for ( Index itkm : tkms ) {
733  HistPtr ph = tmhs[itkm];
734  if ( pmantop == nullptr ) {
735  pmantop = new TPadManipulator;
737  if ( npad > 1 ) pmantop->split(npadx, npady);
738  plotFileName = nameReplace(pfname, state().currentAcd, itkm);
739  }
740  TPadManipulator* pman = pmantop->man(ipad);
741  pman->add(ph.get(), "hist", false);
742  if ( m_PlotShowFit > 1 ) pman->addHistFun(1);
743  if ( m_PlotShowFit ) {
744  pman->addHistFun(0);
745  TF1* pfun = dynamic_cast<TF1*>(ph->GetListOfFunctions()->At(0));
746  if ( pfun != nullptr ) {
747  ostringstream ssout;
748  ssout.precision(1);
749  ssout << "Mean: " << std::fixed << pfun->GetParameter(1);
750  TLatex* ptxt = new TLatex(0.72, 0.86, ssout.str().c_str());
751  ptxt->SetNDC();
752  ptxt->SetTextFont(42);
753  pman->add(ptxt);
754  managedObjects.push_back(ptxt);
755  ssout.str("");
756  ssout << "Sigma: " << std::fixed << pfun->GetParameter(2);
757  ptxt = new TLatex(0.72, 0.80, ssout.str().c_str());
758  ptxt->SetNDC();
759  ptxt->SetTextFont(42);
760  pman->add(ptxt);
761  managedObjects.push_back(ptxt);
762  }
763  }
764  pman->addVerticalModLines(64);
765  pman->showUnderflow();
766  pman->showOverflow();
767  ++icount;
768  if ( ++ipad == npad || icount == tkms.size() ) {
769  if ( m_LogLevel >= 2 ) cout << myname << "Saving plot " << plotFileName << endl;
770  pmantop->print(plotFileName);
771  ++nplot;
772  ipad = 0;
773  delete pmantop;
774  pmantop = nullptr;
775  for ( TObject* pobj : managedObjects ) delete pobj;
776  managedObjects.clear();
777  }
778  }
779  }
780  return 0;
781 }
782 
783 //**********************************************************************
784 
785 // Make the phase graphs.
786 
788  const string myname = "AdcTickModViewer::makePhaseGraph: ";
789  if ( ! m_plotPhase ) return 0;
790  // Plot phase vs. peak tick.
791  Index nvar = m_NTimingPhase;
792  if ( ! m_varPhase ) nvar = state().eventIDs.size();
793  // Smearing of data points.
794  Index ntkm = m_TickModPeriod;
795  if ( ntkm == 0 ) return 0;
796  // Loop over group indices (group = channel. femb, ...).
797  Index ncan = state().phaseChannels.size();
798  if ( m_LogLevel >= 2 ) {
799  cout << myname << "Building phase-peak graphs for " << ncan
800  << " " << m_PhaseGrouping << " indices" << endl;
801  }
802  for ( IndexVectorMap::value_type iich : state().phaseChannels ) {
803  Index igrp = iich.first;
804  const IndexVector ichas = iich.second;
805  setChannel(ichas.front());
806  // Collect the data for this channel from all contributing channels.
807  FloatVVector xpksByPhase(nvar);
808  for ( Index icha : ichas ) {
809  const FloatVVector& chanXpksByPhase = state().MaxTickMods[icha];
810  for ( Index ivar=0; ivar<nvar; ++ivar ) {
811  FloatVector& out = xpksByPhase[ivar];
812  const FloatVector& in = chanXpksByPhase[ivar];
813  out.insert(out.end(), in.begin(), in.end());
814  }
815  }
816  // Build the graph.
817  string hnam = "hphtm";
818  string vname = m_varPhase ? "Phase" :
819  m_varEvent ? "Event" :
820  m_varTick0 ? "Tick0" :
821  m_varNchan ? "Nchan" : "UNKNOWN";
822  string httl = vname + " vs. tickmod peak for run %RUN% " + m_PhaseGrouping
823  + " " + std::to_string(igrp);
824  httl = nameReplace(httl, state().currentAcd, 0);
825  TGraph* pg = new TGraph;
826  pg->SetName(hnam.c_str());
827  pg->SetTitle(httl.c_str());
828  pg->SetMarkerStyle(2);
829  pg->SetMarkerColor(602);
830  pg->GetXaxis()->SetTitle("Peak position [tick]");
831  pg->GetXaxis()->SetTitle("Peak position [tick]");
832  pg->GetXaxis()->SetTitle("Peak position [tick]");
833  if ( m_varPhase ) pg->GetYaxis()->SetTitle("Timing phase");
834  if ( m_varEvent ) pg->GetYaxis()->SetTitle("Event ID");
835  if ( m_varTick0 ) pg->GetYaxis()->SetTitle("Event time [Tick]");
836  if ( m_varNchan ) pg->GetYaxis()->SetTitle("Channel count");
837  if ( m_LogLevel >=3 ) cout << myname << "Plotting " << m_PhaseVariable << " vs. peak tick for "
838  << m_PhaseGrouping << " " << igrp << endl;
839  // Find range of tickmods with no change and with smaller values shifted
840  // up by one period. The distribution with smaller range is used.
841  double xmin = 1.e20;
842  double xmax = -1.e20;
843  double xminShift = 1.e20;
844  double xmaxShift = -1.e20;
845  float xhalf = 0.5*ntkm;
846  for ( Index ivar=0; ivar<nvar; ++ivar ) {
847  for ( float x : xpksByPhase[ivar] ) {
848  if ( x < xmin ) xmin = x;
849  if ( x > xmax ) xmax = x;
850  float xs = x < xhalf ? x + ntkm : x;
851  if ( xs < xminShift ) xminShift = xs;
852  if ( xs > xmaxShift ) xmaxShift = xs;
853  }
854  }
855  bool doShift = (xmax - xmin) > xhalf;
856  doShift &= xmaxShift - xminShift < xmax - xmin; // Should we shift points?
857  if ( doShift ) {
858  xmin = xminShift;
859  xmax = xmaxShift;
860  }
861  // Fill the graph.
862  for ( Index ivar=0; ivar<nvar; ++ivar ) {
863  float y0 = ivar;
864  if ( m_varEvent ) y0 = state().eventIDs[ivar];
865  if ( m_varTick0 ) y0 = state().tick0s[ivar];
866  if ( m_varNchan ) y0 = state().nchans[ivar];
867  FloatVector& xpks = xpksByPhase[ivar];
868  if ( m_LogLevel >= 4 ) cout << myname << "Phase " << ivar << " peak count: " << xpks.size() << endl;
869  Index nxpk = xpks.size();
870  for ( Index ixpk=0; ixpk<nxpk; ++ixpk ) {
871  float x = xpks[ixpk];
872  if ( doShift && x < xhalf ) x += ntkm;
873  float y = y0;
874  if ( m_varPhase || m_varEvent ) y+= -0.25 + 0.5*(ixpk+0.5)/nxpk; // Smear integers
875  pg->SetPoint(pg->GetN(), x, y);
876  }
877  }
878  pg->GetXaxis()->SetRangeUser(xmin, xmax);
879  // Save the graph in the state for this tool.
880  state().phaseGraphs[igrp].reset(pg);
881  }
882  return 0;
883 }
884 
885 //**********************************************************************
886 
887 // Plot the phase graphs.
888 
890  const string myname = "AdcTickModViewer::plotPhaseGraphs: ";
891  if ( ! m_plotPhase ) return 0;
892  if ( m_LogLevel >=3 ) cout << myname << "Making phase graph plots. Count: "
893  << state().phaseGraphs.size() << endl;
894  Index npha = m_NTimingPhase;
895  // Find the pad counts. Plot has npady x npadx pads with one tickmod plot per pad.
896  Index npad = 0;
897  Index npadx = 0;
898  Index npady = 0;
899  if ( m_PhasePlotSplitX > 0 ) {
900  npadx = m_PhasePlotSplitX;
902  npad = npadx*npady;
903  }
904  // Find the min and max ticks.
905  TPadManipulator* pmantop = nullptr;
906  Index igrpLast = state().phaseGraphs.rbegin()->first;
907  Index ipad = 0;
908  Name plotFileName;
909  for ( GraphMap::value_type icgr : state().phaseGraphs ) {
910  Index igrp = icgr.first;
911  setChannel(state().phaseChannels[igrp].front());
912  TGraph* pg = icgr.second.get();
913  // If needed, start a new plot.
914  if ( pmantop == nullptr ) {
915  pmantop = new TPadManipulator;
918  if ( npad > 1 ) pmantop->split(npadx, npady);
919  plotFileName = nameReplace(m_PhasePlotFileName, state().currentAcd, 0);
920  ipad = 0;
921  }
922  TPadManipulator* pman = pmantop->man(ipad);
923  // Evaluate plot range.
924  double xmin = int(pg->GetXaxis()->GetXmin());
925  double xmax = int(pg->GetXaxis()->GetXmax() + 1.0);
926  while ( xmax - xmin < 10.0 ) {
927  xmin -= 0.5;
928  xmax += 0.5;
929  }
930  // Create plot.
931  pman->add(pg->Clone(), "P");
932  pman->addAxis();
933  pman->setRangeX(xmin, xmax);
934  if ( m_varPhase ) pman->setRangeY(-1, npha);
935  pman->setGridX();
936  pman->setGridY();
937  // Print the plot.
938  if ( ++ipad == npad || igrp == igrpLast ) {
939  if ( m_LogLevel >= 2 ) cout << myname << "Saving plot " << plotFileName << endl;
940  pmantop->print(plotFileName);
941  pmantop = nullptr;
942  }
943  }
945  return 0;
946 }
947 
948 //**********************************************************************
949 
ChannelInfoPtr getChannelInfoPtr() const
int setGridY(bool flag=true)
std::vector< AdcCount > AdcCountVector
Definition: AdcTypes.h:19
void clearChannelIndex() const
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
HistVectorMap ChannelTickModProcHists
Name nameReplace(Name name, const AdcChannelData &acd, Index itkm) const
std::map< Index, HistVector > HistVectorMap
AdcIndex subRun() const
void fill(const StickyCodeMetrics &scm)
bool dbg
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
unsigned int Index
DataMap & setStatus(int stat)
Definition: DataMap.h:130
std::string string
Definition: nybbler.cc:12
HistVectorMap ChannelTickModFullHists
std::shared_ptr< TH1 > HistPtr
virtual DataMap viewMap(const AdcChannelDataMap &acds) const
const TimeOffsetTool * m_tickOffsetTool
Coord add(Coord c1, Coord c2)
Definition: restypedef.cpp:23
struct vector vector
ChannelGroupService::Name Name
int replace(std::string substr, const T &xsub)
FloatVVectorMap MaxTickMods
Index getChannelIndex() const
int setCanvasSize(int wx, int wy)
int16_t adc
Definition: CRTFragment.hh:202
int split(Index nx, Index ny)
IndexVector m_PlotChannels
EventInfoPtr getEventInfoPtr() const
unsigned int Index
int showOverflow(bool show=true)
Q_EXPORT QTSManip setprecision(int p)
Definition: qtextstream.h:343
State & state() const
Index fembID() const
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void setChannelData(const AdcChannelData &acd) const
void setChannelInfo(ChannelInfoPtr pchi)
virtual Offset offset(const Data &dat) const =0
void setHistVector(Name name, const HistVector &hsts, bool own=false)
Definition: DataMap.h:150
DataMap view(const AdcChannelData &acd) const override
static std::string build(const AdcChannelStringTool *ptool, const AdcChannelData &acd, const DataMap &dm, std::string spat)
bool hasMetadata(Name mname) const
Index fembChannel() const
int showUnderflow(bool show=true)
AdcIndex run() const
Index setChannel(Index igran) const
void setEventInfo(EventInfoPtr pevi)
int addAxis(bool flag=true)
float getMetadata(Name mname, float def=0.0) const
void setInt(Name name, int val)
Definition: DataMap.h:131
AdcIndex event() const
static int max(int a, int b)
static constexpr double ps
Definition: Units.h:99
AdcCountVector raw
TPadManipulator * man(unsigned int ipad=0)
std::vector< float > FloatVector
int addVerticalModLines(double xmod, double xoff=0.0, double lenfrac=1.0, int isty=3)
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
Channel channel() const
int addHistFun(unsigned int ifun=0)
DataMap viewMap(const AdcChannelDataMap &acds) const override
AdcSignal pedestal
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
int processChannelTickMod(const AdcChannelData &acd, Index itkm0, Index itkm, float &sigMean) const
int makeTickModPlots(Index &nplot) const
std::vector< FloatVector > FloatVVector
def chmod(path, mode)
int setRangeX(double x1, double x2)
int processAccumulation(Index &nplot) const
AdcChannelDataMap acdMap
AdcTickModViewer(fhicl::ParameterSet const &ps)
list x
Definition: train.py:276
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
const AdcChannelStringTool * m_adcStringBuilder
IndexVectorMap phaseChannels
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
short AdcCount
Definition: AdcTypes.h:18
std::vector< Index > IndexVector
int setGridX(bool flag=true)
int processAccumulatedChannel(Index &nplot) const
static Index badIndex()
int setRangeY(double y1, double y2)
double mean(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:16
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
unsigned int Index
int print(std::string fname, std::string spat="{,}")
static DuneToolManager * instance(std::string fclname="", int dbg=1)
AdcLongIndex triggerClock() const
std::vector< HistPtr > HistVector
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
T * getShared(std::string name)
QTextStream & endl(QTextStream &s)