21 #ifndef THUNDEREGG_POISSON_DFTPATCHSOLVER_H
22 #define THUNDEREGG_POISSON_DFTPATCHSOLVER_H
38 dgemv_(
char&,
int&,
int&,
double&,
double*,
int&,
double*,
int&,
double&,
double*,
int&);
70 std::shared_ptr<const PatchOperator<D>> op;
74 std::map<PatchInfo<D>, std::array<std::shared_ptr<std::valarray<double>>, D>, CompareFunction>
79 std::map<PatchInfo<D>, std::array<std::shared_ptr<std::valarray<double>>, D>, CompareFunction>
84 std::map<const PatchInfo<D>,
PatchArray<D>, CompareFunction> eigen_vals;
88 std::map<std::tuple<DftType, int>, std::shared_ptr<std::valarray<double>>> transform_matrixes;
93 std::bitset<Side<D>::number_of> neumann;
114 std::array<std::shared_ptr<std::valarray<double>>, D> plan(std::array<DftType, D> types)
116 std::array<std::shared_ptr<std::valarray<double>>, D> retval;
117 for (
size_t axis = 0; axis < D; axis++) {
118 retval[axis] = getTransformArray(types[axis], this->
getDomain().getNs()[axis]);
130 std::shared_ptr<std::valarray<double>> getTransformArray(DftType type,
int n)
132 std::shared_ptr<std::valarray<double>> matrix_ptr;
134 if (transform_matrixes.count(std::make_tuple(type, n)) == 0) {
135 matrix_ptr = std::make_shared<std::valarray<double>>(n * n);
136 transform_matrixes[std::make_tuple(type, n)] = matrix_ptr;
137 std::valarray<double>& matrix = *matrix_ptr;
140 case DftType::DCT_II:
141 for (
int j = 0; j < n; j++) {
142 for (
int i = 0; i < n; i++) {
143 matrix[i * n + j] = cos(M_PI / n * (i * (j + 0.5)));
147 case DftType::DCT_III:
148 for (
int i = 0; i < n; i++) {
151 for (
int j = 1; j < n; j++) {
152 for (
int i = 0; i < n; i++) {
153 matrix[i * n + j] = cos(M_PI / n * ((i + 0.5) * j));
157 case DftType::DCT_IV:
158 for (
int j = 0; j < n; j++) {
159 for (
int i = 0; i < n; i++) {
160 matrix[i * n + j] = cos(M_PI / n * ((i + 0.5) * (j + 0.5)));
164 case DftType::DST_II:
165 for (
int i = 0; i < n; i++) {
166 for (
int j = 0; j < n; j++) {
167 matrix[i * n + j] = sin(M_PI / n * ((i + 1) * (j + 0.5)));
171 case DftType::DST_III:
172 for (
int i = 0; i < n; i += 2) {
173 matrix[i * n + n - 1] = 0.5;
175 for (
int i = 1; i < n; i += 2) {
176 matrix[i * n + n - 1] = -0.5;
178 for (
int i = 0; i < n; i++) {
179 for (
int j = 0; j < n - 1; j++) {
180 matrix[i * n + j] = sin(M_PI / n * ((i + 0.5) * (j + 1)));
184 case DftType::DST_IV:
185 for (
int j = 0; j < n; j++) {
186 for (
int i = 0; i < n; i++) {
187 matrix[i * n + j] = sin(M_PI / n * ((i + 0.5) * (j + 0.5)));
192 matrix_ptr = transform_matrixes.at(std::make_tuple(type, n));
204 void executePlan(
const std::array<std::shared_ptr<std::valarray<double>>, D>& plan,
215 for (
size_t axis = 0; axis < D; axis++) {
217 std::array<int, D + 1> start = in.
getStart();
218 std::array<int, D + 1> end = in.
getEnd();
221 std::valarray<double>& matrix = *plan[axis];
233 }
else if (axis == D - 2) {
234 new_result = local_tmp.
getView();
235 }
else if (axis % 2) {
248 Loop::Nested<D + 1>(start, end, [&](std::array<int, D + 1> coord) {
262 prev_result = new_result;
274 std::array<DftType, D> transforms;
275 for (
size_t axis = 0; axis < D; axis++) {
276 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
277 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
278 transforms[axis] = DftType::DCT_II;
279 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis))) {
280 transforms[axis] = DftType::DCT_IV;
281 }
else if (patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
282 transforms[axis] = DftType::DST_IV;
284 transforms[axis] = DftType::DST_II;
298 std::array<DftType, D> transforms_inv;
299 for (
size_t axis = 0; axis < D; axis++) {
300 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
301 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
302 transforms_inv[axis] = DftType::DCT_III;
303 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis))) {
304 transforms_inv[axis] = DftType::DCT_IV;
305 }
else if (patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
306 transforms_inv[axis] = DftType::DST_IV;
308 transforms_inv[axis] = DftType::DST_III;
311 return transforms_inv;
323 std::valarray<size_t> all_strides(D);
324 size_t curr_stride = 1;
325 for (
size_t i = 0; i < D; i++) {
326 all_strides[i] = curr_stride;
327 curr_stride *= pinfo.
ns[i];
330 for (
size_t axis = 0; axis < D; axis++) {
331 int n = pinfo.
ns[axis];
334 if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) &&
335 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
336 for (
int xi = 0; xi < n; xi++) {
337 double val = 4 / (h * h) * pow(sin(xi * M_PI / (2 * n)), 2);
339 Loop::OverInteriorIndexes<D>(
340 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
342 }
else if (patchIsNeumannOnSide(pinfo, LowerSideOnAxis<D>(axis)) ||
343 patchIsNeumannOnSide(pinfo, HigherSideOnAxis<D>(axis))) {
344 for (
int xi = 0; xi < n; xi++) {
345 double val = 4 / (h * h) * pow(sin((xi + 0.5) * M_PI / (2 * n)), 2);
347 Loop::OverInteriorIndexes<D>(
348 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
351 for (
int xi = 0; xi < n; xi++) {
352 double val = 4 / (h * h) * pow(sin((xi + 1) * M_PI / (2 * n)), 2);
354 Loop::OverInteriorIndexes<D>(
355 slice, [&](
const std::array<int, D>& coord) { slice[coord] -= val; });
370 if (plan1.count(pinfo) == 0) {
371 plan1[pinfo] = plan(getTransformsForPatch(pinfo));
372 plan2[pinfo] = plan(getInverseTransformsForPatch(pinfo));
373 eigen_vals.emplace(pinfo, getEigenValues(pinfo));
390 std::bitset<Side<D>::number_of> a_neumann;
391 std::bitset<Side<D>::number_of> b_neumann;
393 a_neumann[s.
getIndex()] = patchIsNeumannOnSide(a, s);
394 b_neumann[s.
getIndex()] = patchIsNeumannOnSide(b, s);
396 return std::forward_as_tuple(a_neumann.to_ulong(), a.
spacings[0]) <
397 std::forward_as_tuple(b_neumann.to_ulong(), b.spacings[0]);
400 plan1 = std::map<PatchInfo<D>,
401 std::array<std::shared_ptr<std::valarray<double>>, D>,
402 CompareFunction>(compare);
403 plan2 = std::map<PatchInfo<D>,
404 std::array<std::shared_ptr<std::valarray<double>>, D>,
405 CompareFunction>(compare);
406 eigen_vals = std::map<const PatchInfo<D>,
PatchArray<D>, CompareFunction>(compare);
409 for (
auto pinfo : this->
getDomain().getPatchInfoVector()) {
426 Loop::OverInteriorIndexes<D + 1>(
427 f_view, [&](std::array<int, D + 1> coord) { f_copy[coord] = f_view[coord]; });
429 op->modifyRHSForInternalBoundaryConditions(pinfo, u_view, f_copy.
getView());
434 Loop::OverInteriorIndexes<D + 1>(
435 tmp, [&](std::array<int, D + 1> coord) { tmp[coord] /= eigen_vals_view[coord]; });
437 if (neumann.all() && !pinfo.
hasNbr()) {
441 executePlan(plan2.at(pinfo), tmp.
getView(), u_view);
444 for (
size_t axis = 0; axis < D; axis++) {
445 scale *= 2.0 / this->
getDomain().getNs()[axis];
447 Loop::OverInteriorIndexes<D + 1>(u_view,
448 [&](std::array<int, D + 1> coord) { u_view[coord] *= scale; });
452 extern template class DFTPatchSolver<2>;
453 extern template class DFTPatchSolver<3>;