21 #ifndef THUNDEREGG_POISSON_SCHUR_FFTWPATCHSOLVER_H
22 #define THUNDEREGG_POISSON_SCHUR_FFTWPATCHSOLVER_H
55 std::shared_ptr<const PatchOperator<D>> op;
59 std::map<const PatchInfo<D>, std::shared_ptr<fftw_plan>, CompareFunction> plan1;
63 std::map<const PatchInfo<D>, std::shared_ptr<fftw_plan>, CompareFunction> plan2;
67 std::map<const PatchInfo<D>,
PatchArray<D>, CompareFunction> eigen_vals;
71 std::bitset<Side<D>::number_of> neumann;
92 std::array<fftw_r2r_kind, D> getTransformsForPatch(
const PatchInfo<D>& pinfo)
95 std::array<fftw_r2r_kind, D> transforms;
96 for (
size_t axis = 0; axis < D; axis++) {
97 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
98 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
99 transforms[D - 1 - axis] = FFTW_REDFT10;
100 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis))) {
101 transforms[D - 1 - axis] = FFTW_REDFT11;
102 }
else if (patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
103 transforms[D - 1 - axis] = FFTW_RODFT11;
105 transforms[D - 1 - axis] = FFTW_RODFT10;
117 std::array<fftw_r2r_kind, D> getInverseTransformsForPatch(
const PatchInfo<D>& pinfo)
120 std::array<fftw_r2r_kind, D> transforms_inv;
121 for (
size_t axis = 0; axis < D; axis++) {
122 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
123 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
124 transforms_inv[D - 1 - axis] = FFTW_REDFT01;
125 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis))) {
126 transforms_inv[D - 1 - axis] = FFTW_REDFT11;
127 }
else if (patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
128 transforms_inv[D - 1 - axis] = FFTW_RODFT11;
130 transforms_inv[D - 1 - axis] = FFTW_RODFT01;
133 return transforms_inv;
145 std::valarray<size_t> all_strides(D);
146 size_t curr_stride = 1;
147 for (
size_t i = 0; i < D; i++) {
148 all_strides[i] = curr_stride;
149 curr_stride *= pinfo.
ns[i];
152 for (
size_t axis = 0; axis < D; axis++) {
153 int n = pinfo.
ns[axis];
156 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
157 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
158 for (
int xi = 0; xi < n; xi++) {
159 double val = 4 / (h * h) * pow(sin(xi * M_PI / (2 * n)), 2);
161 Loop::OverInteriorIndexes<D>(
162 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
164 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) ||
165 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
166 for (
int xi = 0; xi < n; xi++) {
167 double val = 4 / (h * h) * pow(sin((xi + 0.5) * M_PI / (2 * n)), 2);
169 Loop::OverInteriorIndexes<D>(
170 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
173 for (
int xi = 0; xi < n; xi++) {
174 double val = 4 / (h * h) * pow(sin((xi + 1) * M_PI / (2 * n)), 2);
176 Loop::OverInteriorIndexes<D>(
177 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
197 std::bitset<Side<D>::number_of> a_neumann;
198 std::bitset<Side<D>::number_of> b_neumann;
200 a_neumann[s.
getIndex()] = patchIsNeumannOnSide(a, s);
201 b_neumann[s.
getIndex()] = patchIsNeumannOnSide(b, s);
203 return std::forward_as_tuple(a_neumann.to_ulong(), a.
spacings[0]) <
204 std::forward_as_tuple(b_neumann.to_ulong(), b.spacings[0]);
207 plan1 = std::map<const PatchInfo<D>, std::shared_ptr<fftw_plan>, CompareFunction>(compare);
208 plan2 = std::map<const PatchInfo<D>, std::shared_ptr<fftw_plan>, CompareFunction>(compare);
209 eigen_vals = std::map<const PatchInfo<D>,
PatchArray<D>, CompareFunction>(compare);
212 for (
auto pinfo : this->
getDomain().getPatchInfoVector()) {
230 Loop::OverInteriorIndexes<D + 1>(
231 f_copy, [&](std::array<int, D + 1> coord) { f_copy[coord] = f_view[coord]; });
233 op->modifyRHSForInternalBoundaryConditions(pinfo, u_view, f_copy.
getView());
235 fftw_execute_r2r(*plan1.at(pinfo), &f_copy[f_copy.
getStart()], &tmp[tmp.
getStart()]);
238 Loop::OverInteriorIndexes<D + 1>(
239 tmp, [&](std::array<int, D + 1> coord) { tmp[coord] /= eigen_vals_view[coord]; });
241 if (neumann.all() && !pinfo.
hasNbr()) {
245 fftw_execute_r2r(*plan2.at(pinfo), &tmp[tmp.
getStart()], &sol[sol.
getStart()]);
248 for (
size_t axis = 0; axis < D; axis++) {
249 scale *= 2.0 * this->
getDomain().getNs()[axis];
251 Loop::OverInteriorIndexes<D + 1>(
252 u_view, [&](std::array<int, D + 1> coord) { u_view[coord] = sol[coord] / scale; });
263 if (plan1.count(pinfo) == 0) {
265 std::array<int, D> ns_reversed;
266 for (
size_t i = 0; i < D; i++) {
267 ns_reversed[D - 1 - i] = pinfo.
ns[i];
269 std::array<fftw_r2r_kind, D> transforms = getTransformsForPatch(pinfo);
270 std::array<fftw_r2r_kind, D> transforms_inv = getInverseTransformsForPatch(pinfo);
276 fftw_plan* fftw_plan1 =
new fftw_plan();
278 *fftw_plan1 = fftw_plan_r2r(D,
283 FFTW_MEASURE | FFTW_DESTROY_INPUT | FFTW_UNALIGNED);
285 plan1[pinfo] = std::shared_ptr<fftw_plan>(fftw_plan1, [](fftw_plan* plan) {
286 fftw_destroy_plan(*plan);
290 fftw_plan* fftw_plan2 =
new fftw_plan();
292 *fftw_plan2 = fftw_plan_r2r(D,
296 transforms_inv.data(),
297 FFTW_MEASURE | FFTW_DESTROY_INPUT | FFTW_UNALIGNED);
299 plan2[pinfo] = std::shared_ptr<fftw_plan>(fftw_plan2, [](fftw_plan* plan) {
300 fftw_destroy_plan(*plan);
304 eigen_vals.emplace(pinfo, getEigenValues(pinfo));
312 std::bitset<Side<D>::number_of>
getNeumann()
const {
return neumann; }
314 extern template class FFTWPatchSolver<2>;
315 extern template class FFTWPatchSolver<3>;