test_Tpc2dDeconvolute.cxx
Go to the documentation of this file.
1 // test_Tpc2dDeconvolute.cxx
2 //
3 // David Adams
4 // April 2019
5 //
6 // Test Tpc2dDeconvolute.
7 
8 #include <string>
9 #include <iostream>
10 #include <fstream>
11 #include <sstream>
12 #include <vector>
13 #include <iomanip>
18 #include <TRandom.h>
19 #include <TH1F.h>
20 #include <TCanvas.h>
21 #include "TLegend.h"
22 
23 #undef NDEBUG
24 #include <cassert>
25 
26 using std::string;
27 using std::cout;
28 using std::endl;
29 using std::ostringstream;
30 using std::istringstream;
31 using std::ofstream;
33 using std::vector;
34 using std::setw;
35 using std::fixed;
36 
37 using Index = unsigned int;
38 using Name = std::string;
39 
40 //**********************************************************************
41 namespace {
42 
43 class Plot {
44 public:
45  TPadManipulator topman;
46  float ymin = 0.0;
47  float ymax = 42.0;
48  Name dopt = "HIST";
49  Plot(Index npad) : topman(400, 800) {
50  topman.split(1, npad);
51  }
52  void setRange(float a_ymin, float a_ymax) {
53  ymin = a_ymin;
54  ymax = a_ymax;
55  }
56  int addData(const TpcData& tpd, Name roinam, int col, int lwid, int lsty) {
57  string myname = "Plot::addData: ";
58  // Log messages
59  // 0 - none
60  // 1 - sample count for each channel
61  // 2 - non-zero samples
62  // 3 - all samples
63  int dbg = 1;
64  Index iman = 0;
65  const AdcChannelDataMap& data = *tpd.getAdcData()[0];
66  for ( auto& ent : data ) {
67  const AdcSignalVector& sams = ent.second.samples;
68  Index nsam = sams.size();
69  Index icha = ent.first;
70  string scha = std::to_string(icha);
71  string slab = roinam.size() ? roinam : "ADC";
72  if ( dbg > 0 ) cout << myname << slab << " sample count is " << nsam << " for channel "
73  << icha << endl;
74  TPadManipulator* pman = topman.man(iman);
75  if ( pman == nullptr ) {
76  cout << myname << "ERROR: Unable to find subpad " << iman << endl;
77  return 2;
78  }
79  ++iman;
80  Name hnam = "hch" + scha;
81  Name httl = "Channel " + scha + ";Tick;Charge";
82  TH1* ph = new TH1F(hnam.c_str(), httl.c_str(), nsam, 0, nsam);
83  ph->SetDirectory(nullptr);
84  ph->SetStats(0);
85  ph->SetLineColor(col);
86  ph->SetLineWidth(lwid);
87  ph->SetLineStyle(lsty);
88  if ( roinam.size() ) {
89  assert(tpd.getTpcData(roinam) != nullptr );
90  const TpcData::Tpc2dRoiVector& rois = tpd.getTpcData(roinam)->get2dRois();
91  assert( rois.size() == 1 );
92  const Tpc2dRoi& roi = rois[0];
93  assert( roi.sampleSize() == nsam );
94  for ( Index isam=0; isam<nsam; ++isam ) {
95  float val = roi.value(icha, isam);
96  if ( dbg > 2 || (dbg > 1 && sams[isam]) ) {
97  cout << myname << "... " << setw(3) << isam << ": " << val << endl;
98  }
99  ph->Fill(isam+1, val);
100  }
101  } else {
102  for ( Index isam=0; isam<nsam; ++isam ) {
103  if ( dbg > 2 || (dbg > 1 && sams[isam]) ) {
104  cout << myname << "... " << setw(3) << isam << ": " << sams[isam] << endl;
105  }
106  ph->Fill(isam+1, sams[isam]);
107  }
108  }
109  if ( nsam > 0 ) {
110  pman->add(ph, dopt);
111  pman->setGridY();
112  pman->setRangeY(ymin, ymax);
113  }
114  }
115  dopt = "HIST SAME";
116  //pcan->cd();
117  //ph->Draw(dopt.c_str());
118  return 0;
119  }
120  int print(Name fname) {
121  string myname = "Plot::print: ";
122  topman.draw();
123  //cout << myname << "Printing " << fname << endl;
124  topman.print(fname);
125  return 0;
126  }
127 };
128 
129 bool checkEqual(float x1, float x2) {
130  if ( x1 == x2 ) return true;
131  if ( x1 > 0.0 && x2 > 0.0 ) {
132  return fabs(x1-x2)/x1+x2 < 1.e-6;
133  }
134  return false;
135 }
136 
137 } // end unnamed namepsace
138 
139 //**********************************************************************
140 
141 int test_Tpc2dDeconvolute(bool useExistingFcl) {
142  const string mypre = "test_Tpc2dDeconvolute";
143  const string myname = mypre + ": ";
144 #ifdef NDEBUG
145  cout << myname << "NDEBUG must be off." << endl;
146  abort();
147 #endif
148  string line = "-----------------------------";
149 
150  cout << myname << line << endl;
151  string fclfile = "test_Tpc2dDeconvolute.fcl";
152  // Response has four bins/channels and is defined for central and first neightbor.
153  // The summed response to a unit input bin charge is 1.0 in the central for any bin
154  // and {0.5, 0.25, 0.125, 0.0625} in the neighbor from closest to furthest bin.
155  //
156  if ( ! useExistingFcl ) {
157  cout << myname << "Creating top-level FCL." << endl;
158  ofstream fout(fclfile.c_str());
159  fout << "data.response: [" << endl;
160  fout << " [0.2, 0.4, 0.3, 0.1]," << endl;
161  fout << " [-0.04, -0.08, -0.06, -0.02]," << endl;
162  fout << " [0.04, 0.08, 0.06, 0.02]" << endl;
163  fout << "]" << endl;
164  fout << "tools: {" << endl;
165  fout << " mycon: {" << endl;
166  fout << " tool_type: Adc2dConvolute" << endl;
167  fout << " LogLevel: 1" << endl;
168  fout << " ResponseVectors: @local::data.response" << endl;
169  fout << " ResponseCenter: 1" << endl;;
170  fout << " BinsPerWire: 1" << endl;;
171  fout << " BinsPerTick: 0" << endl;;
172  fout << " MinChannel: 100" << endl;;
173  fout << " MaxChannel: 104" << endl;;
174  fout << " }" << endl;
175  fout << " myroi: {" << endl;
176  fout << " tool_type: AdcToRoi2d" << endl;
177  fout << " LogLevel: 1" << endl;
178  fout << " Option: 1" << endl;
179  fout << " }" << endl;
180  fout << " mydco: {" << endl;
181  fout << " tool_type: Tpc2dDeconvolute" << endl;
182  fout << " LogLevel: 1" << endl;
183  fout << " FftSize: 1000" << endl;
184  fout << " ResponseVectors: @local::data.response" << endl;
185  fout << " ResponseCenter: 1" << endl;
186  fout << " InPath: \"conv\"" << endl;
187  fout << " OutPath: \"dcon\"" << endl;
188  fout << " SampleSigma: 2.0" << endl;
189  fout << " ChannelSigma: 0.0" << endl;
190  fout << " LowFilterPower: 0.0" << endl;
191  fout << " LowFilterWidth: 0.0" << endl;
192  fout << " }" << endl;
193  fout << "}" << endl;
194  fout.close();
195  } else {
196  cout << myname << "Using existing top-level FCL." << endl;
197  }
198 
199  cout << myname << line << endl;
200  cout << myname << "Fetching tool manager." << endl;
202  assert ( ptm != nullptr );
203  DuneToolManager& tm = *ptm;
204  tm.print();
205  assert( tm.toolNames().size() == 3 );
206 
207  cout << myname << line << endl;
208  cout << myname << "Fetching tools." << endl;
209  auto pcon = tm.getPrivate<TpcDataTool>("mycon");
210  assert( pcon != nullptr );
211  auto pdco = tm.getPrivate<TpcDataTool>("mydco");
212  assert( pdco != nullptr );
213 
214  cout << myname << line << endl;
215  cout << myname << "Create empty input data." << endl;
216  Index nsam = 60;
217  Index ncha = 5;
218  Index chan0 = 100;
219  TpcData tpd(1);
220  AdcChannelDataMap& data = *tpd.getAdcData()[0];
221  for ( Index icha=100; icha<105; ++icha ) {
222  AdcChannelData& acd = data[icha];
223  acd.setEventInfo(123, 456);
224  acd.setChannelInfo(icha);
225  acd.samples.resize(nsam, 0.0);
226  }
227  std::map<Index,float> expAreas;
228  for ( Index icha=100; icha<106; ++icha ) expAreas[icha] = 0.0;
229 
230  Index nsig = 3;
231  Index isig = 0;
232 
233  if ( isig < nsig ) {
234  cout << myname << "Add signal " << ++isig << endl;
235  float sfac = 1.0;
236  data[102].samples[20] = 100.0*sfac;
237  expAreas[100] += +20.0*sfac;
238  expAreas[101] += -20.0*sfac;
239  expAreas[102] += 100.0*sfac;
240  expAreas[103] += -20.0*sfac;
241  expAreas[104] += +20.0*sfac;
242  }
243 
244  if ( isig < nsig ) {
245  cout << myname << "Add signal " << ++isig << endl;
246  data[103].samples[10] = 100.0;
247  expAreas[101] += 20.0;
248  expAreas[102] += -20.0;
249  expAreas[103] += 100.0;
250  expAreas[104] += -20.0;
251  }
252 
253  cout << myname << line << endl;
254  cout << myname << "Check signals." << endl;
255  if ( isig < nsig ) {
256  cout << myname << "Add signal " << ++isig << endl;
257  data[101].samples[30] = 100.0;
258  expAreas[100] += -20.0;
259  expAreas[101] += 100.0;
260  expAreas[102] += -20.0;
261  expAreas[103] += 20.0;
262  }
263 
264  cout << myname << "Check signals." << endl;
265  cout << myname << "Signal count: " << nsig << endl;
266  assert( isig == nsig );
267 
268  cout << myname << line << endl;
269  string fnam = "noconvhist.png";
270  cout << myname << "Create plot " << fnam << endl;
271  Plot plt1(data.size());
272  LineColors lc;
273  plt1.addData(tpd, "", lc.green(), 2, 1);
274  plt1.setRange(0, 105);
275  plt1.print(fnam);
276 
277  cout << myname << line << endl;
278  cout << myname << "Call convolution tool." << endl;
279  DataMap ret = pcon->updateMap(data);
280  ret.print();
281  assert( ret == 0 );
282  assert( ret.getInt("responseVectorCount") == 3 );
283  assert( ret.getInt("channelMin") == 100 );
284  assert( ret.getInt("channelMax") == 104 );
285 
286  cout << myname << line << endl;
287  cout << myname << "Copy samples to ROI." << endl;
288  tpd.addTpcData("conv");
289  assert( tpd.getTpcData("conv") != nullptr );
290  assert( tpd.getTpcData("dcon") == nullptr );
291  assert( tpd.getTpcData("conv")->get2dRois().size() == 0 );
292  tpd.getTpcData("conv")->get2dRois().emplace_back(5, nsam, 100, 0);
293  assert( tpd.getTpcData("conv")->get2dRois().size() == 1 );
294  Tpc2dRoi& roi = tpd.getTpcData("conv")->get2dRois().back();
296  Index& kcha = idxs[0];
297  Index& ksam = idxs[1];
298  for ( kcha=0; kcha<ncha; ++kcha ) {
299  for ( ksam=0; ksam<nsam; ++ksam ) {
300  roi.data().setValue(idxs, data[chan0+kcha].samples[ksam]);
301  }
302  }
303  assert( tpd.getTpcData("conv")->get2dRois().size() == 1 );
304 
305  cout << myname << line << endl;
306  fnam = "convhist.png";
307  cout << myname << "Create plot " << fnam << endl;
308  Plot plt2(data.size());
309  plt2.setRange(-10, 45);
310  plt2.addData(tpd, "", lc.blue(), 2, 1);
311  plt2.addData(tpd, "conv", lc.red(), 2, 2);
312  plt2.print(fnam);
313 
314  cout << myname << line << endl;
315  cout << myname << "Check convoluted areas" << endl;
316  cout << myname << "Chan Nsam Area" << endl;
317  cout << myname << "---- ---- -----------" << endl;
318  for ( const auto& kdat : data ) {
319  Index icha = kdat.first;
320  const AdcSignalVector& sams = kdat.second.samples;
321  //assert( sams.size() == nsam );
322  float area = 0.0;
323  for ( float sam : sams ) area += sam;
324  cout << myname << setw(4) << icha << setw(6) << nsam << setw(13) << area
325  << " (" << expAreas[icha] << ")" << endl;
326  assert ( checkEqual(area, expAreas[icha]) );
327  }
328 
329  cout << myname << line << endl;
330  cout << myname << "Call deconvolution tool." << endl;
331  ret = pdco->updateTpcData(tpd);
332  ret.print();
333  assert( ret == 0 );
334  assert( ret.getInt("dcoNroiIn") == 1 );
335  assert( ret.getInt("dcoNroiOut") == 1 );
336  assert( tpd.getTpcData("conv")->get2dRois().size() == 1 );
337  assert( tpd.getTpcData("dcon")->get2dRois().size() == 1 );
338  cout << myname << "Input normalization: "
339  << tpd.getTpcData("conv")->get2dRois()[0].dft()->normalization().globalName() << ", "
340  << tpd.getTpcData("conv")->get2dRois()[0].dft()->normalization().termName() << endl;
341  cout << myname << "Output normaization: "
342  << tpd.getTpcData("dcon")->get2dRois()[0].dft()->normalization().globalName() << ", "
343  << tpd.getTpcData("dcon")->get2dRois()[0].dft()->normalization().termName() << endl;
344  assert( tpd.getTpcData("conv")->get2dRois()[0].dft()->normalization() ==
345  tpd.getTpcData("dcon")->get2dRois()[0].dft()->normalization() );
346 
347  cout << myname << line << endl;
348  fnam = "dcovhist.png";
349  cout << myname << "Create plot " << fnam << endl;
350  Plot plt3(data.size());
351  plt3.setRange(-10, 45);
352  plt3.addData(tpd, "", lc.blue(), 2, 1);
353  plt2.addData(tpd, "conv", lc.red(), 2, 2);
354  plt3.addData(tpd, "dcon", lc.orange(), 2, 3);
355  plt3.print(fnam);
356 
357  cout << myname << line << endl;
358  cout << myname << "Done." << endl;
359  return 0;
360 }
361 
362 //**********************************************************************
363 
364 int main(int argc, char* argv[]) {
365  bool useExistingFcl = false;
366  if ( argc > 1 ) {
367  string sarg(argv[1]);
368  if ( sarg == "-h" ) {
369  cout << "Usage: " << argv[0] << " [KEEPFCL [NOISE [SIGMAFIL [NSAM [SETSEED]]]]]" << endl;
370  cout << " KEEPFCL = if 1 (or true), existing FCL file is used [false]" << endl;
371  return 0;
372  }
373  useExistingFcl = sarg == "true" || sarg == "1";
374  }
375  return test_Tpc2dDeconvolute(useExistingFcl);
376 }
377 
378 //**********************************************************************
int setGridY(bool flag=true)
bool dbg
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
const std::vector< std::string > & toolNames() const
std::string string
Definition: nybbler.cc:12
struct vector vector
ChannelGroupService::Name Name
int split(Index nx, Index ny)
TpcData * addTpcData(Name nam, bool copyAdcData=true)
Definition: TpcData.cxx:24
void print() const
unsigned int Index
void print(std::ostream *pout) const
Definition: DataMap.h:245
tm
Definition: demo.py:21
bool checkEqual(string s1, string s2)
AdcDataVector & getAdcData()
Definition: TpcData.h:55
int test_Tpc2dDeconvolute(bool useExistingFcl)
void setChannelInfo(ChannelInfoPtr pchi)
DataArray::IndexArray IndexArray
Definition: Tpc2dRoi.h:25
void setEventInfo(EventInfoPtr pevi)
TPadManipulator * man(unsigned int ipad=0)
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
std::unique_ptr< T > getPrivate(std::string name)
TpcData * getTpcData(Name nam)
Definition: TpcData.cxx:42
int getInt(Name name, int def=0) const
Definition: DataMap.h:218
std::vector< Tpc2dRoi > Tpc2dRoiVector
Definition: TpcData.h:31
void line(double t, double *p, double &x, double &y, double &z)
int main(int argc, char *argv[])
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
std::map< AdcChannel, AdcChannelData > AdcChannelDataMap
int setRangeY(double y1, double y2)
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
int print(std::string fname, std::string spat="{,}")
Tpc2dRoiVector & get2dRois()
Definition: TpcData.h:57
static DuneToolManager * instance(std::string fclname="", int dbg=1)
AdcSignalVector samples
QTextStream & endl(QTextStream &s)