17 template <
typename FieldLHS,
typename FieldRHS>
22 , meshComplex_m(nullptr)
23 , layoutComplex_m(nullptr) {
27 template <
typename FieldLHS,
typename FieldRHS>
31 , meshComplex_m(nullptr)
32 , layoutComplex_m(nullptr) {
41 template <
typename FieldLHS,
typename FieldRHS>
45 , meshComplex_m(nullptr)
46 , layoutComplex_m(nullptr) {
55 template <
typename FieldLHS,
typename FieldRHS>
64 template <
typename FieldLHS,
typename FieldRHS>
66 static_assert(
Dim == 3,
"Dimension other than 3 not supported in FFTTruncatedGreenPeriodicPoissonSolver!");
69 layout_mp = &(this->rhs_mp->getLayout());
70 mesh_mp = &(this->rhs_mp->get_mesh());
74 hr_m = mesh_mp->getMeshSpacing();
77 Vector_t origin = mesh_mp->getOrigin();
80 domain_m = layout_mp->getDomain();
83 for (
unsigned int i = 0; i <
Dim; ++i) {
84 nr_m[i] = domain_m[i].length();
88 std::array<bool, Dim> isParallel = layout_mp->isParallel();
94 unsigned int RCDirection = this->params_m.template get<int>(
"r2c_direction");
95 for (
unsigned int i = 0; i <
Dim; ++i) {
97 domainComplex_m[RCDirection] =
Index(nr_m[RCDirection] / 2 + 1);
99 domainComplex_m[i] =
Index(nr_m[i]);
104 meshComplex_m = std::unique_ptr<mesh_type>(
new mesh_type(domainComplex_m, hr_m, origin));
106 std::unique_ptr<FieldLayout_t>(
new FieldLayout_t(comm, domainComplex_m, isParallel));
109 grn_m.initialize(*mesh_mp, *layout_mp);
110 rhotr_m.initialize(*meshComplex_m, *layoutComplex_m);
111 grntr_m.initialize(*meshComplex_m, *layoutComplex_m);
112 tempFieldComplex_m.initialize(*meshComplex_m, *layoutComplex_m);
115 fft_m = std::make_unique<FFT_t>(*layout_mp, *layoutComplex_m, this->params_m);
116 fft_m->warmup(grn_m, grntr_m);
119 for (
unsigned int d = 0; d <
Dim; ++d) {
120 grnIField_m[d].initialize(*mesh_mp, *layout_mp);
123 auto view = grnIField_m[d].getView();
124 const int nghost = grnIField_m[d].getNghost();
125 const auto& ldom = layout_mp->getLocalNDIndex();
128 const int size = nr_m[d];
134 "Helper index Green field initialization",
136 KOKKOS_LAMBDA(
const int i,
const int j,
const int k) {
138 const int ig = i + ldom[0].first() - nghost;
139 const int jg = j + ldom[1].first() - nghost;
140 const int kg = k + ldom[2].first() - nghost;
143 const bool outsideN = (ig >= size / 2);
144 view(i, j, k) = (size * outsideN - ig) * (size * outsideN - ig);
147 const bool isOrig = ((ig == 0) && (jg == 0) && (kg == 0));
148 view(i, j, k) += isOrig * 1.0;
153 "Helper index Green field initialization",
155 KOKKOS_LAMBDA(
const int i,
const int j,
const int k) {
157 const int jg = j + ldom[1].first() - nghost;
160 const bool outsideN = (jg >= size / 2);
161 view(i, j, k) = (size * outsideN - jg) * (size * outsideN - jg);
166 "Helper index Green field initialization",
168 KOKKOS_LAMBDA(
const int i,
const int j,
const int k) {
170 const int kg = k + ldom[2].first() - nghost;
173 const bool outsideN = (kg >= size / 2);
174 view(i, j, k) = (size * outsideN - kg) * (size * outsideN - kg);
189 template <
typename FieldLHS,
typename FieldRHS>
192 const int out = this->params_m.template get<int>(
"output_type");
195 mesh_mp = &(this->rhs_mp->get_mesh());
200 for (
unsigned int i = 0; i <
Dim; ++i) {
201 if (hr_m[i] != mesh_mp->getMeshSpacing(i)) {
202 hr_m[i] = mesh_mp->getMeshSpacing(i);
208 meshComplex_m->setMeshSpacing(hr_m);
212 fft_m->transform(
FORWARD, *(this->rhs_mp), rhotr_m);
221 rhotr_m = -rhotr_m * grntr_m;
224 if ((out == Base::GRAD) || (out == Base::SOL_AND_GRAD)) {
228 const Trhs pi = Kokkos::numbers::pi_v<Trhs>;
229 Kokkos::complex<Trhs> imag = {0.0, 1.0};
231 auto view = rhotr_m.getView();
232 const int nghost = rhotr_m.getNghost();
233 auto tempview = tempFieldComplex_m.getView();
234 auto viewRhs = this->rhs_mp->getView();
235 auto viewLhs = this->lhs_mp->getView();
236 const int nghostL = this->lhs_mp->getNghost();
237 const auto& lDomComplex = layoutComplex_m->getLocalNDIndex();
242 Vector_t origin = mesh_mp->getOrigin();
244 for (
size_t gd = 0; gd <
Dim; ++gd) {
246 "Gradient FFTPeriodicPoissonSolver",
getRangePolicy(view, nghost),
247 KOKKOS_LAMBDA(
const index_array_type& args) {
250 for (
unsigned d = 0; d <
Dim; ++d) {
251 iVec[d] += lDomComplex[d].first();
256 for (
size_t d = 0; d <
Dim; ++d) {
257 const Trhs Len = N[d] * hsize[d];
258 bool shift = (iVec[d] > (N[d] / 2));
259 bool notMid = (iVec[d] != (N[d] / 2));
262 kVec[d] = notMid * 2 *
pi / Len * (iVec[d] - shift * N[d]);
266 for (
unsigned d = 0; d <
Dim; ++d) {
267 Dr += kVec[d] * kVec[d];
272 bool isNotZero = (Dr != 0.0);
274 apply(tempview, args) *= -(isNotZero * imag * kVec[gd]);
277 fft_m->transform(
BACKWARD, *this->rhs_mp, tempFieldComplex_m);
280 "Assign Gradient FFTPeriodicPoissonSolver",
getRangePolicy(viewLhs, nghostL),
281 KOKKOS_LAMBDA(
const index_array_type& args) {
282 apply(viewLhs, args)[gd] =
apply(viewRhs, args);
287 *(this->lhs_mp) = *(this->lhs_mp) * nr_m[0] * nr_m[1] * nr_m[2];
289 *(this->lhs_mp) = *(this->lhs_mp) * hr_m[0] * hr_m[1] * hr_m[2];
292 if ((out == Base::SOL) || (out == Base::SOL_AND_GRAD)) {
294 fft_m->transform(
BACKWARD, *(this->rhs_mp), rhotr_m);
297 *(this->rhs_mp) = *(this->rhs_mp) * nr_m[0] * nr_m[1] * nr_m[2];
299 *(this->rhs_mp) = *(this->rhs_mp) * hr_m[0] * hr_m[1] * hr_m[2];
306 template <
typename FieldLHS,
typename FieldRHS>
315 const Trhs alpha = this->params_m.
template get<Trhs>(
"alpha");
316 const Trhs forceConstant = this->params_m.
template get<Trhs>(
"force_constant");
322 for (
unsigned int i = 0; i <
Dim; ++i) {
323 grn_m = grn_m + grnIField_m[i] * hrsq[i];
327 const int nghost = grn_m.getNghost();
328 const auto& ldom = layout_mp->getLocalNDIndex();
333 KOKKOS_LAMBDA(
const int i,
const int j,
const int k) {
335 const int ig = i + ldom[0].first() - nghost;
336 const int jg = j + ldom[1].first() - nghost;
337 const int kg = k + ldom[2].first() - nghost;
339 const bool isOrig = (ig == 0 && jg == 0 && kg == 0);
341 Trhs r = Kokkos::real(Kokkos::sqrt(view(i, j, k)));
342 view(i, j, k) = (!isOrig) * forceConstant * (Kokkos::erf(
alpha * r) / r);
346 fft_m->transform(
FORWARD, grn_m, grntr_m);
ippl::FieldLayout< Dim > FieldLayout_t
ippl::UniformCartesian< double, 3 > Mesh_t
constexpr double alpha
The fine structure constant, no dimension.
Implementations for FFT constructor/destructor and transforms.
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
RangePolicy< View::rank, typenameView::execution_space, PolicyArgs... >::policy_type getRangePolicy(const View &view, int shift=0)
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
typename BareField_t::view_type view_type
void setRhs(rhs_type &rhs) override
void setDefaultParameters() override
typename FieldRHS::value_type Trhs
FFTTruncatedGreenPeriodicPoissonSolver()
typename FieldRHS::Mesh_t mesh_type
void setLhs(lhs_type &lhs)
void merge(const ParameterList &p) noexcept
void update(const ParameterList &p) noexcept