P4IVHOQ7CXP63QW2Q54MYFCXG5NJ76PGQXUM45TRXPMKNGQUKAHAC
REQUIRES Arith
// AMReX uses a weird Laplace stencil. It takes a second derivative in
// one direction, and smoothes with weights [1, 4, 1] / 6 in the other
// directions.
template <typename T>
T laplace(const GF3D<const T, 0, 0, 0> &u, const PointDesc &p) {
T r = 0;
for (int dir = 0; dir < dim; ++dir) {
vect<T, dim> lap{1, -2, 1};
lap /= pow(p.DX[dir], 2);
vect<T, dim> smo{1, 4, 1};
smo /= 6;
for (int k = -1; k <= 1; ++k) {
for (int j = -1; j <= 1; ++j) {
for (int i = -1; i <= 1; ++i) {
const vect<int, dim> di{i, j, k};
T w = 1;
for (int d = 0; d < dim; ++d)
if (d == dir)
w *= lap[1 + di[d]];
else
w *= smo[1 + di[d]];
auto I = p.I;
for (int d = 0; d < dim; ++d)
I += di[d] * p.DI(d);
r += w * u(I);
}
}
}
}
return r;
}
// extern "C" void Poisson_fixup(CCTK_ARGUMENTS) {
// DECLARE_CCTK_ARGUMENTS_Poisson_fixup;
// DECLARE_CCTK_PARAMETERS;
//
// const GF3D<CCTK_REAL, 0, 0, 0> phi_(cctkGH, phi);
//
// // Set boundary conditions
// loop_bnd<0, 0, 0>(
// cctkGH, [&](const PointDesc &p) { phi_(p.I) = fbnd(p.x, p.y, p.z); });
// }
ires_(p.I) = (phi_(p.I - p.DI(0)) - 2 * phi_(p.I) + phi_(p.I + p.DI(0))) /
pow(p.DX[0], 2) +
(phi_(p.I - p.DI(1)) - 2 * phi_(p.I) + phi_(p.I + p.DI(1))) /
pow(p.DX[1], 2) +
(phi_(p.I - p.DI(2)) - 2 * phi_(p.I) + phi_(p.I + p.DI(2))) /
pow(p.DX[2], 2) -
frhs(p.x, p.y, p.z);
ires_(p.I) = laplace(phi_, p) - frhs(p.x, p.y, p.z);