PSCF v1.1
pspc/field/FFT.tpp
1#ifndef PSPC_FFT_TPP
2#define PSPC_FFT_TPP
3
4/*
5* PSCF Package
6*
7* Copyright 2016 - 2022, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "FFT.h"
12
13namespace Pscf {
14namespace Pspc
15{
16
17 using namespace Util;
18
19 /*
20 * Default constructor.
21 */
22 template <int D>
24 : rFieldCopy_(),
25 meshDimensions_(0),
26 rSize_(0),
27 kSize_(0),
28 fPlan_(0),
29 iPlan_(0),
30 isSetup_(false)
31 {}
32
33 /*
34 * Destructor.
35 */
36 template <int D>
38 {
39 if (fPlan_) {
40 fftw_destroy_plan(fPlan_);
41 }
42 if (iPlan_) {
43 fftw_destroy_plan(iPlan_);
44 }
45 }
46
47 /*
48 * Setup mesh dimensions.
49 */
50 template <int D>
51 void FFT<D>::setup(IntVec<D> const& meshDimensions)
52 {
53 // Precondition
54 UTIL_CHECK(!isSetup_);
55
56 // Create local r-grid and k-grid field objects
57 RField<D> rField;
58 rField.allocate(meshDimensions);
59 RFieldDft<D> kField;
60 kField.allocate(meshDimensions);
61
62 setup(rField, kField);
63 }
64
65 /*
66 * Check and (if necessary) setup mesh dimensions.
67 */
68 template <int D>
69 void FFT<D>::setup(RField<D>& rField, RFieldDft<D>& kField)
70 {
71 // Preconditions
72 UTIL_CHECK(!isSetup_);
73 IntVec<D> rDimensions = rField.meshDimensions();
74 IntVec<D> kDimensions = kField.meshDimensions();
75 UTIL_CHECK(rDimensions == kDimensions);
76
77 // Set and check mesh dimensions
78 rSize_ = 1;
79 kSize_ = 1;
80 for (int i = 0; i < D; ++i) {
81 UTIL_CHECK(rDimensions[i] > 0);
82 meshDimensions_[i] = rDimensions[i];
83 rSize_ *= rDimensions[i];
84 if (i < D - 1) {
85 kSize_ *= rDimensions[i];
86 } else {
87 kSize_ *= (rDimensions[i]/2 + 1);
88 }
89 }
90 UTIL_CHECK(rField.capacity() == rSize_);
91 UTIL_CHECK(kField.capacity() == kSize_);
92
93 // Allocate rFieldCopy_ array if necessary
94 if (!rFieldCopy_.isAllocated()) {
95 rFieldCopy_.allocate(rDimensions);
96 } else {
97 if (rFieldCopy_.capacity() != rSize_) {
98 rFieldCopy_.deallocate();
99 rFieldCopy_.allocate(rDimensions);
100 }
101 }
102 UTIL_CHECK(rFieldCopy_.capacity() == rSize_);
103
104 // Allocate kFieldCopy_ array if necessary
105 if (!kFieldCopy_.isAllocated()) {
106 kFieldCopy_.allocate(kDimensions);
107 } else {
108 if (kFieldCopy_.capacity() != rSize_) {
109 kFieldCopy_.deallocate();
110 kFieldCopy_.allocate(kDimensions);
111 }
112 }
113 UTIL_CHECK(kFieldCopy_.capacity() == kSize_);
114
115 // Make FFTW plans (see explicit specializations FFT.cpp)
116 makePlans(rField, kField);
117
118 isSetup_ = true;
119 }
120
121 /*
122 * Execute forward transform.
123 */
124 template <int D>
125 void FFT<D>::forwardTransform(RField<D> const & rField, RFieldDft<D>& kField) const
126 {
127 UTIL_CHECK(isSetup_)
128 UTIL_CHECK(rFieldCopy_.capacity() == rSize_);
129 UTIL_CHECK(rField.capacity() == rSize_);
130 UTIL_CHECK(kField.capacity() == kSize_);
131 UTIL_CHECK(rField.meshDimensions() == meshDimensions_);
132 UTIL_CHECK(kField.meshDimensions() == meshDimensions_);
133
134 // Copy rescaled input data prior to work array
135 double scale = 1.0/double(rSize_);
136 for (int i = 0; i < rSize_; ++i) {
137 rFieldCopy_[i] = rField[i]*scale;
138 }
139
140 // Execute preplanned forward transform
141 fftw_execute_dft_r2c(fPlan_, &rFieldCopy_[0], &kField[0]);
142 }
143
144 /*
145 * Execute inverse (complex-to-real) transform.
146 */
147 template <int D>
148 void
150 const
151 {
152 UTIL_CHECK(isSetup_)
153 UTIL_CHECK(rField.capacity() == rSize_);
154 UTIL_CHECK(kField.capacity() == kSize_);
155 UTIL_CHECK(rField.meshDimensions() == meshDimensions_);
156 UTIL_CHECK(kField.meshDimensions() == meshDimensions_);
157
158 fftw_execute_dft_c2r(iPlan_, &kField[0], &rField[0]);
159
160 }
161
162 /*
163 * Execute inverse (complex-to-real) transform without destroying input.
164 */
165 template <int D>
167 const
168 {
169 UTIL_CHECK(kFieldCopy_.capacity()==kField.capacity());
170
171 kFieldCopy_ = kField;
172 inverseTransform(kFieldCopy_, rField);
173 }
174
175}
176}
177#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition: IntVec.h:27
void forwardTransform(RField< D > const &in, RFieldDft< D > &out) const
Compute forward (real-to-complex) Fourier transform.
virtual ~FFT()
Destructor.
FFT()
Default constructor.
void inverseTransformSafe(RFieldDft< D > const &in, RField< D > &out) const
Compute inverse (complex-to-real) Fourier transform without destroying input.
void inverseTransform(RFieldDft< D > &in, RField< D > &out) const
Compute inverse (complex-to-real) Fourier transform.
void setup(IntVec< D > const &meshDimensions)
Setup grid dimensions, plans and work space.
Fourier transform of a real field on an FFT mesh.
Definition: RFieldDft.h:31
IntVec< D > const & meshDimensions() const
Return vector of spatial mesh dimensions by constant reference.
Definition: RFieldDft.h:137
void allocate(IntVec< D > const &meshDimensions)
Allocate the underlying C array for an FFT grid.
Definition: RFieldDft.h:116
Field of real double precision values on an FFT mesh.
Definition: RField.h:29
const IntVec< D > & meshDimensions() const
Return mesh dimensions by constant reference.
Definition: RField.h:102
void allocate(const IntVec< D > &meshDimensions)
Allocate the underlying C array for an FFT grid.
Definition: RField.tpp:97
int capacity() const
Return allocated size.
Definition: Array.h:159
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
C++ namespace for polymer self-consistent field theory (PSCF).
Utility classes for scientific computation.
Definition: accumulators.mod:1