AdcChannelPlotter_tool.cc
Go to the documentation of this file.
1 // AdcChannelPlotter_tool.cc
2 
3 #include "AdcChannelPlotter.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 
18 using std::string;
19 using std::cout;
20 using std::endl;
21 using std::ofstream;
22 using std::ostream;
23 using std::ostringstream;
24 using std::setw;
25 using std::fixed;
26 using std::setprecision;
27 using std::vector;
28 
29 using Index = unsigned int;
30 
31 //**********************************************************************
32 // Class methods.
33 //**********************************************************************
34 
36 : m_LogLevel(ps.get<int>("LogLevel")),
37  m_HistTypes(ps.get<NameVector>("HistTypes")),
38  m_HistName(ps.get<string>("HistName")),
39  m_HistTitle(ps.get<string>("HistTitle")),
40  m_RootFileName(ps.get<string>("RootFileName")),
41  m_PlotFileName(ps.get<string>("PlotFileName")),
42  m_PlotSamMin(ps.get<Index>("PlotSamMin")),
43  m_PlotSamMax(ps.get<Index>("PlotSamMax")),
44  m_PlotSigOpt(ps.get<string>("PlotSigOpt")),
45  m_PlotSigMin(ps.get<float>("PlotSigMin")),
46  m_PlotSigMax(ps.get<float>("PlotSigMax")),
47  m_PlotDistMin(ps.get<float>("PlotDistMin")),
48  m_PlotDistMax(ps.get<float>("PlotDistMax")),
49  m_ColorBad(ps.get<Index>("ColorBad")),
50  m_ColorNoisy(ps.get<Index>("ColorNoisy")),
51  m_LabelSize(ps.get<float>("LabelSize")),
52  m_SkipFlags(ps.get<IndexVector>("SkipFlags")) {
53  const string myname = "AdcChannelPlotter::ctor: ";
54  if ( m_HistTypes.size() == 0 ) {
55  cout << myname << "WARNING: No histogram types are specified." << endl;
56  return;
57  }
59  string stringBuilder = "adcStringBuilder";
60  m_adcStringBuilder = ptm->getShared<AdcChannelStringTool>(stringBuilder);
61  if ( m_adcStringBuilder == nullptr ) {
62  cout << myname << "WARNING: AdcChannelStringTool not found: " << stringBuilder << endl;
63  }
64  if ( m_ColorBad || m_ColorNoisy ) {
65  if ( m_LogLevel >= 1 ) cout << myname << "Fetching channel status service." << endl;
67  if ( m_pChannelStatusProvider == nullptr ) {
68  cout << myname << "WARNING: Channel status provider not found." << endl;
69  m_ColorBad = 0;
70  m_ColorNoisy = 0;
71  }
72  }
73  for ( Index flg : m_SkipFlags ) m_skipFlags.insert(flg);
74  if ( m_LogLevel > 0 ) {
75  cout << myname << " LogLevel: " << m_LogLevel << endl;
76  cout << myname << " HistTypes: [";
77  bool first = true;
78  for ( string name : m_HistTypes ) {
79  if ( ! first ) cout << ", ";
80  first = false;
81  cout << name;
82  }
83  cout << "]" << endl;
84  cout << myname << " HistName: " << m_HistName << endl;
85  cout << myname << " HistTitle: " << m_HistTitle << endl;
86  cout << myname << " RootFileName: " << m_RootFileName << endl;
87  cout << myname << " PlotFileName: " << m_PlotFileName << endl;
88  cout << myname << " PlotSamMin: " << m_PlotSamMin << endl;
89  cout << myname << " PlotSamMax: " << m_PlotSamMax << endl;
90  cout << myname << " PlotSigOpt: " << m_PlotSigOpt << endl;
91  cout << myname << " PlotSigMin: " << m_PlotSigMin << endl;
92  cout << myname << " PlotSigMax: " << m_PlotSigMax << endl;
93  cout << myname << " PlotDistMin: " << m_PlotDistMin << endl;
94  cout << myname << " PlotDistMax: " << m_PlotDistMax << endl;
95  cout << myname << " ColorBad: " << m_ColorBad << endl;
96  cout << myname << " ColorNoisy: " << m_ColorNoisy << endl;
97  cout << myname << " LabelSize: " << m_LabelSize << endl;
98  cout << myname << " SkipFlags: [";
99  first = true;
100  for ( Index flg : m_SkipFlags ) {
101  if ( first ) first = false;
102  else cout << ", ";
103  cout << flg;
104  }
105  cout << "]" << endl;
106  }
107 }
108 
109 //**********************************************************************
110 
112 }
113 
114 //**********************************************************************
115 
117  const string myname = "AdcChannelPlotter::view: ";
118  if ( m_LogLevel >= 3 ) cout << myname << "Processing channel " << acd.channel() << endl;
119  DataMap res;
120  if ( m_HistTypes.size() == 0 ) {
121  cout << myname << "WARNING: No histogram types are specified." << endl;
122  return res.setStatus(1);
123  }
124  string hnameBase = m_HistName;
125  if ( hnameBase == "" ) hnameBase = "%TYPE%";
126  string htitlBase = m_HistTitle;
127  if ( htitlBase == "" ) htitlBase = "%TYPE%";
128  TDirectory* polddir = gDirectory;
129  TFile* pfile = nullptr;
130  if ( m_RootFileName.size() ) {
131  string fname = nameReplace(m_RootFileName, acd, m_HistTypes[0]);
132  pfile = TFile::Open(fname.c_str(), "UPDATE");
133  }
134  vector<TH1*> hists;
135  bool resManage = true; // Does returned data map manage the histogram
136  for ( string type : m_HistTypes ) {
137  TH1* ph = nullptr;
138  string hname = nameReplace(hnameBase, acd, type);
139  string htitl = nameReplace(htitlBase, acd, type);
140  bool isRawDist = type == "rawdist" || type == "rawdistlog";
141  if ( type == "raw" ) {
142  Index nsam = acd.raw.size();
143  if ( nsam == 0 ) {
144  cout << myname << "WARNING: Raw data is empty." << endl;
145  continue;
146  }
147  htitl += "; Tick; ADC count";
148  ph = new TH1F(hname.c_str(), htitl.c_str(), nsam, 0, nsam);
149  hists.push_back(ph);
150  float sigMin = acd.raw[0];
151  float sigMax = sigMin;
152  for ( Index isam=0; isam<nsam; ++isam ) {
153  float sig = acd.raw[isam];
154  ph->SetBinContent(isam+1, sig);
155  if ( isam >= m_PlotSamMin && isam < m_PlotSamMax ) {
156  if ( sig < sigMin ) sigMin = sig;
157  if ( sig > sigMax ) sigMax = sig;
158  }
159  }
160  res.setFloat("plotSigMin_" + type, sigMin);
161  res.setFloat("plotSigMax_" + type, sigMax);
162  } else if ( isRawDist ) {
163  Index nsam = acd.raw.size();
164  if ( nsam == 0 ) {
165  cout << myname << "WARNING: Raw data is empty." << endl;
166  continue;
167  }
168  // Flag samples to keep in pedestal fit.
169  vector<bool> keep(nsam, true);
170  Index nkeep = 0;
171  for ( Index isam=0; isam<nsam; ++isam ) {
172  if ( isam >= acd.flags.size() ) {
173  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: flags are missing." << endl;
174  break;
175  }
176  Index flg = acd.flags[isam];
177  if ( m_skipFlags.count(flg) ) keep[isam] = false;
178  else ++nkeep;
179  }
180  if ( nkeep == 0 ) {
181  if ( m_LogLevel >= 2 ) cout << myname << "WARNING: No raw data is selected." << endl;
182  return res.setStatus(2);
183  }
184  // Create a new histogram if %EVENT% appears in the name.
185  bool useExistingHist = m_HistName.find("%EVENT%") == string::npos;
186  if ( useExistingHist ) {
187  HistMap::iterator ihst = getState().hists.find(hname);
188  if ( ihst != getState().hists.end() ) ph = ihst->second;
189  resManage = false;
190  }
191  if ( ph == nullptr ) {
192  htitl += "; ADC count; # samples";
193  unsigned int nadc = 4096;
194  ph = new TH1F(hname.c_str(), htitl.c_str(), nadc, 0, nadc);
195  if ( ! useExistingHist ) hists.push_back(ph);
196  if ( useExistingHist ) getState().hists[hname] = ph;
197  }
198  float sigMin = acd.raw[0];
199  float sigMax = sigMin;
200  for ( Index isam=0; isam<nsam; ++isam ) {
201  float sig = acd.raw[isam];
202  if ( keep[isam] ) ph->Fill(sig);
203  if ( isam >= m_PlotSamMin && isam < m_PlotSamMax ) {
204  if ( sig < sigMin ) sigMin = sig;
205  if ( sig > sigMax ) sigMax = sig;
206  }
207  }
208  res.setFloat("plotSigMin_" + type, sigMin);
209  res.setFloat("plotSigMax_" + type, sigMax);
210  } else if ( type == "prepared" ) {
211  Index nsam = acd.samples.size();
212  if ( nsam == 0 ) {
213  cout << myname << "WARNING: Prepared data is empty." << endl;
214  continue;
215  }
216  htitl += "; Tick; Signal";
217  if ( acd.sampleUnit.size() ) {
218  htitl += " [" + acd.sampleUnit + "]";
219  }
220  ph = new TH1F(hname.c_str(), htitl.c_str(), nsam, 0, nsam);
221  hists.push_back(ph);
222  float sigMin = acd.samples[0];
223  float sigMax = sigMin;
224  for ( Index isam=0; isam<nsam; ++isam ) {
225  float sig = acd.samples[isam];
226  ph->SetBinContent(isam+1, sig);
227  if ( isam >= m_PlotSamMin && isam < m_PlotSamMax ) {
228  if ( sig < sigMin ) sigMin = sig;
229  if ( sig > sigMax ) sigMax = sig;
230  }
231  }
232  res.setFloat("plotSigMin_" + type, sigMin);
233  res.setFloat("plotSigMax_" + type, sigMax);
234  } else {
235  cout << myname << "WARNING: Unknown type: " << type << endl;
236  }
237  if ( ph == nullptr ) continue;
238  ph->SetStats(0);
239  ph->SetLineWidth(2);
241  ph->SetLineColor(m_ColorBad);
242  }
244  ph->SetLineColor(m_ColorNoisy);
245  }
246  res.setHist(type, ph, resManage);
247  }
248  if ( pfile != nullptr ) {
249  if ( m_LogLevel >= 2 ) cout << myname << "Writing to " << pfile->GetName() << endl;
250  for ( TH1* ph : hists ) ph->Write();
251  if ( m_LogLevel >= 4 ) {
252  cout << myname << "File listing: " << endl;
253  pfile->ls();
254  }
255  pfile->Close();
256  delete pfile;
257  gDirectory = polddir;
258  }
259  return res;
260 }
261 
262 //**********************************************************************
263 
265  const string myname = "AdcChannelPlotter::viewMap: ";
266  DataMap resall;
267  bool doPlots = m_PlotFileName.size();
268  Index nx = 1;
269  Index ny = 8;
270  Index nplt = nx*ny;
271  Index ndx = 4;
272  Index ndy = 4;
273  Index ndplt = ndx*ndy;
274  using ManMap = std::map<string, TPadManipulator>;
275  using NameMap = std::map<string, string>;
276  using IndexMap = std::map<string, Index>;
277  ManMap mans;
278  IndexMap iplts;
279  IndexMap nplts;
280  NameMap pfnames;
281  std::vector<TLatex*> labs;
282  bool useViewPort = true;
283  for ( const AdcChannelDataMap::value_type& iacd : acds ) {
284  Index icha = iacd.first;
285  string schan = std::to_string(icha);
286  TLatex* ptxt = new TLatex(0.98, 0.025, schan.c_str());
287  ptxt->SetNDC();
288  ptxt->SetTextFont(42);
289  ptxt->SetTextAlign(31);
290  labs.push_back(ptxt);
291  const AdcChannelData& acd = iacd.second;
292  DataMap res = view(acd);
293  if ( doPlots ) {
294  for ( string type : m_HistTypes ) {
295  bool isRaw = type == "raw";
296  bool isRawDist = type == "rawdist" || type == "rawdistlog";
297  bool isLogY = type == "rawdistlog";
298  float marginTop = 0.0;
299  float marginBottom = isRawDist ? 0.12 : 0.09;
300  float marginLeft = isRawDist ? 0.12 : 0.05;
301  float marginRight = isRawDist ? 0.02 : 0.01;
302  float xlab = isRawDist ? 0.95 : 0.98;
303  float ylab = 0.05 + marginBottom;
304  float hlab = isRawDist ? 0.08 : 0.16;
305  ptxt->SetX(xlab);
306  ptxt->SetY(ylab);
307  ptxt->SetTextSize(hlab);
308  if ( mans.find(type) == mans.end() ) {
309  if ( m_LogLevel >= 3 ) cout << "Creating new top-level plot of type " << type << "." << endl;
310  TPadManipulator& topman = mans[type];
311  topman.setCanvasSize(1400, 1000);
312  if ( useViewPort ) {
313  float xview1 = 0.0;
314  float yview1 = isRawDist ? 0.0 : 0.00;
315  float xview2 = 1.0;
316  float yview2 = isRawDist ? 0.96 : 0.96;
317  if ( topman.addPad(xview1, yview1, xview2, yview2) ) {
318  cout << myname << "ERROR: Unable to add subpad." << endl;
319  abort();
320  }
321  }
322  TPadManipulator& man = *topman.man(0);
323  if ( isRaw || type == "prepared" ) {
324  man.split(nx,ny);
325  for ( Index ipad=0; ipad<nplt; ++ipad ) {
326  if ( isRaw && (m_PlotSigMax - m_PlotSigMin) < 1001 ) man.man(ipad)->addHorizontalModLines(64);
327  man.man(ipad)->setRangeX(m_PlotSamMin, m_PlotSamMax);
328  man.addAxis();
329  }
330  nplts[type] = nx*ny;
331  } else if ( isRawDist ) {
332  man.split(ndx, ndy);
333  for ( Index ipad=0; ipad<ndplt; ++ipad ) {
334  man.man(ipad)->addVerticalModLines(64);
335  man.man(ipad)->setRangeX(m_PlotSigMin, m_PlotSigMax);
336  man.man(ipad)->showUnderflow();
337  man.man(ipad)->showOverflow();
338  if ( type == "rawdistlog" ) man.man(ipad)->setLogY();
339  man.addAxis();
340  }
341  nplts[type] = ndx*ndy;
342  }
343  pfnames[type] = nameReplace(m_PlotFileName, acd, type);
344  iplts[type] = 0;
345  if ( m_LabelSize ) {
348  //man.setTitleSize(m_LabelSize);
349  }
350  for ( Index ipsm=0; ipsm<man.npad(); ++ipsm ) {
351  TPadManipulator* psman = man.man(ipsm);
352  psman->setMarginTop(marginTop);
353  psman->setMarginBottom(marginBottom);
354  psman->setMarginLeft(marginLeft);
355  psman->setMarginRight(marginRight);
356  }
357  }
358  Index& iplt = iplts[type];
359  Index nplt = nplts[type];
360  TH1* ph = res.getHist(type);
361  if ( m_LogLevel >= 3 ) cout << myname << " Adding subplot " << iplt << " for type " << type << "." << endl;
362  TPadManipulator& topman = mans[type];
363  string sttl = ph->GetTitle();
364  Index ipos = sttl.find(" channel");
365  sttl = sttl.substr(0, ipos);
366  topman.setTitle(sttl, 0.025);
367  TPadManipulator& man = useViewPort ? *topman.man(0)->man(iplt) : *topman.man(iplt);
368  man.add(ph, "hist", false);
369  man.setTitle("");
370  if ( type == "raw" || type == "prepared" ) {
371  float ymin = m_PlotSigMin;
372  float ymax = m_PlotSigMax;
373  if ( m_PlotSigOpt == "pedestal" ) {
374  if ( type == "raw" ) {
375  ymin += acd.pedestal;
376  ymax += acd.pedestal;
377  } else {
378  cout << myname << "Invalid raw PlotSigOpt = " << m_PlotSigOpt << ". Using fixed." << endl;
379  }
380  } else if ( m_PlotSigOpt == "full" ) {
381  int dSigMin = m_PlotSigMin;
382  int gSigMin = res.getFloat("plotSigMin_" + type);
383  int gSigMax = res.getFloat("plotSigMax_" + type) + 0.999;
384  if ( gSigMax - gSigMin < dSigMin ) {
385  while ( gSigMax - gSigMin < dSigMin ) {
386  if ( gSigMin > 0 ) --gSigMin;
387  if ( gSigMax - gSigMin < dSigMin ) ++gSigMax;
388  }
389  }
390  ymin = gSigMin;
391  ymax = gSigMax;
392  } else if ( m_PlotSigOpt != "fixed" ) {
393  cout << myname << "Invalid " << type << " PlotSigOpt = " << m_PlotSigOpt << ". Using fixed." << endl;
394  }
395  man.setRangeY(ymin, ymax);
396  man.add(ptxt);
397  // For raw data, add line showing the pedestal.
398  if ( type == "raw" && acd.pedestal > ymin && acd.pedestal < ymax ) {
399  man.addHorizontalLine(acd.pedestal);
400  }
401  // For prepared data, add line showing zero.
402  if ( type == "prepared" ) {
403  man.addHorizontalLine(0.0);
404  }
405 
406  } else if ( isRawDist ) {
407  if ( m_PlotSigOpt == "fixed" ) {
408  float xmin = m_PlotSigMin;
409  float xmax = m_PlotSigMax;
410  man.setRangeX(xmin, xmax);
411  } else if ( m_PlotSigOpt == "pedestal" ) {
412  float xmin = acd.pedestal + m_PlotSigMin;
413  float xmax = acd.pedestal + m_PlotSigMax;
414  man.setRangeX(xmin, xmax);
415  } else if ( m_PlotSigOpt != "full" ) {
416  cout << myname << "Invalid rawdist PlotSigOpt = " << m_PlotSigOpt << ". Using full." << endl;
417  }
418  if ( m_PlotDistMax > m_PlotDistMin ) {
419  if ( isLogY ) man.setLogRangeY(m_PlotDistMin, m_PlotDistMax);
421  }
422  man.add(ptxt);
423  }
424  man.addAxis();
425  if ( ++iplt >= nplt ) {
426  if ( m_LogLevel >= 3 ) cout << "Printing plot " << pfnames[type] << endl;
427  for ( string type : m_HistTypes ) mans[type].print(pfnames[type]);
428  mans.erase(type);
429  pfnames.erase(type);
430  }
431  }
432  }
433  }
434  // Print any left over (i.e. partial) plots.
435  for ( ManMap::value_type& iman : mans ) iman.second.print(pfnames[iman.first]);
436  for ( TLatex* ptxt : labs ) delete ptxt;
437  return resall;
438 }
439 
440 //**********************************************************************
441 
442 string AdcChannelPlotter::
443 nameReplace(string name, const AdcChannelData& acd, string type) const {
445  string nameout = name;
446  StringManipulator sman(nameout, false);
447  if ( type.size() ) sman.replace("%TYPE%", type);
448  if ( pnbl == nullptr ) return nameout;
449  DataMap dm;
450  return pnbl->build(acd, dm, nameout);
451 }
452 
453 //**********************************************************************
454 
static QCString name
Definition: declinfo.cpp:673
virtual bool IsBad(raw::ChannelID_t channel) const =0
Returns whether the specified channel is bad in the current run.
intermediate_table::iterator iterator
State & getState() const
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
const AdcChannelStringTool * m_adcStringBuilder
int setLabelSizeX(double siz)
DataMap view(const AdcChannelData &acd) const override
const lariov::ChannelStatusProvider * m_pChannelStatusProvider
void setFloat(Name name, float val)
Definition: DataMap.h:133
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
unsigned int Index
Name nameReplace(Name name, const AdcChannelData &acd, Name type) const
void setMarginLeft(double xmar)
DataMap & setStatus(int stat)
Definition: DataMap.h:130
std::string string
Definition: nybbler.cc:12
int addPad(double x1, double y1, double x2, double y2, int icol=-1)
virtual bool IsNoisy(raw::ChannelID_t channel) const =0
Returns whether the specified channel is noisy in the current run.
DataMap viewMap(const AdcChannelDataMap &acds) const override
struct vector vector
int replace(std::string substr, const T &xsub)
int setLabelSizeY(double siz)
int setCanvasSize(int wx, int wy)
void setHist(Name name, TH1 *ph, bool own=false)
Definition: DataMap.h:136
int split(Index nx, Index ny)
unsigned int Index
int showOverflow(bool show=true)
Q_EXPORT QTSManip setprecision(int p)
Definition: qtextstream.h:343
int setTitle(std::string sttl, float height=-1.0)
std::vector< Index > IndexVector
int addHorizontalLine(double yoff=0.0, double lenfrac=1.0, int isty=1)
static std::string build(const AdcChannelStringTool *ptool, const AdcChannelData &acd, const DataMap &dm, std::string spat)
int setLogY(bool flag=true)
int showUnderflow(bool show=true)
int addAxis(bool flag=true)
unsigned int npad() const
static constexpr double ps
Definition: Units.h:99
AdcCountVector raw
TPadManipulator * man(unsigned int ipad=0)
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
Float getFloat(Name name, Float def=0.0) const
Definition: DataMap.h:220
void setMarginTop(double xmar)
Channel channel() const
AdcSignal pedestal
int setLogRangeY(double y1, double y2)
int setRangeX(double x1, double x2)
static QCString type
Definition: declinfo.cpp:672
Interface for experiment-specific channel quality info provider.
std::vector< Name > NameVector
void setMarginBottom(double xmar)
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
TH1 * getHist(Name name, TH1 *def=nullptr) const
Definition: DataMap.h:223
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
Interface for experiment-specific service for channel quality info.
int addHorizontalModLines(double ymod, double yoff=0.0, double lenfrac=1.0, int isty=3)
AdcChannelPlotter(fhicl::ParameterSet const &ps)
int setRangeY(double y1, double y2)
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
void setMarginRight(double xmar)
static DuneToolManager * instance(std::string fclname="", int dbg=1)
AdcSignalVector samples
T * getShared(std::string name)
QTextStream & endl(QTextStream &s)
AdcFlagVector flags