Tpc2dDeconvolute_tool.cc
Go to the documentation of this file.
1 // Tpc2dDeconvolute_tool.cc
2 
3 #include "Tpc2dDeconvolute.h"
4 #include "TMath.h"
5 #include <iostream>
6 #include <iomanip>
7 #include <sstream>
8 
9 using std::string;
10 using std::cout;
11 using std::endl;
12 using std::setw;
13 using std::fixed;
14 using std::setprecision;
15 using std::ostringstream;
16 
17 using Index = unsigned int;
20 using DoubleVector = std::vector<double>;
21 using DoubleVectorMap = std::map<Index, DoubleVector>;
22 using Name = std::string;
25 
26 namespace {
27 
28 // Complex to string: mag@thtdeg
29 string comstr(Tpc2dRoi::Dft::Complex val) {
30  float mag = std::abs(val);
31  float tht = 180/acos(-1.0)*std::arg(val);
32  ostringstream ssout;
33  if ( mag > 0.01 ) {
34  ssout.setf(std::ios::fixed);
35  ssout.precision(3);
36  }
37  ssout << "(" << mag << "@" << setw(4) << int(tht) << ")";
38  return ssout.str();
39 }
40 
41 } // end unnamed namespace
42 
43 //**********************************************************************
44 // Class methods.
45 //**********************************************************************
46 
48 : m_LogLevel(ps.get<int>("LogLevel")),
49  m_ResponseVectors(ps.get<ResponseVectorVector>("ResponseVectors")),
50  m_ResponseCenter(ps.get<int>("ResponseCenter")),
51  m_FftSize(ps.get<Index>("FftSize")),
52  m_InPath(ps.get<Name>("InPath")),
53  m_OutPath(ps.get<Name>("OutPath")),
54  m_SampleSigma(ps.get<float>("SampleSigma")),
55  m_ChannelSigma(ps.get<float>("ChannelSigma")),
56  m_LowFilterWidth(ps.get<float>("LowFilterWidth")),
57  m_LowFilterPower(ps.get<float>("LowFilterPower")),
58  m_pfft(new Fw2dFFT(m_FftSize, 1)) {
59  const string myname = "Tpc2dDeconvolute::ctor: ";
60  if ( m_LogLevel >= 1 ) {
61  std::ios cout_state(nullptr);
62  cout_state.copyfmt(std::cout);
63  cout << myname << "Parameters:" << endl;
64  cout << myname << " LogLevel: " << m_LogLevel << endl;
65  cout << myname << " ResponseVectors: [";
66  Index indent = 22;
67  bool first = true;
68  for ( const ResponseVector& vec : m_ResponseVectors ) {
69  if ( first ) first = false;
70  else cout << ", ";
71  for ( Index isam=0; isam<vec.size(); ++isam ) {
72  float val = vec[isam];
73  if ( isam != 0 ) cout << ", ";
74  if ( isam == 0 ) cout << "\n" << myname << setw(indent) << "[";
75  else if ( 10*(isam/10) == isam ) cout << "\n" << myname << setw(indent) << " ";
76  cout << setw(11) << fixed << setprecision(7) << val;
77  }
78  cout << "]";
79  }
80  cout << endl;
81  cout << myname << setw(indent-2) << "]" << endl;
82  cout << myname << " ResponseCenter: " << m_ResponseCenter << endl;
83  cout << myname << " FftSize: " << m_FftSize << endl;
84  cout << myname << " InPath: " << m_InPath << endl;
85  cout << myname << " OutPath: " << m_OutPath << endl;
86  cout << myname << " SampleSigma: " << m_SampleSigma << endl;
87  cout << myname << " ChannelSigma: " << m_ChannelSigma << endl;
88  cout << myname << " LowFilterPower: " << m_LowFilterPower << endl;
89  cout << myname << " LowFilterWidth: " << m_LowFilterWidth << endl;
90  }
91 }
92 
93 //**********************************************************************
94 
96  const string myname = "Tpc2dDeconvolute::updateTpcData: ";
97  DataMap ret;
98  // Find input data.
99  TpcData* ptpdIn = tpd.getTpcData(m_InPath);
100  if ( ptpdIn == nullptr ) {
101  cout << myname << "WARNING: Input TPC data not found at " << m_InPath << "." << endl;
102  return ret.setStatus(1);
103  }
104  TpcData::Tpc2dRoiVector& inrois = ptpdIn->get2dRois();
105  // Create output data object.
106  TpcData::Tpc2dRoiVector* poutrois = nullptr;
107  if ( m_OutPath.size() && m_OutPath != "." ) {
108  TpcData* ptpdOut = tpd.getTpcData(m_OutPath);
109  if ( ptpdOut == nullptr ) {
110  if ( m_LogLevel >= 2 ) {
111  cout << myname << "Adding data path " << m_OutPath << "." << endl;
112  }
113  ptpdOut = tpd.addTpcData(m_OutPath);
114  if ( ptpdOut == nullptr ) {
115  cout << myname << "ERROR: Unable to create output TPC data at " << m_OutPath << "." << endl;
116  return ret.setStatus(2);
117  }
118  }
119  poutrois = &ptpdOut->get2dRois();
120  if ( poutrois->size() ) {
121  // Might want to add config flag to disable this message.
122  cout << myname << "WARNING: Output 2D ROI container is not empty." << endl;
123  }
124  }
125  // Define DFT normalization.
126  RealDftNormalization dftNorm(12);
127  // Loop over 2d ROIs.
128  Index xflog = 0;
129  Index nroi = 0;
130  for ( Tpc2dRoi& roi : inrois ) {
131  // Check fft size.
132  Index ncha = roi.channelSize();
133  Index nsam = roi.sampleSize();
134  IndexArray ndxs = {ncha, nsam};
135  if ( fft().checkDataSize(ndxs) ) {
136  cout << myname << "ERROR: Skipping too-large 2D ROI: " << ncha << " x " << nsam << endl;
137  continue;
138  }
139  // Get ROI DFT.
140  if ( roi.dft() == nullptr ) {
141  const RealData& rdat = roi.data();
142  DftData* pdft = new DftData(dftNorm, ndxs);
143  fft().fftForward(rdat, *pdft, xflog);
144  roi.resetDft(pdft);
145  }
146  if ( roi.dft() == nullptr ) {
147  cout << myname << "ERROR: Forward FFT of ROI failed." << endl;
148  continue;
149  }
150  DftData& roiDft = *roi.dft();
151  // Build ncha x nsam response matrix.
152  RealData resDat(ndxs);
154  // ... Response is periodic. Choose tick offset in first period.
155  // ... Response is symmetric in channel.
156  int nsamInt = nsam;
157  int samoffInt = m_ResponseCenter;
158  while ( samoffInt < 0 ) samoffInt += nsamInt;
159  while ( samoffInt >= nsamInt ) samoffInt -= nsamInt;
160  Index samoff = samoffInt;
161  for ( Index dcha1=0; dcha1<(ncha+1)/2; ++dcha1 ) {
162  const ResponseVector& res1d =
163  dcha1 < m_ResponseVectors.size() ? m_ResponseVectors[dcha1] : empty;
164  IndexVector dchas(1, dcha1);
165  if ( dcha1 ) {
166  Index dcha2 = ncha - dcha1;
167  if ( dcha2 != dcha1 ) dchas.push_back(dcha2);
168  }
169  for ( Index dsam=0; dsam<nsam; ++dsam ) {
170  Index isam = dsam + samoff;
171  if ( isam >= nsam ) isam -= nsam;
172  float rval = isam < res1d.size() ? res1d[isam] : 0.0;
173  for ( Index dcha : dchas ) {
174  IndexArray idxs = {dcha, dsam};
175  Index idat = resDat.setValue(idxs, rval);
176  if ( m_LogLevel >= 3 ) {
177  cout << myname << " res[" << dcha << ", " << dsam << "]: " << rval << endl;
178  }
179  // This shouldn't happen...
180  if ( idat >= resDat.size() ) {
181  cout << myname << "ERROR: Unexpected invalid response indices." << endl;
182  }
183  }
184  }
185  }
186  // Get response DFT.
188  DftData resDft(respNorm, ndxs);
189  fft().fftForward(resDat, resDft, xflog);
190  // Build sample filter.
191  // User supplies Gaussian sigma in sample (tick). Xform is a Gaussian
192  // with sigma_freq = Nsam/(2 pi sigma_time).
193  std::vector<double> samFilt(nsam, 1.0);
194  if ( m_SampleSigma > 0.0 ) {
195  float freqSigma = nsam/(2.0*acos(-1.0)*m_SampleSigma);
196  for ( Index ifrq=0; ifrq<nsam; ++ifrq ) {
197  float xf = ifrq/freqSigma;
198  float fac = exp(-xf*xf/2.0);
199  samFilt[ifrq] = fac;
200  if ( m_LogLevel >= 3 ) cout << myname << " samfil[" << ifrq << "]: " << fac << endl;
201  }
202  }
203  // Build channel filter.
204  // User supplies Gaussian sigma in channel. Xform is a Gaussian
205  // with sigma_freq = Ncha/(2 pi sigma_time).
206  std::vector<double> chaFilt(ncha, 1.0);
207  if ( m_ChannelSigma > 0.0 ) {
208  float freqSigma = nsam/(2.0*acos(-1.0)*m_ChannelSigma);
209  for ( Index ifrq=0; ifrq<ncha; ++ifrq ) {
210  float xf = ifrq/freqSigma;
211  float fac = exp(-xf*xf/2.0);
212  chaFilt[ifrq] = fac;
213  if ( m_LogLevel >= 3 ) cout << myname << " chafil[" << ifrq << "]: " << fac << endl;
214  }
215  }
216  std::vector<double> samFiltLow(nsam, 1.0);
217  if ( m_LowFilterPower > 0 ) {
218  if ( m_LowFilterWidth == 0.0 ) {
219  samFiltLow[0] = 0.0;
220  } else {
221  samFiltLow[0] = 0.0;
222  double fac = nsam/m_LowFilterWidth;
223  for ( Index ifrq=1; ifrq<nsam; ++ifrq ) {
224  double arg = pow(fac/ifrq, m_LowFilterPower);
225  samFiltLow[ifrq] = 1.0/(1.0 + arg);
226  }
227  }
228  }
229  // Evaluate deconvoluted DFT.
230  // Copy the input ROI DFT, multiply by filter and divide by response.
231  DftData* poutDft = new DftData(roiDft);
232  bool logEntry = m_LogLevel>=4;
233  for ( Index idat=0; idat<poutDft->size(); ++idat ) {
234  auto idxs = poutDft->indexArrays(idat);
235  Index dcha = idxs[0][0];
236  Index dsam = idxs[0][1];
237  Tpc2dRoi::Dft::Complex& val = poutDft->data()[idat];
238  // For the filters, use the smaller of the wave number and its conjugate.
239  Index dchaFilt = std::min(dcha, ncha-dcha);
240  Index dsamFilt = std::min(dsam, nsam-dsam);
241  if ( logEntry ) {
242  cout << myname << "Decon[" << dcha << "," << dsam << "]";
243  cout << "[" << dchaFilt << "," << dsamFilt << "]";
244  cout << ": " << comstr(val);
245  }
246  val *= chaFilt[dchaFilt];
247  val *= samFilt[dsamFilt];
248  val *= samFiltLow[dsamFilt];
249  Tpc2dRoi::Dft::Complex resp = resDft.data()[idat];
250  if ( resp != 0.0 ) val /= resp;
251  if ( logEntry ) {
252  cout << " * " << chaFilt[dchaFilt];
253  cout << " * " << samFilt[dsamFilt];
254  cout << " / " << comstr(resp) << " = " << comstr(val) << endl;
255  }
256  }
257  if ( m_LogLevel >=3 ) {
258  cout << myname << " Input power: " << roiDft.power() << endl;
259  cout << myname << "Response power: " << resDft.power() << endl;
260  cout << myname << " Output power: " << poutDft->power() << endl;
261  }
262  // Create the output ROI and attach the DFT data.
263  Tpc2dRoi* poutroi = &roi;
264  if ( poutrois != nullptr ) {
265  poutrois->emplace_back(ncha, nsam, roi.channelOffset(), roi.sampleOffset());
266  poutroi = &poutrois->back();
267  }
268  poutroi->resetDft(poutDft);
269  // Evaluate deconvoluted reponse.
270  int dstat = fft().fftBackward(*poutroi->dft(), poutroi->data());
271  if ( dstat ) {
272  cout << myname << "ERROR: Reverse xform failed with error " << dstat << endl;
273  continue;
274  }
275  ++nroi;
276  }
277  ret.setInt("dcoNroiIn", inrois.size());
278  ret.setInt("dcoNroiOut", nroi);
279  return ret;
280 }
281 
282 //**********************************************************************
283 
285  const string myname = "Tpc2dDeconvolute::updateTpcData: ";
286  cout << myname << "ERROR: View of TPC data is not supported here." << endl;
287  DataMap ret;
288  return ret.setStatus(1);
289 }
290 
291 //**********************************************************************
292 
294  return *m_pfft;
295 }
296 
297 //**********************************************************************
std::map< Index, DoubleVector > DoubleVectorMap
const std::vector< F > & data() const
Definition: Real2dData.h:117
int fftForward(const Data &dat, DFT &dft, Index logLevel=0)
Definition: Fw2dFFT.cxx:93
DFT::IndexArray IndexArray
Definition: Fw2dFFT.h:39
unsigned int Index
DataMap & setStatus(int stat)
Definition: DataMap.h:130
std::string string
Definition: nybbler.cc:12
IndexArrayVector indexArrays(Index idat) const
constexpr T pow(T x)
Definition: pow.h:72
ChannelGroupService::Name Name
TpcData * addTpcData(Name nam, bool copyAdcData=true)
Definition: TpcData.cxx:24
DftData::IndexArray IndexArray
unsigned int Index
Q_EXPORT QTSManip setprecision(int p)
Definition: qtextstream.h:343
static RealDftNormalization convolutionNormalization()
std::vector< Index > IndexVector
int fftBackward(const DFT &dft, Data &dat, Index logLevel=0)
Definition: Fw2dFFT.cxx:123
std::vector< ResponseVector > ResponseVectorVector
T abs(T value)
Fw2dFFT & fft() const
DataMap viewTpcData(const TpcData &) const override
Index size(Index idim) const
Definition: Real2dData.h:91
Tpc2dRoi::Dft DftData
void resetDft(Dft *pdft)
Definition: Tpc2dRoi.h:73
ResponseVectorVector m_ResponseVectors
void setInt(Name name, int val)
Definition: DataMap.h:131
std::vector< double > DoubleVector
Definition: fcldump.cxx:27
static constexpr double ps
Definition: Units.h:99
Tpc2dDeconvolute(fhicl::ParameterSet const &ps)
Index size() const
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
std::complex< Float > Complex
Definition: Real2dDftData.h:29
TpcData * getTpcData(Name nam)
Definition: TpcData.cxx:42
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
std::vector< Tpc2dRoi > Tpc2dRoiVector
Definition: TpcData.h:31
AdcSignalVector ResponseVector
const DataArray & data() const
Definition: Tpc2dRoi.h:50
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
Dft::FloatVector FloatVector
virtual F power(const IndexArray &ifrqs) const
Definition: Real2dDftData.h:91
std::unique_ptr< Fw2dFFT > m_pfft
FftwDouble2dDftData Dft
Definition: Tpc2dRoi.h:26
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
Index setValue(const IndexArray &isams, Float val, Index *pchk=nullptr)
Definition: Real2dData.h:197
Tpc2dRoiVector & get2dRois()
Definition: TpcData.h:57
DataMap updateTpcData(TpcData &) const override
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
QTextStream & endl(QTextStream &s)
Real2dData< float > DataArray
Definition: Tpc2dRoi.h:24
Dft * dft()
Definition: Tpc2dRoi.h:68