npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
ConvolutionEngine1D.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_CONVOLUTIONENGINE1D_HH_
2 #define NPSTAT_CONVOLUTIONENGINE1D_HH_
3 
4 /*!
5 // \file ConvolutionEngine1D.hh
6 //
7 // \brief Fast one-dimensional convolutions via Fourier
8 // transforms (FFTW interface)
9 //
10 // Author: I. Volobouev
11 //
12 // November 2009
13 */
14 
15 #include <map>
16 
18 #include "npstat/nm/ArrayND.hh"
19 
20 #ifdef SWIG
21 #include "npstat/wrap/arrayNDToNumpy.hh"
22 #include "npstat/wrap/numpyArrayUtils.hh"
23 #endif // SWIG
24 
25 namespace npstat {
26  /**
27  // Class for performing convolutions by FFT using FFTW library.
28  // Internally, transforms are calculated in double precision.
29  */
31  {
32  public:
33  /**
34  // Constructor takes data length and FFTW optimization flag
35  // as parameters. Make sure the data length is sufficient
36  // to avoid the convolution wrap-around.
37  */
38  explicit ConvolutionEngine1D(unsigned dataLen,
39  unsigned optimization = FFTW_ESTIMATE);
41 
42  /**
43  // Provide the filter for subsequent convolutions.
44  //
45  // The "shift" argument allows you to rotate the filter data
46  // buffer so that the element with index "shift" becomes new
47  // element with index 0 (essentially, the buffer is rotated
48  // left by "shift" elements).
49  */
50  template <typename Real>
51  void setFilter(const Real* data, unsigned dataLen, unsigned shift=0);
52 
53  /**
54  // Provide the filter for subsequent convolutions using its
55  // Fourier space representation
56  */
57  void setFilterImage(const std::complex<double>* image, unsigned imLen);
58 
59  /**
60  // Convolve provided data with the filter previously established
61  // by setFilter.
62  //
63  // The "shift" argument allows you to rotate the input data
64  // buffer so that the element with index "shift" becomes new
65  // element with index 0 (essentially, the buffer is rotated
66  // left by "shift" elements).
67  */
68  template <typename Real1, typename Real2>
69  void convolveWithFilter(const Real1* in, Real2* out, unsigned dataLen,
70  unsigned shift=0);
71 
72  /** Deconvolve the input using the previously established filter */
73  template <typename Real1, typename Real2>
74  void deconvolveFilter(const Real1* in, Real2* out, unsigned dataLen,
75  unsigned shift=0);
76 
77  /**
78  // Provide a filter for subsequent convolutions.
79  //
80  // The "shift" argument allows you to rotate the filter data
81  // buffer so that the element with index "shift" becomes new
82  // element with index 0 (essentially, the buffer is rotated
83  // left by "shift" elements).
84  //
85  // "id" is the user id for the filter which can be later reused
86  // with the method "convolveWithDeposit".
87  */
88  template <typename Real>
89  void depositFilter(unsigned long id,
90  const Real* data, unsigned dataLen,
91  unsigned shift=0);
92 
93  /**
94  // Provide a filter for subsequent convolutions using its
95  // Fourier space representation
96  //
97  // "id" is the user id for the filter which can be later reused
98  // with the method "convolveWithDeposit".
99  */
100  void depositFilterImage(unsigned long id,
101  const std::complex<double>* image, unsigned imLen);
102 
103  /**
104  // Convolve provided data with one of the filters previously
105  // established by the depositFilter method. The "id" argument
106  // is used to identify a particular filter.
107  //
108  // The "shift" argument allows you to rotate the input data
109  // buffer so that the element with index "shift" becomes new
110  // element with index 0 (essentially, the buffer is rotated
111  // left by "shift" elements).
112  */
113  template <typename Real1, typename Real2>
114  void convolveWithDeposit(unsigned long id,
115  const Real1* in, Real2* out, unsigned dataLen,
116  unsigned shift=0);
117 
118  /** Deconvolve the data with a previously deposited filter */
119  template <typename Real1, typename Real2>
120  void deconvolveDeposit(unsigned long id,
121  const Real1* in, Real2* out, unsigned dataLen,
122  unsigned shift=0);
123 
124  /**
125  // Convolve the filter established by the "setFilter" method
126  // with a previously deposited filter
127  */
128  template <typename Real2>
129  void convolveFilterAndDeposit(unsigned long id,
130  Real2* out, unsigned dataLen);
131 
132  /**
133  // Deconvolve the filter established by the "setFilter" method
134  // with a previously deposited filter
135  */
136  template <typename Real2>
137  void deconvolveFilterAndDeposit(unsigned long id,
138  Real2* out, unsigned dataLen);
139 
140  /**
141  // Discard a filter previously deposited by "depositFilter" method.
142  // This method returns "true" if the filter with the given id
143  // was indeed discarded and "false" if such a filter was not found.
144  */
145  bool discardFilter(unsigned long id);
146 
147  /** Discard all filters deposited by "depositFilter" method */
149 
150  /** Expected data length */
151  inline unsigned dataLength() const {return dataLen_;}
152 
153  /** Expected image length */
154  inline unsigned imageLength() const {return dataLen_/2 + 1;}
155 
156  // Some accessors
157  inline bool isFilterSet() const {return validFilter_;}
158  inline unsigned filterBankSize() const {return filterMap_.size();}
159 
160  private:
161  typedef std::map<unsigned long,FourierImage*> FilterMap;
162 
164  ConvolutionEngine1D(const ConvolutionEngine1D&);
165  ConvolutionEngine1D& operator=(const ConvolutionEngine1D&);
166 
167  template <typename Real1, typename Real2>
168  void convolveWithImage(const fftw_complex* image,
169  const Real1* in, Real2* out, unsigned dataLen,
170  unsigned shift);
171 
172  template <typename Real1, typename Real2>
173  void deconvolveImage(const fftw_complex* image,
174  const Real1* in, Real2* out, unsigned dataLen,
175  unsigned shift);
176  fftw_plan pf;
177  fftw_plan pb;
178 
179  double* in;
180  fftw_complex* out;
181  fftw_complex* filterImage;
182 
183  unsigned dataLen_;
184  bool validFilter_;
185 
186  FilterMap filterMap_;
187 
188 #ifdef SWIG
189  public:
190  inline void setFilter2(PyObject* input, unsigned shift=0)
191  {
192  if (!isNumpyShapeCompatible(input, &dataLen_, 1U)) throw std::invalid_argument(
193  "In npstat::ConvolutionEngine1D::setFilter2: incompatible array shape");
194  const int typenum = numpyArrayType(input);
195  if (typenum == NumpyTypecode<double>::code)
196  setFilter((double*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
197  else if (typenum == NumpyTypecode<float>::code)
198  setFilter((float*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
199  else if (typenum == NumpyTypecode<long long>::code)
200  setFilter((long long*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
201  else if (typenum == NumpyTypecode<long int>::code)
202  setFilter((long int*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
203  else if (typenum == NumpyTypecode<unsigned char>::code)
204  setFilter((unsigned char*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
205  else if (typenum == NumpyTypecode<int>::code)
206  setFilter((int*)PyArray_DATA((PyArrayObject*)input), dataLen_, shift);
207  else
208  throw std::invalid_argument("In npstat::ConvolutionEngine1D::setFilter2: "
209  "unsupported input array type");
210  }
211 
212  inline void depositFilter2(unsigned long id,
213  const double* in, unsigned dataLen,
214  unsigned shift=0)
215  {depositFilter(id, in, dataLen, shift);}
216 
217  inline PyObject* convolveWithFilter2(const double* in, unsigned dataLen,
218  const unsigned shift = 0,
219  const bool makeNonNegative = false)
220  {
221  const int typenum = NumpyTypecode<double>::code;
222  npy_intp sh = dataLen;
223  PyObject* xarr = PyArray_SimpleNew(1, &sh, typenum);
224  if (xarr)
225  {
226  double* out = (double*)PyArray_DATA((PyArrayObject*)xarr);
227  try
228  {
229  convolveWithFilter(in, out, dataLen, shift);
230  }
231  catch (const std::exception& e)
232  {
233  Py_DECREF(xarr);
234  throw e;
235  }
236  if (makeNonNegative)
237  for (unsigned i=0; i<dataLen; ++i)
238  if (out[i] < 0.0)
239  out[i] = 0.0;
240  }
241  return xarr;
242  }
243 
244  inline PyObject* convolveWithDeposit2(const unsigned long id,
245  const double* in, unsigned dataLen,
246  const unsigned shift = 0,
247  const bool makeNonNegative = false)
248  {
249  const int typenum = NumpyTypecode<double>::code;
250  npy_intp sh = dataLen;
251  PyObject* xarr = PyArray_SimpleNew(1, &sh, typenum);
252  if (xarr)
253  {
254  double* out = (double*)PyArray_DATA((PyArrayObject*)xarr);
255  try
256  {
257  convolveWithDeposit(id, in, out, dataLen, shift);
258  }
259  catch (const std::exception& e)
260  {
261  Py_DECREF(xarr);
262  throw e;
263  }
264  if (makeNonNegative)
265  for (unsigned i=0; i<dataLen; ++i)
266  if (out[i] < 0.0)
267  out[i] = 0.0;
268  }
269  return xarr;
270  }
271 
272  inline PyObject* convolveFilterAndDeposit2(const unsigned long id,
273  const bool makeNonNegative = false)
274  {
275  const int typenum = NumpyTypecode<double>::code;
276  npy_intp sh = dataLen_;
277  PyObject* xarr = PyArray_SimpleNew(1, &sh, typenum);
278  if (xarr)
279  {
280  double* out = (double*)PyArray_DATA((PyArrayObject*)xarr);
281  try
282  {
283  convolveFilterAndDeposit(id, out, dataLen_);
284  }
285  catch (const std::exception& e)
286  {
287  Py_DECREF(xarr);
288  throw e;
289  }
290  if (makeNonNegative)
291  for (unsigned i=0; i<dataLen_; ++i)
292  if (out[i] < 0.0)
293  out[i] = 0.0;
294  }
295  return xarr;
296  }
297 #endif // SWIG
298  };
299 }
300 
301 #include "npstat/nm/ConvolutionEngine1D.icc"
302 
303 #endif // NPSTAT_CONVOLUTIONENGINE1D_HH_
Arbitrary-dimensional array template.
Memory manager for Fourier transforms produced by FFTW.
Definition: ConvolutionEngine1D.hh:31
void deconvolveDeposit(unsigned long id, const Real1 *in, Real2 *out, unsigned dataLen, unsigned shift=0)
void setFilterImage(const std::complex< double > *image, unsigned imLen)
void deconvolveFilter(const Real1 *in, Real2 *out, unsigned dataLen, unsigned shift=0)
void convolveWithDeposit(unsigned long id, const Real1 *in, Real2 *out, unsigned dataLen, unsigned shift=0)
ConvolutionEngine1D(unsigned dataLen, unsigned optimization=FFTW_ESTIMATE)
void convolveFilterAndDeposit(unsigned long id, Real2 *out, unsigned dataLen)
void setFilter(const Real *data, unsigned dataLen, unsigned shift=0)
void deconvolveFilterAndDeposit(unsigned long id, Real2 *out, unsigned dataLen)
void convolveWithFilter(const Real1 *in, Real2 *out, unsigned dataLen, unsigned shift=0)
unsigned dataLength() const
Definition: ConvolutionEngine1D.hh:151
void depositFilter(unsigned long id, const Real *data, unsigned dataLen, unsigned shift=0)
unsigned imageLength() const
Definition: ConvolutionEngine1D.hh:154
bool discardFilter(unsigned long id)
void depositFilterImage(unsigned long id, const std::complex< double > *image, unsigned imLen)
Definition: AbsArrayProjector.hh:14