Branch data Line data Source code
1 : : //
2 : : // Class FFTOpenPoissonSolver
3 : : // FFT-based Poisson Solver for open boundaries.
4 : : // Solves laplace(phi) = -rho, and E = -grad(phi).
5 : : //
6 : : //
7 : :
8 : : #ifndef IPPL_FFT_OPEN_POISSON_SOLVER_H_
9 : : #define IPPL_FFT_OPEN_POISSON_SOLVER_H_
10 : :
11 : : #include <Kokkos_MathematicalConstants.hpp>
12 : : #include <Kokkos_MathematicalFunctions.hpp>
13 : :
14 : : #include "Types/Vector.h"
15 : :
16 : : #include "Utility/IpplException.h"
17 : : #include "Utility/IpplTimings.h"
18 : :
19 : : #include "Field/Field.h"
20 : :
21 : : #include "Communicate/Archive.h"
22 : : #include "FFT/FFT.h"
23 : : #include "Field/HaloCells.h"
24 : : #include "FieldLayout/FieldLayout.h"
25 : : #include "Meshes/UniformCartesian.h"
26 : : #include "Poisson.h"
27 : :
28 : : namespace ippl {
29 : : namespace detail {
30 : :
31 : : /*!
32 : : * Access a view that either contains a vector field or a scalar field
33 : : * in such a way that the correct element access is determined at compile
34 : : * time, reducing the number of functions needed to achieve the same
35 : : * behavior for both kinds of fields
36 : : * @tparam tensorRank indicates whether scalar, vector, or matrix field
37 : : * @tparam - the view type
38 : : */
39 : : template <int tensorRank, typename>
40 : : struct ViewAccess;
41 : :
42 : : template <typename View>
43 : : struct ViewAccess<2, View> {
44 : 0 : KOKKOS_INLINE_FUNCTION constexpr static auto& get(View&& view, unsigned dim1,
45 : : unsigned dim2, size_t i, size_t j,
46 : : size_t k) {
47 : 0 : return view(i, j, k)[dim1][dim2];
48 : : }
49 : : };
50 : :
51 : : template <typename View>
52 : : struct ViewAccess<1, View> {
53 : 0 : KOKKOS_INLINE_FUNCTION constexpr static auto& get(View&& view, unsigned dim1,
54 : : [[maybe_unused]] unsigned dim2,
55 : : size_t i, size_t j, size_t k) {
56 : 0 : return view(i, j, k)[dim1];
57 : : }
58 : : };
59 : :
60 : : template <typename View>
61 : : struct ViewAccess<0, View> {
62 : 0 : KOKKOS_INLINE_FUNCTION constexpr static auto& get(View&& view,
63 : : [[maybe_unused]] unsigned dim1,
64 : : [[maybe_unused]] unsigned dim2,
65 : : size_t i, size_t j, size_t k) {
66 : 0 : return view(i, j, k);
67 : : }
68 : : };
69 : : } // namespace detail
70 : :
71 : : template <typename FieldLHS, typename FieldRHS>
72 : : class FFTOpenPoissonSolver : public Poisson<FieldLHS, FieldRHS> {
73 : : constexpr static unsigned Dim = FieldLHS::dim;
74 : : using Trhs = typename FieldRHS::value_type;
75 : : using mesh_type = typename FieldLHS::Mesh_t;
76 : : using Tg = typename FieldLHS::value_type::value_type;
77 : :
78 : : public:
79 : : // type of output
80 : : using Base = Poisson<FieldLHS, FieldRHS>;
81 : :
82 : : // types for LHS and RHS
83 : : using typename Base::lhs_type, typename Base::rhs_type;
84 : :
85 : : // define a type for the 3 dimensional real to complex Fourier transform
86 : : typedef FFT<RCTransform, FieldRHS> FFT_t;
87 : :
88 : : // enum type for the algorithm
89 : : enum Algorithm {
90 : : HOCKNEY = 0b01,
91 : : VICO = 0b10,
92 : : BIHARMONIC = 0b11,
93 : : DCT_VICO = 0b100
94 : : };
95 : :
96 : : // define a type for a 3 dimensional field (e.g. charge density field)
97 : : // define a type of Field with integers to be used for the helper Green's function
98 : : // also define a type for the Fourier transformed complex valued fields
99 : : // define matrix and matrix field types for the Hessian
100 : : typedef FieldRHS Field_t;
101 : : typedef typename FieldLHS::Centering_t Centering;
102 : : typedef Field<int, Dim, mesh_type, Centering> IField_t;
103 : : typedef Field<Tg, Dim, mesh_type, Centering> Field_gt;
104 : : typedef Field<Kokkos::complex<Tg>, Dim, mesh_type, Centering> CxField_gt;
105 : : typedef typename FFT_t::ComplexField CxField_t;
106 : : typedef Vector<Trhs, Dim> Vector_t;
107 : : typedef typename mesh_type::matrix_type Matrix_t;
108 : : typedef Field<Matrix_t, Dim, mesh_type, Centering> MField_t;
109 : :
110 : : // define type for field layout
111 : : typedef FieldLayout<Dim> FieldLayout_t;
112 : :
113 : : // type for communication buffers
114 : : using memory_space = typename FieldLHS::memory_space;
115 : : using buffer_type = mpi::Communicator::buffer_type<memory_space>;
116 : :
117 : : // types of mesh and mesh spacing
118 : : using vector_type = typename mesh_type::vector_type;
119 : : using scalar_type = typename mesh_type::value_type;
120 : :
121 : : // constructor and destructor
122 : : FFTOpenPoissonSolver();
123 : : FFTOpenPoissonSolver(rhs_type& rhs, ParameterList& params);
124 : : FFTOpenPoissonSolver(lhs_type& lhs, rhs_type& rhs, ParameterList& params);
125 [ # # # # ]: 0 : ~FFTOpenPoissonSolver() = default;
126 : :
127 : : // override the setRhs function of the Solver class
128 : : // since we need to call initializeFields()
129 : : void setRhs(rhs_type& rhs) override;
130 : :
131 : : // allows user to set gradient of phi = Efield instead of spectral
132 : : // calculation of Efield (which uses FFTs)
133 : : void setGradFD();
134 : :
135 : : // solve the Poisson equation using FFT;
136 : : // more specifically, compute the scalar potential given a density field rho using
137 : : void solve() override;
138 : :
139 : : // override getHessian to return Hessian field if flag is on
140 : 0 : MField_t* getHessian() override {
141 [ # # # # ]: 0 : bool hessian = this->params_m.template get<bool>("hessian");
142 [ # # ]: 0 : if (!hessian) {
143 [ # # # # : 0 : throw IpplException(
# # ]
144 : : "FFTOpenPoissonSolver::getHessian()",
145 : : "Cannot call getHessian() if 'hessian' flag in ParameterList is false");
146 : : }
147 : 0 : return &hess_m;
148 : : }
149 : :
150 : : // compute standard Green's function
151 : : void greensFunction();
152 : :
153 : : // function called in the constructor to initialize the fields
154 : : void initializeFields();
155 : :
156 : : // communication used for multi-rank Vico-Greengard's Green's function
157 : : void communicateVico(Vector<int, Dim> size, typename CxField_gt::view_type view_g,
158 : : const ippl::NDIndex<Dim> ldom_g, const int nghost_g,
159 : : typename Field_t::view_type view, const ippl::NDIndex<Dim> ldom,
160 : : const int nghost);
161 : :
162 : : // needed for improved Vico-Greengard (DCT VICO)
163 : : void communicateVico(Vector<int, Dim> size, typename Field_t::view_type view_g,
164 : : const ippl::NDIndex<Dim> ldom_g, const int nghost_g,
165 : : typename Field_t::view_type view, const ippl::NDIndex<Dim> ldom,
166 : : const int nghost);
167 : :
168 : : private:
169 : : // create a field to use as temporary storage
170 : : // references to it can be created to make the code where it is used readable
171 : : Field_t storage_field;
172 : :
173 : : Field_t& rho2_mr =
174 : : storage_field; // the charge-density field with mesh doubled in each dimension
175 : : Field_t& grn_mr = storage_field; // the Green's function
176 : :
177 : : // rho2tr_m is the Fourier transformed charge-density field
178 : : // domain3_m and mesh3_m are used
179 : : CxField_t rho2tr_m;
180 : :
181 : : // grntr_m is the Fourier transformed Green's function
182 : : // domain3_m and mesh3_m are used
183 : : CxField_t grntr_m;
184 : :
185 : : // temp_m field for the E-field computation
186 : : CxField_t temp_m;
187 : :
188 : : // fields that facilitate the calculation in greensFunction()
189 : : IField_t grnIField_m[Dim];
190 : :
191 : : // hessian matrix field (only if hessian parameter is set)
192 : : MField_t hess_m;
193 : :
194 : : // the FFT object
195 : : std::unique_ptr<FFT_t> fft_m;
196 : :
197 : : // mesh and layout objects for rho_m (RHS)
198 : : mesh_type* mesh_mp;
199 : : FieldLayout_t* layout_mp;
200 : :
201 : : // mesh and layout objects for rho2_m
202 : : std::unique_ptr<mesh_type> mesh2_m;
203 : : std::unique_ptr<FieldLayout_t> layout2_m;
204 : :
205 : : // mesh and layout objects for the Fourier transformed Complex fields
206 : : std::unique_ptr<mesh_type> meshComplex_m;
207 : : std::unique_ptr<FieldLayout_t> layoutComplex_m;
208 : :
209 : : // domains for the various fields
210 : : NDIndex<Dim> domain_m; // original domain, gridsize
211 : : NDIndex<Dim> domain2_m; // doubled gridsize (2*Nx,2*Ny,2*Nz)
212 : : NDIndex<Dim> domainComplex_m; // field for the complex values of the RC transformation
213 : :
214 : : // mesh spacing and mesh size
215 : : vector_type hr_m;
216 : : Vector<int, Dim> nr_m;
217 : :
218 : : // string specifying algorithm: Hockney or Vico-Greengard
219 : : std::string alg_m;
220 : :
221 : : // members for Vico-Greengard
222 : : CxField_gt grnL_m;
223 : :
224 : : std::unique_ptr<FFT<CCTransform, CxField_gt>> fft4n_m;
225 : :
226 : : std::unique_ptr<mesh_type> mesh4_m;
227 : : std::unique_ptr<FieldLayout_t> layout4_m;
228 : :
229 : : NDIndex<Dim> domain4_m;
230 : :
231 : : // members for improved Vico-Greengard (DCT VICO)
232 : : Field_t grn2n1_m;
233 : :
234 : : std::unique_ptr<FFT<Cos1Transform, Field_t>> fft2n1_m;
235 : :
236 : : std::unique_ptr<mesh_type> mesh2n1_m;
237 : : std::unique_ptr<FieldLayout_t> layout2n1_m;
238 : :
239 : : NDIndex<Dim> domain2n1_m;
240 : :
241 : : // bool indicating whether we want gradient of solution to calculate E field
242 : : bool isGradFD_m;
243 : :
244 : : // buffer for communication
245 : : detail::FieldBufferData<Trhs> fd_m;
246 : :
247 : : protected:
248 : 0 : virtual void setDefaultParameters() override {
249 : : using heffteBackend = typename FFT_t::heffteBackend;
250 [ # # ]: 0 : heffte::plan_options opts = heffte::default_options<heffteBackend>();
251 [ # # # # ]: 0 : this->params_m.add("use_pencils", opts.use_pencils);
252 [ # # # # ]: 0 : this->params_m.add("use_reorder", opts.use_reorder);
253 [ # # # # ]: 0 : this->params_m.add("use_gpu_aware", opts.use_gpu_aware);
254 [ # # # # ]: 0 : this->params_m.add("r2c_direction", 0);
255 : :
256 [ # # # # : 0 : switch (opts.algorithm) {
# ]
257 : 0 : case heffte::reshape_algorithm::alltoall:
258 [ # # # # ]: 0 : this->params_m.add("comm", a2a);
259 : 0 : break;
260 : 0 : case heffte::reshape_algorithm::alltoallv:
261 [ # # # # ]: 0 : this->params_m.add("comm", a2av);
262 : 0 : break;
263 : 0 : case heffte::reshape_algorithm::p2p:
264 [ # # # # ]: 0 : this->params_m.add("comm", p2p);
265 : 0 : break;
266 : 0 : case heffte::reshape_algorithm::p2p_plined:
267 [ # # # # ]: 0 : this->params_m.add("comm", p2p_pl);
268 : 0 : break;
269 : 0 : default:
270 [ # # # # : 0 : throw IpplException("FFTOpenPoissonSolver::setDefaultParameters",
# # ]
271 : : "Unrecognized heffte communication type");
272 : : }
273 : :
274 [ # # # # ]: 0 : this->params_m.add("algorithm", HOCKNEY);
275 [ # # # # ]: 0 : this->params_m.add("hessian", false);
276 : 0 : }
277 : : };
278 : : } // namespace ippl
279 : :
280 : : #include "PoissonSolvers/FFTOpenPoissonSolver.hpp"
281 : : #endif
|