ExpTailPedRemover_tool.cc
Go to the documentation of this file.
1 // ExpTailPedRemover_tool.cc
2 
3 #include "ExpTailPedRemover.h"
4 #include <iostream>
5 #include <iomanip>
11 #include "TVectorD.h"
12 #include "TMatrixDSym.h"
13 #include <iomanip>
14 
15 using std::string;
16 using std::cout;
17 using std::endl;
18 using std::setw;
19 using std::copy;
20 using std::setw;
21 using std::to_string;
22 
23 using Index = unsigned int;
24 using DoubleVector = std::vector<double>;
25 
26 //**********************************************************************
27 // Class methods.
28 //**********************************************************************
29 
31 : m_LogLevel(ps.get<int>("LogLevel")),
32  m_SignalFlag(ps.get<Index>("SignalFlag")),
33  m_SignalIterationLimit(ps.get<Index>("SignalIterationLimit")),
34  m_SignalTool(ps.get<string>("SignalTool")),
35  m_DecayTime(ps.get<double>("DecayTime")) ,
36  m_MaxTick(ps.get<Index>("MaxTick")),
37  m_PedDegree(ps.get<int>("PedDegree")),
38  m_PedTick0(ps.get<Index>("PedTick0")),
39  m_PedFreqs(ps.get<FloatVector>("PedFreqs")) ,
40  m_NoWarnStatuses(ps.get<IndexVector>("NoWarnStatuses")),
41  m_IncludeChannelRanges(ps.get<NameVector>("IncludeChannelRanges")),
42  m_ExcludeChannelRanges(ps.get<NameVector>("ExcludeChannelRanges")),
43  m_useChannelRanges(false),
44  m_nowarnStatuses(m_NoWarnStatuses.begin(), m_NoWarnStatuses.end()),
45  m_pSignalTool(nullptr) {
46  const string myname = "ExpTailPedRemover::ctor: ";
47  if ( m_SignalFlag > 3 ) {
48  Index signalFlag = 2;
49  cout << myname << "WARNING: Invalid SignalFlag value " << m_SignalFlag
50  << " reset to " << signalFlag << "." << endl;
51  m_SignalFlag = signalFlag;
52  }
53  if ( m_SignalFlag >= 2 ) {
55  if ( ptm == nullptr ) {
56  cout << myname << "ERROR: Unable to retrieve tool manager." << endl;
57  } else {
59  if ( m_pSignalTool == nullptr ) {
60  cout << myname << "ERROR: Signal finding tool not found: " << m_SignalTool << endl;
61  }
62  }
63  }
64  Index nchaCheck = 0;
65  if ( m_IncludeChannelRanges.size() ) {
67  const IndexRangeTool* pcrt = ptm->getShared<IndexRangeTool>("channelRanges");
68  if ( pcrt == nullptr ) {
69  cout << myname << "ERROR: IndexRangeTool not found: channelRanges" << endl;
70  } else {
71  for ( Name crn : m_IncludeChannelRanges ) {
72  IndexRange ran = pcrt->get(crn);
73  if ( ran.isValid() ) {
74  if ( ran.end > m_checkChannels.size() ) m_checkChannels.resize(ran.end, false);
75  for ( Index icha=ran.begin; icha<ran.end; ++icha ) m_checkChannels[icha] = true;
76  } else {
77  cout << myname << "WARNING: Ignoring invalid include channel range " << crn << endl;
78  }
79  }
80  if ( m_ExcludeChannelRanges.size() ) {
81  for ( Name crn : m_ExcludeChannelRanges ) {
82  if ( crn == "all" ) {
83  m_checkChannels.clear();
84  break;
85  }
86  IndexRange ran = pcrt->get(crn);
87  if ( ran.isValid() ) {
88  Index end = ran.end < m_checkChannels.size() ? ran.end : m_checkChannels.size();
89  for ( Index icha=ran.begin; icha<end; ++icha ) m_checkChannels[icha] = false;
90  } else {
91  cout << myname << "WARNING: Ignoring invalid exclude channel range " << crn << endl;
92  }
93  }
94  }
95  m_useChannelRanges = true;
96  for ( bool keep : m_checkChannels ) if ( keep ) ++nchaCheck;
97  }
98  }
99  // Build the pedestal vectors.
100  if ( m_PedDegree > 2 ) {
101  cout << myname << "WARNING: Pedestal degree reduced from m_PedDegree to 2." << endl;
102  m_PedDegree = 2;
103  }
104  Index nped = (usePolynomial() ? m_PedDegree + 1 : 0) + 2*m_PedFreqs.size();
105  Index nfit = nped + useTail();
106  m_fitNames.resize(nfit);
107  m_fitNamesString = "{";
108  if ( nfit == 0 ) {
109  cout << myname << "WARNING: No fit parameters." << endl;
110  m_fitNamesString += "}";
111  } else if ( m_MaxTick < nfit ) {
112  cout << myname << "ERROR: MaxTick = " << m_MaxTick << " is less than nfit = " << nfit << endl;
113  m_fitNamesString += "}";
114  } else {
115  Index nsam = m_MaxTick;
116  Index ifit = 0;
117  m_pedVectors.resize(nped, FloatVector(nsam, 1.0));
119  if ( useTail() ) {
120  m_fitNames[ifit++] = "Tail";
121  m_fitNamesString += "tau0 ";
122  ++nfit;
123  }
124  if ( usePolynomial() ) {
125  m_fitNames[ifit++] = "Pedestal";
126  m_fitNamesString += "ped ";
127  ++iped;
128  if ( m_PedDegree > 0 ) {
129  FloatVector& vec = *(iped++);
130  for ( Index isam=0; isam<nsam; ++isam ) {
131  vec[isam] = float(isam) - m_PedTick0;
132  }
133  m_fitNames[ifit++] = "Slope";
134  m_fitNamesString += "slope ";
135  }
136  if ( m_PedDegree > 1 ) {
137  FloatVector& vec = *(iped++);
138  for ( Index isam=0; isam<nsam; ++isam ) {
139  float dsam = float(isam) - m_PedTick0;
140  vec[isam] = dsam*dsam;
141  }
142  m_fitNames[ifit++] = "Curvature";
143  m_fitNamesString += "curv ";
144  }
145  }
146  float twopi = 2.0*acos(-1.0);
147  for ( float frq : m_PedFreqs ) {
148  FloatVector& cvec = *(iped++);
149  FloatVector& svec = *(iped++);
150  for ( Index isam=0; isam<nsam; ++isam ) {
151  cvec[isam] = cos(twopi*frq*isam);
152  svec[isam] = sin(twopi*frq*isam);
153  }
154  m_fitNames[ifit++] = "Cos";
155  m_fitNames[ifit++] = "Sin";
156  m_fitNamesString += "cos sin ";
157  }
158  m_fitNamesString[m_fitNamesString.size()-1] = '}';
159  if ( iped != m_pedVectors.end() ) {
160  cout << myname << "ERROR: Unexpected pedestal vector size: " << m_pedVectors.size() << endl;
161  }
162  }
163  if ( m_LogLevel >= 1 ) {
164  cout << myname << "Parameters:" << endl;
165  cout << myname << " LogLevel: " << m_LogLevel << endl;
166  cout << myname << " SignalFlag: " << m_SignalFlag << endl;
167  cout << myname << " SignalIterationLimit: " << m_SignalIterationLimit << endl;
168  cout << myname << " SignalTool: " << m_SignalTool << endl;
169  cout << myname << " DecayTime: " << m_DecayTime << endl;
170  cout << myname << " MaxTick: " << m_MaxTick << endl;
171  cout << myname << " PedDegree: " << m_PedDegree << endl;
172  cout << myname << " PedTick0: " << m_PedTick0 << endl;
173  cout << myname << " PedFreqs: [";
174  bool first = true;
175  for ( float frq : m_PedFreqs ) {
176  if ( first ) first = false;
177  else cout << ", ";
178  cout << frq;
179  }
180  cout << "]" << endl;
181  cout << myname << " IncludeChannelRanges: [";
182  first = true;
183  for ( Name crn : m_IncludeChannelRanges ) {
184  if ( first ) first = false;
185  else cout << ", ";
186  cout << crn;
187  }
188  cout << "]" << endl;
189  cout << myname << " NoWarnStatuses: [";
190  first = true;
191  for ( Index ist : m_NoWarnStatuses ) {
192  if ( first ) first = false;
193  else cout << ", ";
194  cout << ist;
195  }
196  cout << "]" << endl;
197  cout << myname << " ExcludeChannelRanges: [";
198  first = true;
199  for ( Name crn : m_ExcludeChannelRanges ) {
200  if ( first ) first = false;
201  else cout << ", ";
202  cout << crn;
203  }
204  cout << "]" << endl;
205  if ( m_useChannelRanges ) {
206  cout << myname << "Channel checking enabled for " << nchaCheck << " channel"
207  << ( nchaCheck == 1 ? "" : "s") << "." << endl;
208  } else {
209  cout << myname << "Channel checking disabled." << endl;
210  cout << myname << "Fit parameters: " << m_fitNamesString << endl;
211  }
212  }
213 }
214 
215 //**********************************************************************
216 
218  const string myname = "ExpTailPedRemover::update: ";
219  string mychan = myname + " Channel " + to_string(acd.channel()) + ": ";
220  DataMap ret;
221 
222  // Save the data before tail removal.
223  AdcSignalVector samples = acd.samples;
224  Index nsam = samples.size();
225  string sampleUnit = acd.sampleUnit;
226 
227  // Check the channel.
228  if ( m_useChannelRanges ) {
229  if ( acd.channel() >= m_checkChannels.size() || ! m_checkChannels[acd.channel()] ) {
230  if ( m_LogLevel >= 2 ) cout << myname << "Skipping channel " << acd.channel() << endl;
231  return ret;
232  }
233  }
234 
235  // Check input data size.
236  Index ntai = useTail(); // # tail parameters
237  Index nped = m_pedVectors.size(); // # pedestal parameters
238  Index ncof = ntai + nped; // # fitted parameters
239  if ( nsam < ncof ) {
240  cout << myname << "WARNING: Data for channel " << acd.channel() << " has "
241  << ( nsam==0 ? "no" : "too few" ) << " ticks: " << nsam << " < " << ncof << endl;
242  return ret.setStatus(1);
243  }
244  if ( nsam > m_MaxTick ) {
245  cout << myname << "WARNING: Data for channel " << acd.channel() << " has too many ticks:"
246  << nsam << " > " << m_MaxTick << ". Please increase MaxTick." << endl;
247  return ret.setStatus(1);
248  }
249 
250  if ( m_LogLevel >= 3 ) cout << myname << "Correcting run " << acd.run() << " event " << acd.event()
251  << " channel " << acd.channel() << endl;
252 
253  // Set flag indicating if signal should be found each iteration.
254  // If not, check that signal is already found.
255  bool checkSignalDefault = true; // Whether to use only non-signal in fit.
256  bool findSignal = false; // Whether to find signals each iteration.
257  if ( m_SignalFlag == 0 ) {
258  checkSignalDefault = false;
259  } else if ( m_SignalFlag == 1 ) {
260  if ( acd.signal.size() < nsam ) {
261  cout << mychan << "WARNING: Data is missing signal flags--padding from " << acd.signal.size()
262  << " to " << nsam << " samples." << endl;
263  }
264  } else if ( m_SignalFlag >= 2 ) {
265  if ( m_pSignalTool == nullptr ) {
266  cout << mychan << "WARNING: Signal-finding tool is missing. Using all signals." << endl;
267  checkSignalDefault = false;
268  } else {
269  findSignal = true;
270  }
271  }
272 
273  // Iterate over fits based on background samples.
274  // Loop ends when the signal selection does not change or the maximumc # loops is reached.
275  Index niter = 0; // # fit iterations
276  FloatVector cofs(ncof, 0); // {tau0, lam1, lam2, ...} (ped = lam1)
277  Index nsamFit = 0;
278  Index maxiter = findSignal ? m_SignalIterationLimit : 1;
279  double noise = 0.0;
280  while ( niter < maxiter ) {
281  // Do signal finding.
282  if ( findSignal ) {
283  AdcFilterVector signalLast = acd.signal;
284  DataMap fret = m_pSignalTool->update(acd);
285  if ( fret ) {
286  cout << myname << "WARNING: Signal-finding failed for event " << acd.event()
287  << " channel " << acd.channel() << endl;
288  break;
289  }
290  if ( acd.signal == signalLast && niter > 0 ) {
291  if ( m_LogLevel >=3 ) cout << mychan << "Signal is unchanged. Exiting loop." << endl;
292  break;
293  }
294  }
295  // Check that we have enough background to evaluate tau and the pedestal params.
296  bool checkSignal = checkSignalDefault;
297  if ( checkSignal ) {
298  Index nchk = 0;
299  for ( Index isam=0; isam<nsam; ++isam ) {
300  if ( isam < acd.signal.size() && acd.signal[isam] ) continue;
301  if ( ++nchk >= ncof ) break;
302  }
303  if ( nchk < ncof ) {
304  Index cstat = acd.channelStatus();
305  string sstat = cstat==0 ? "Good" : cstat==1 ? "Bad" : cstat==2 ? "Noisy" : "Unknown";
306  bool dowarn = m_nowarnStatuses.count(cstat) == 0;
307  if ( dowarn ) cout << myname << "WARNING: " << sstat << " channel " << acd.channel()
308  << ": Not-signal sample count of " << nchk
309  << " is not sufficient to evaluate the " << ncof << " fit parameters.";
310  if ( niter == 0 ) {
311  if ( dowarn ) cout << " Using all samples." << endl;
312  checkSignal = false;
313  } else {
314  if ( dowarn ) cout << " Exiting loop." << endl;;
315  break;
316  }
317  }
318  }
319  // Evaluate the signal coefficients (C_iM in DUNE-doc-20618).
320  using DoubleVector = std::vector<double>;
321  using DoubleVectorVector = std::vector<DoubleVector>;
322  DoubleVectorVector cofvecs(ncof, DoubleVector(nsam, 0.0)); // [Ctau], Clam1, Clam2, ...
324  if ( ! useTail() ) sta.setBeta(1.0, true);
325  if ( ! sta.isValid() ) {
326  cout << mychan << "ERROR: SampleTailer is invalid. Exiting." << endl;
327  break;
328  }
329  Index icof = 0;
330  // Tail coefficient.
331  if ( useTail() ) {
332  sta.setTail0(1.0);
333  sta.setPedestal(0.0);
334  sta.setDataZero(nsam);
335  DoubleVector& ctau = cofvecs[icof++];
336  copy(sta.signal().begin(), sta.signal().end(), ctau.begin());
337  }
338  // Pedestal coefficients.
339  for ( Index iped=0; iped<nped; ++iped ) {
340  sta.setTail0(0.0);
341  sta.setPedestalVector(&m_pedVectors[iped]);
342  sta.setDataZero(nsam);
343  DoubleVector& cped = cofvecs[icof++];
344  copy(sta.signal().begin(), sta.signal().end(), cped.begin());
345  }
346  // Data coefficient.
347  sta.setTail0(0.0);
348  sta.setPedestal(0.0);
349  sta.setData(samples);
350  DoubleVector cdat(nsam);
351  copy(sta.signal().begin(), sta.signal().end(), cdat.begin());
352  // Evaluate the K-params (K_MN in DUNE-doc-20618).
353  TMatrixDSym kmat(ncof);
354  TVectorD kvec(ncof);
355  nsamFit = 0;
356  for ( Index isam=0; isam<nsam; ++isam ) {
357  if ( checkSignal && isam < acd.signal.size() && acd.signal[isam] ) continue;
358  double cd = cdat[isam];
359  for ( icof=0; icof<ncof; ++icof ) {
360  double ci = cofvecs[icof][isam];
361  kvec[icof] += cd*ci;
362  for ( Index jcof=0; jcof<=icof; ++jcof ) {
363  double cj = cofvecs[jcof][isam];
364  kmat[icof][jcof] += ci*cj;
365  }
366  }
367  ++nsamFit;
368  }
369  // TMatrixDSym must be symmetrized!
370  for ( icof=0; icof<ncof; ++icof ) {
371  for ( Index jcof=0; jcof<icof; ++jcof ) {
372  kmat[jcof][icof] = kmat[icof][jcof];
373  }
374  }
375  // Invert matrix and solve for [tau], {ped}.
376  double det = 0.0;
377  kmat.Invert(&det);
378  if ( ! kmat.IsValid() || det == 0.0 ) {
379  if ( m_nowarnStatuses.count(acd.channelStatus()) == 0 ) {
380  cout << myname << "WARNING: Channel " << acd.channel() << ": Unable to invert K-matrix with "
381  << nsamFit << " of " << nsam << " samples--stopping iteration for channel "
382  << acd.channel() << " with status " << acd.channelStatus() << "." << endl;
383  for ( icof=0; icof<ncof; ++icof ) {
384  cout << mychan;
385  for ( Index jcof=0; jcof<ncof; ++jcof ) {
386  cout << setw(20) << kmat[icof][jcof];
387  }
388  cout << endl;
389  }
390  }
391  break;
392  }
393  kvec *= kmat;
394  kvec *= -1.0; // kvec now holds the fitted coefficients {tau, lam1, lam2, ...}
395  for ( icof=0; icof<ncof; ++icof ) {
396  cofs[icof] = kvec[icof];
397  }
398  // Use the parameters to remove tail and pedestal from the original data and store
399  // these subtracted samples in the channel data.
400  float tau = useTail() ? cofs[0] : 0.0;
401  FloatVector peds(nsam, 0.0);
402  icof = ntai;
403  for ( Index iped=0; iped<nped; ++iped ) {
404  for ( Index isam=0; isam<nsam; ++isam ) {
405  peds[isam] += cofs[icof]*m_pedVectors[iped][isam];
406  }
407  ++icof;
408  }
409  sta.setTail0(tau);
410  sta.setPedestalVector(&peds);
411  sta.setData(samples);
412  acd.samples = sta.signal();
413  // Evaluate the non-signal rms.
414  double sumsq = 0.0;
415  for ( Index isam=0; isam<nsam; ++isam ) {
416  if ( checkSignal && isam < acd.signal.size() && acd.signal[isam] ) continue;
417  double sig = sta.signal()[isam];
418  sumsq += sig*sig;
419  }
420  Index ndof = nsamFit > ncof ? nsamFit - ncof : 1;
421  noise = sqrt(sumsq/ndof);
422  // Update iteration count.
423  if ( m_LogLevel >= 3 ) {
424  cout << mychan << "Iteration " << niter << ": nsamfit=" << nsamFit
425  << ", noise=" << noise << "; " << m_fitNamesString << ": {";
426  bool first = true;
427  for ( float cof : cofs ) {
428  if ( first ) first = false;
429  else cout << ", ";
430  cout << cof;
431  }
432  cout << "}" << endl;
433  }
434  ++niter;
435  }
436 
437  // Log result of interation.
438  if ( m_LogLevel >= 2 ) {
439  cout << mychan << "Iteration count: " << niter << endl;
440  cout << mychan << "Noise: " << noise;
441  if ( sampleUnit.size() ) cout << " " << sampleUnit;
442  cout << " from " << nsamFit << "/" << nsam << " samples" << endl;
443  cout << mychan << "Final " << m_fitNamesString << ": {";
444  bool first = true;
445  for ( float cof : cofs ) {
446  if ( first ) first = false;
447  else cout << ", ";
448  cout << cof;
449  }
450  cout << "}" << endl;
451  }
452 
453  // Use the fitted
454  acd.metadata["uscPedestal"] = cofs[1];
455  acd.metadata["uscTail"] = cofs[0];
456  acd.metadata["uscNoise"] = noise;
457  for ( Index icof=0; icof<cofs.size(); ++icof ) {
458  Name name = "usc" + m_fitNames[icof];
459  ret.setFloat(name, cofs[icof]);
460  }
461  ret.setFloat("uscNoise", noise);
462  ret.setInt("uscNsamFit", nsamFit);
463  ret.setInt("uscNiteration", niter);
464 
465  return ret;
466 }
467 
468 //**********************************************************************
469 
static QCString name
Definition: declinfo.cpp:673
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
intermediate_table::iterator iterator
ExpTailPedRemover(fhicl::ParameterSet const &ps)
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
bool isValid() const
Definition: SampleTailer.h:80
int setData(const FloatVector &inData)
bool usePolynomial() const
unsigned int Index
IndexVector m_NoWarnStatuses
std::string string
Definition: nybbler.cc:12
Index begin
Definition: IndexRange.h:34
unsigned int Index
bool isValid() const
Definition: IndexRange.h:94
NameVector m_ExcludeChannelRanges
Index end
Definition: IndexRange.h:35
virtual DataMap update(AdcChannelData &) const
int setPedestal(float val)
bool useTail() const
std::vector< double > DoubleVector
int setBeta(float val, bool cancelSignal)
const FloatVector & signal() const
Definition: SampleTailer.h:90
AdcIndex run() const
std::vector< double > DoubleVector
Definition: fcldump.cxx:27
AdcChannelTool * m_pSignalTool
AdcIndex event() const
static constexpr double ps
Definition: Units.h:99
int setTail0(float val)
std::vector< Index > IndexVector
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
int setPedestalVector(const FloatVector *pval)
int twopi
Definition: units.py:12
Index channelStatus() const
Channel channel() const
std::vector< bool > m_checkChannels
AdcFilterVector signal
std::vector< bool > AdcFilterVector
Definition: AdcTypes.h:27
FloatVectorVector m_pedVectors
std::vector< Name > NameVector
T copy(T const &v)
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
DataMap update(AdcChannelData &acd) const override
NameVector m_IncludeChannelRanges
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
static DuneToolManager * instance(std::string fclname="", int dbg=1)
AdcSignalVector samples
T * getShared(std::string name)
QTextStream & endl(QTextStream &s)
std::vector< float > FloatVector
virtual IndexRange get(Name nam) const =0
int setDataZero(Index nsam)