SIRIUS 7.5.0
Electronic structure library and applications
fft.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2019 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file fft.hpp
21 *
22 * \brief Contains helper functions for the interface with SpFFT library.
23 */
24
25#ifndef __FFT_HPP__
26#define __FFT_HPP__
27
28#include <spfft/spfft.hpp>
29#include "core/splindex.hpp"
31#include "SDDK/memory.hpp"
32
33namespace sirius {
34
35/// FFT-related functions and objects.
36namespace fft {
37
38/// Type traits to handle Spfft grid for different precision type.
39template <typename T>
40struct SpFFT_Grid {};
41
42template <>
43struct SpFFT_Grid<double> {using type = spfft::Grid;};
44
45template <>
46struct SpFFT_Grid<std::complex<double>> {using type = spfft::Grid;};
47
48#ifdef SIRIUS_USE_FP32
49template <>
50struct SpFFT_Grid<std::complex<float>> {using type = spfft::GridFloat;};
51
52template <>
53struct SpFFT_Grid<float> {using type = spfft::GridFloat;};
54#endif
55
56template <typename T>
57using spfft_grid_type = typename SpFFT_Grid<T>::type;
58
59/// Type traits to handle Spfft driver for different precision type.
60template <typename T>
62
63template <>
64struct SpFFT_Transform<double> {using type = spfft::Transform;};
65
66template <>
67struct SpFFT_Transform<std::complex<double>> {using type = spfft::Transform;};
68
69#ifdef SIRIUS_USE_FP32
70template <>
71struct SpFFT_Transform<float> {using type = spfft::TransformFloat;};
72
73template <>
74struct SpFFT_Transform<std::complex<float>> {using type = spfft::TransformFloat;};
75#endif
76
77template <typename T>
78using spfft_transform_type = typename SpFFT_Transform<T>::type;
79
80const std::map<SpfftProcessingUnitType, sddk::memory_t> spfft_memory_t = {
81 {SPFFT_PU_HOST, sddk::memory_t::host},
82 {SPFFT_PU_GPU, sddk::memory_t::device}
83};
84
85template <typename F, typename T, typename ...Args>
86using enable_return = typename std::enable_if<std::is_same<typename std::result_of<F(Args...)>::type, T>::value, void>::type;
87
88/// Load data from real-valued lambda.
89template <typename T, typename F>
90inline enable_return<F, T, int>
91spfft_input(spfft_transform_type<T>& spfft__, F&& fr__)
92{
93 switch (spfft__.type()) {
94 case SPFFT_TRANS_C2C: {
95 auto ptr = reinterpret_cast<std::complex<T>*>(spfft__.space_domain_data(SPFFT_PU_HOST));
96 #pragma omp parallel for schedule(static)
97 for (int i = 0; i < spfft__.local_slice_size(); i++) {
98 ptr[i] = std::complex<T>(fr__(i), 0.0);
99 }
100 break;
101 }
102 case SPFFT_TRANS_R2C: {
103 auto ptr = reinterpret_cast<T*>(spfft__.space_domain_data(SPFFT_PU_HOST));
104 #pragma omp parallel for schedule(static)
105 for (int i = 0; i < spfft__.local_slice_size(); i++) {
106 ptr[i] = fr__(i);
107 }
108 break;
109 }
110 default: {
111 throw std::runtime_error("wrong spfft type");
112 }
113 }
114}
115
116/// Load data from complex-valued lambda.
117template <typename T, typename F>
118inline enable_return<F, std::complex<T>, int>
119spfft_input(spfft_transform_type<T>& spfft__, F&& fr__)
120{
121 switch (spfft__.type()) {
122 case SPFFT_TRANS_C2C: {
123 auto ptr = reinterpret_cast<std::complex<T>*>(spfft__.space_domain_data(SPFFT_PU_HOST));
124 #pragma omp parallel for schedule(static)
125 for (int i = 0; i < spfft__.local_slice_size(); i++) {
126 ptr[i] = fr__(i);
127 }
128 break;
129 }
130 case SPFFT_TRANS_R2C: {
131 }
132 default: {
133 throw std::runtime_error("wrong spfft type");
134 }
135 }
136}
137
138/// Input CPU data to CPU buffer of SpFFT.
139template <typename T>
140inline void spfft_input(spfft_transform_type<T>& spfft__, T const* data__)
141{
142 spfft_input<T>(spfft__, [&](int ir){return data__[ir];});
143}
144
145template <typename T, typename F>
146inline void spfft_multiply(spfft_transform_type<T>& spfft__, F&& fr__)
147{
148 switch (spfft__.type()) {
149 case SPFFT_TRANS_C2C: {
150 auto ptr = reinterpret_cast<std::complex<T>*>(spfft__.space_domain_data(SPFFT_PU_HOST));
151 #pragma omp parallel for schedule(static)
152 for (int i = 0; i < spfft__.local_slice_size(); i++) {
153 ptr[i] *= fr__(i);
154 }
155 break;
156 }
157 case SPFFT_TRANS_R2C: {
158 auto ptr = reinterpret_cast<T*>(spfft__.space_domain_data(SPFFT_PU_HOST));
159 #pragma omp parallel for schedule(static)
160 for (int i = 0; i < spfft__.local_slice_size(); i++) {
161 ptr[i] *= fr__(i);
162 }
163 break;
164 }
165 default: {
166 throw std::runtime_error("wrong spfft type");
167 }
168 }
169}
170
171/// Output CPU data from the CPU buffer of SpFFT.
172template <typename T>
173inline void spfft_output(spfft_transform_type<T>& spfft__, T* data__)
174{
175 switch (spfft__.type()) {
176 case SPFFT_TRANS_C2C: {
177 auto ptr = reinterpret_cast<std::complex<T>*>(spfft__.space_domain_data(SPFFT_PU_HOST));
178 #pragma omp parallel for schedule(static)
179 for (int i = 0; i < spfft__.local_slice_size(); i++) {
180 data__[i] = std::real(ptr[i]);
181 }
182 break;
183 }
184 case SPFFT_TRANS_R2C: {
185 auto ptr = reinterpret_cast<T*>(spfft__.space_domain_data(SPFFT_PU_HOST));
186 #pragma omp parallel for schedule(static)
187 for (int i = 0; i < spfft__.local_slice_size(); i++) {
188 data__[i] = ptr[i];
189 }
190 break;
191 }
192 default: {
193 throw std::runtime_error("wrong spfft type");
194 }
195 }
196}
197
198template <typename T>
199inline void spfft_output(spfft_transform_type<T>& spfft__, std::complex<T>* data__)
200{
201 switch (spfft__.type()) {
202 case SPFFT_TRANS_C2C: {
203 auto ptr = reinterpret_cast<std::complex<T>*>(spfft__.space_domain_data(SPFFT_PU_HOST));
204 #pragma omp parallel for schedule(static)
205 for (int i = 0; i < spfft__.local_slice_size(); i++) {
206 data__[i] = ptr[i];
207 }
208 break;
209 }
210 case SPFFT_TRANS_R2C: {
211 /* can't be a R2C transform and complex output data */
212 }
213 default: {
214 throw std::runtime_error("wrong spfft type");
215 }
216 }
217}
218
219/// Total size of the SpFFT transformation grid.
220template <typename T>
221inline size_t spfft_grid_size(T const& spfft__)
222{
223 return spfft__.dim_x() * spfft__.dim_y() * spfft__.dim_z();
224}
225
226/// Local size of the SpFFT transformation grid.
227template <typename T>
228inline size_t spfft_grid_size_local(T const& spfft__)
229{
230 return spfft__.local_slice_size();
231}
232
233/// Split z-dimenstion of size_z between MPI ranks of the FFT communicator.
234/** SpFFT works with any z-distribution of the real-space FFT buffer. Here we split the z-dimenstion
235 * using block distribution. */
236inline auto split_z_dimension(int size_z__, mpi::Communicator const& comm_fft__)
237{
238 return splindex_block<>(size_z__, n_blocks(comm_fft__.size()), block_id(comm_fft__.rank()));
239}
240
241} // namespace fft
242
243} // namespace sirius
244
245#endif // __FFT_HPP__
246
247/** \page ft_pw Fourier transform and plane wave normalization
248 *
249 * FFT convention:
250 * \f[
251 * f({\bf r}) = \sum_{{\bf G}} e^{i{\bf G}{\bf r}} f({\bf G})
252 * \f]
253 * is a \em backward transformation from a set of pw coefficients to a function.
254 *
255 * \f[
256 * f({\bf G}) = \frac{1}{\Omega} \int e^{-i{\bf G}{\bf r}} f({\bf r}) d {\bf r} =
257 * \frac{1}{N} \sum_{{\bf r}_j} e^{-i{\bf G}{\bf r}_j} f({\bf r}_j)
258 * \f]
259 * is a \em forward transformation from a function to a set of coefficients.
260
261 * We use plane waves in two different cases: a) plane waves (or augmented plane waves in the case of APW+lo method)
262 * as a basis for expanding Kohn-Sham wave functions and b) plane waves are used to expand charge density and
263 * potential. When we are dealing with plane wave basis functions it is convenient to adopt the following
264 * normalization:
265 * \f[
266 * \langle {\bf r} |{\bf G+k} \rangle = \frac{1}{\sqrt \Omega} e^{i{\bf (G+k)r}}
267 * \f]
268 * such that
269 * \f[
270 * \langle {\bf G+k} |{\bf G'+k} \rangle_{\Omega} = \delta_{{\bf GG'}}
271 * \f]
272 * in the unit cell. However, for the expansion of periodic functions such as density or potential, the following
273 * convention is more appropriate:
274 * \f[
275 * \rho({\bf r}) = \sum_{\bf G} e^{i{\bf Gr}} \rho({\bf G})
276 * \f]
277 * where
278 * \f[
279 * \rho({\bf G}) = \frac{1}{\Omega} \int_{\Omega} e^{-i{\bf Gr}} \rho({\bf r}) d{\bf r} =
280 * \frac{1}{\Omega} \sum_{{\bf r}_i} e^{-i{\bf Gr}_i} \rho({\bf r}_i) \frac{\Omega}{N} =
281 * \frac{1}{N} \sum_{{\bf r}_i} e^{-i{\bf Gr}_i} \rho({\bf r}_i)
282 * \f]
283 * i.e. with such convention the plane-wave expansion coefficients are obtained with a normalized FFT.
284 */
MPI communicator wrapper.
int size() const
Size of the communicator (number of ranks).
int rank() const
Rank of MPI process inside communicator.
Contains declaration and implementation of mpi::Communicator class.
Memory management functions and classes.
void spfft_output(spfft_transform_type< T > &spfft__, T *data__)
Output CPU data from the CPU buffer of SpFFT.
Definition: fft.hpp:173
enable_return< F, T, int > spfft_input(spfft_transform_type< T > &spfft__, F &&fr__)
Load data from real-valued lambda.
Definition: fft.hpp:91
size_t spfft_grid_size_local(T const &spfft__)
Local size of the SpFFT transformation grid.
Definition: fft.hpp:228
size_t spfft_grid_size(T const &spfft__)
Total size of the SpFFT transformation grid.
Definition: fft.hpp:221
auto split_z_dimension(int size_z__, mpi::Communicator const &comm_fft__)
Split z-dimenstion of size_z between MPI ranks of the FFT communicator.
Definition: fft.hpp:236
Namespace of the SIRIUS library.
Definition: sirius.f90:5
strong_type< int, struct __n_blocks_tag > n_blocks
Number of blocks to which the global index is split.
Definition: splindex.hpp:105
Contains definition of sddk::splindex_base and specializations of sddk::splindex class.
Type traits to handle Spfft grid for different precision type.
Definition: fft.hpp:40
Type traits to handle Spfft driver for different precision type.
Definition: fft.hpp:61