| 153 | |
| 154 | template<typename Tr, typename Tc> |
| 155 | Array<Tr> fft_c2r(const Array<Tc> &in, const dim4 &odims, const int rank) { |
| 156 | Array<Tr> out = createEmptyArray<Tr>(odims); |
| 157 | |
| 158 | auto func = [=](Param<Tr> out, const af::dim4 oDataDims, CParam<Tc> in, |
| 159 | const af::dim4 iDataDims, const af::dim4 odims) { |
| 160 | auto t_dims = computeDims(rank, odims); |
| 161 | auto in_embed = computeDims(rank, iDataDims); |
| 162 | auto out_embed = computeDims(rank, oDataDims); |
| 163 | |
| 164 | const af::dim4 istrides = in.strides(); |
| 165 | const af::dim4 ostrides = out.strides(); |
| 166 | |
| 167 | using ctype_t = typename fftw_real_transform<Tr, Tc>::ctype_t; |
| 168 | using plan_t = typename fftw_real_transform<Tr, Tc>::plan_t; |
| 169 | plan_t plan; |
| 170 | |
| 171 | fftw_real_transform<Tr, Tc> transform; |
| 172 | |
| 173 | int batch = 1; |
| 174 | for (int i = rank; i < 4; i++) { batch *= odims[i]; } |
| 175 | |
| 176 | // By default, fftw estimate flag is sufficient for most transforms. |
| 177 | // However, complex to real transforms modify the input data memory |
| 178 | // while performing the transformation. To avoid that, we need to pass |
| 179 | // FFTW_PRESERVE_INPUT also. This flag however only works for 1D |
| 180 | // transforms and for higher level transformations, a copy of input |
| 181 | // data is passed onto the upstream FFTW calls. |
| 182 | unsigned int flags = FFTW_ESTIMATE; // NOLINT(hicpp-signed-bitwise) |
| 183 | if (rank == 1) { |
| 184 | flags |= FFTW_PRESERVE_INPUT; // NOLINT(hicpp-signed-bitwise) |
| 185 | } |
| 186 | |
| 187 | plan = transform.create( |
| 188 | rank, t_dims.data(), batch, |
| 189 | reinterpret_cast<ctype_t *>(const_cast<Tc *>(in.get())), |
| 190 | in_embed.data(), static_cast<int>(istrides[0]), |
| 191 | static_cast<int>(istrides[rank]), out.get(), out_embed.data(), |
| 192 | static_cast<int>(ostrides[0]), static_cast<int>(ostrides[rank]), |
| 193 | flags); |
| 194 | |
| 195 | transform.execute(plan); |
| 196 | transform.destroy(plan); |
| 197 | }; |
| 198 | |
| 199 | #ifdef USE_MKL |
| 200 | getQueue().enqueue(func, out, out.getDataDims(), in, in.getDataDims(), |
| 201 | odims); |
| 202 | #else |
| 203 | if (rank > 1 || odims.ndims() > 1) { |
| 204 | // FFTW does not have a input preserving algorithm for multidimensional |
| 205 | // c2r FFTs |
| 206 | Array<Tc> in_ = copyArray<Tc>(in); |
| 207 | getQueue().enqueue(func, out, out.getDataDims(), in_, in.getDataDims(), |
| 208 | odims); |
| 209 | } else { |
| 210 | getQueue().enqueue(func, out, out.getDataDims(), in, in.getDataDims(), |
| 211 | odims); |
| 212 | } |
nothing calls this directly
no test coverage detected