PSCF v1.1
pspg/field/FFT.tpp
1#ifndef PSPG_FFT_TPP
2#define PSPG_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#include <pspg/math/GpuResources.h>
13
14//forward declaration
15//static __global__ void scaleRealData(cudaReal* data, rtype scale, int size);
16
17namespace Pscf {
18namespace Pspg
19{
20
21 using namespace Util;
22
23 /*
24 * Default constructor.
25 */
26 template <int D>
28 : meshDimensions_(0),
29 rSize_(0),
30 kSize_(0),
31 fPlan_(0),
32 iPlan_(0),
33 isSetup_(false)
34 {}
35
36 /*
37 * Destructor.
38 */
39 template <int D>
41 {
42 if (fPlan_) {
43 cufftDestroy(fPlan_);
44 }
45 if (iPlan_) {
46 cufftDestroy(iPlan_);
47 }
48 }
49
50 /*
51 * Setup mesh dimensions.
52 */
53 template <int D>
54 void FFT<D>::setup(IntVec<D> const& meshDimensions)
55 {
56 // Precondition
57 UTIL_CHECK(!isSetup_);
58
59 // Create local r-grid and k-grid field objects
60 RDField<D> rField;
61 rField.allocate(meshDimensions);
62 RDFieldDft<D> kField;
63 kField.allocate(meshDimensions);
64
65 setup(rField, kField);
66 }
67
68 /*
69 * Check and (if necessary) setup mesh dimensions.
70 */
71 template <int D>
72 void FFT<D>::setup(RDField<D>& rField, RDFieldDft<D>& kField)
73 {
74 // Preconditions
75 UTIL_CHECK(!isSetup_);
76 IntVec<D> rDimensions = rField.meshDimensions();
77 IntVec<D> kDimensions = kField.meshDimensions();
78 UTIL_CHECK(rDimensions == kDimensions);
79
80 // Set Mesh dimensions
81 rSize_ = 1;
82 kSize_ = 1;
83 for (int i = 0; i < D; ++i) {
84 UTIL_CHECK(rDimensions[i] > 0);
85 meshDimensions_[i] = rDimensions[i];
86 rSize_ *= rDimensions[i];
87 if (i < D - 1) {
88 kSize_ *= rDimensions[i];
89 } else {
90 kSize_ *= (rDimensions[i]/2 + 1);
91 }
92 }
93
94 UTIL_CHECK(rField.capacity() == rSize_);
95 UTIL_CHECK(kField.capacity() == kSize_);
96
97
98 // Make FFTW plans (explicit specializations)
99 makePlans(rField, kField);
100
101 // Allocate rFieldCopy_ array if necessary
102 if (!rFieldCopy_.isAllocated()) {
103 rFieldCopy_.allocate(rDimensions);
104 } else {
105 if (rFieldCopy_.capacity() != rSize_) {
106 rFieldCopy_.deallocate();
107 rFieldCopy_.allocate(rDimensions);
108 }
109 }
110 UTIL_CHECK(rFieldCopy_.capacity() == rSize_);
111
112 // Allocate kFieldCopy_ array if necessary
113 if (!kFieldCopy_.isAllocated()) {
114 kFieldCopy_.allocate(kDimensions);
115 } else {
116 if (kFieldCopy_.capacity() != rSize_) {
117 kFieldCopy_.deallocate();
118 kFieldCopy_.allocate(kDimensions);
119 }
120 }
121 UTIL_CHECK(kFieldCopy_.capacity() == kSize_);
122
123 isSetup_ = true;
124 }
125
126 /*
127 * Execute forward transform.
128 */
129 template <int D>
131 const
132 {
133 // GPU resources
134 int nBlocks, nThreads;
135 ThreadGrid::setThreadsLogical(rSize_, nBlocks, nThreads);
136
137 // Check dimensions or setup
138 UTIL_CHECK(isSetup_);
139 UTIL_CHECK(rField.capacity() == rSize_);
140 UTIL_CHECK(kField.capacity() == kSize_);
141
142 // Rescale outputted data.
143 cudaReal scale = 1.0/cudaReal(rSize_);
144 scaleRealData<<<nBlocks, nThreads>>>(rField.cDField(), scale, rSize_);
145
146 //perform fft
147 #ifdef SINGLE_PRECISION
148 if(cufftExecR2C(fPlan_, rField.cDField(), kField.cDField()) != CUFFT_SUCCESS) {
149 std::cout << "CUFFT error: forward" << std::endl;
150 return;
151 }
152 #else
153 if(cufftExecD2Z(fPlan_, rField.cDField(), kField.cDField()) != CUFFT_SUCCESS) {
154 std::cout << "CUFFT error: forward" << std::endl;
155 return;
156 }
157 #endif
158
159 }
160
161 /*
162 * Execute forward transform without destroying input.
163 */
164 template <int D>
166 const
167 {
168 UTIL_CHECK(rFieldCopy_.capacity() == rField.capacity());
169
170 rFieldCopy_ = rField;
171 forwardTransform(rFieldCopy_, kField);
172 }
173
174 /*
175 * Execute inverse (complex-to-real) transform.
176 */
177 template <int D>
179 const
180 {
181 UTIL_CHECK(isSetup_);
182 UTIL_CHECK(rField.capacity() == rSize_);
183 UTIL_CHECK(kField.capacity() == kSize_);
184 UTIL_CHECK(rField.meshDimensions() == meshDimensions_);
185 UTIL_CHECK(kField.meshDimensions() == meshDimensions_);
186
187 #ifdef SINGLE_PRECISION
188 if(cufftExecC2R(iPlan_, kField.cDField(), rField.cDField()) != CUFFT_SUCCESS) {
189 std::cout << "CUFFT error: inverse" << std::endl;
190 return;
191 }
192 #else
193 if(cufftExecZ2D(iPlan_, kField.cDField(), rField.cDField()) != CUFFT_SUCCESS) {
194 std::cout << "CUFFT error: inverse" << std::endl;
195 return;
196 }
197 #endif
198
199 }
200
201 /*
202 * Execute inverse (complex-to-real) transform without destroying input.
203 */
204 template <int D>
206 const
207 {
208 UTIL_CHECK(kFieldCopy_.capacity()==kField.capacity());
209
210 kFieldCopy_ = kField;
211 inverseTransform(kFieldCopy_, rField);
212 }
213
214}
215}
216
217#if 0
218static __global__ void scaleRealData(cudaReal* data, cudaReal scale, int size) {
219
220 //write code that will scale
221 int nThreads = blockDim.x * gridDim.x;
222 int startId = blockIdx.x * blockDim.x + threadIdx.x;
223 for(int i = startId; i < size; i += nThreads ) {
224 data[i] *= scale;
225 }
226
227}
228#endif
229
230#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition: IntVec.h:27
Data * cDField()
Return pointer to underlying C array.
Definition: DField.h:119
int capacity() const
Return allocated size.
Definition: DField.h:112
void forwardTransformSafe(RDField< D > const &rField, RDFieldDft< D > &kField) const
Compute forward Fourier transform without destroying input.
void forwardTransform(RDField< D > &rField, RDFieldDft< D > &kField) const
Compute forward (real-to-complex) discrete Fourier transform.
void setup(IntVec< D > const &meshDimensions)
Setup grid dimensions, plans and work space.
void inverseTransform(RDFieldDft< D > &kField, RDField< D > &rField) const
Compute inverse (complex-to-real) discrete Fourier transform.
virtual ~FFT()
Destructor.
FFT()
Default constructor.
void inverseTransformSafe(RDFieldDft< D > const &kField, RDField< D > &rField) const
Compute inverse (complex to real) DFT without destroying input.
Discrete Fourier Transform (DFT) of a real field on an FFT mesh.
Definition: RDFieldDft.h:35
void allocate(const IntVec< D > &meshDimensions)
Allocate the underlying C array for an FFT grid.
Definition: RDFieldDft.h:121
const IntVec< D > & meshDimensions() const
Return vector of mesh dimensions by constant reference.
Definition: RDFieldDft.h:142
Field of real single precision values on an FFT mesh on a device.
Definition: RDField.h:34
void allocate(const IntVec< D > &meshDimensions)
Allocate the underlying C array for an FFT grid.
Definition: RDField.h:108
const IntVec< D > & meshDimensions() const
Return mesh dimensions by constant reference.
Definition: RDField.h:123
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
void setThreadsLogical(int nThreadsLogical)
Set the total number of threads required for execution.
Definition: ThreadGrid.cu:80
C++ namespace for polymer self-consistent field theory (PSCF).
Utility classes for scientific computation.
Definition: accumulators.mod:1