sandbox/acastillo/output_fields/tests_quantities/test_strain_rate_affine.c
Testing
strain_rate_sq() on an affine field
On u_i = A_{ij}x_j with \mathrm{tr}(A) = 0, the gradient is constant, so the centred differences in strain_rate.h are exact and
S^2 = S_{ij}S_{ij}, \qquad S_{ij} = \tfrac{1}{2}(A_{ij} + A_{ji})
is a single constant. Any error is then algebraic, not truncation.
The trace is zero because strain_rate_sq() does not remove
it. Convergence of the differences themselves is covered by test_strain_rate_smooth.c.
Cells are inset one layer from the boundary, since the stencil would
otherwise reach a ghost cell. strain_rate_affine.asc gets
one row per resolution, N err_rel, the max relative
deviation from the constant; test_strain_rate.py applies
the threshold.
#include "run.h"
#include "acastillo/output_fields/strain_rate.h"
#if dimension == 3
double A_aff[3][3] = {{ 0.7, 1.3, 0.5},
{ 0.4, -0.3, 0.9},
{ 0.2, 0.6, -0.4}};
#else
double A_aff[2][2] = {{ 0.7, 1.3},
{ 0.4, -0.7}};
#endif
int main() {
L0 = 1.0;
X0 = Y0 = Z0 = -L0 / 2;
// Contracted from A_aff, so it cannot drift from the coefficients.
double s2_exact = 0.;
for (int i = 0; i < dimension; i++)
for (int j = 0; j < dimension; j++)
s2_exact += sq (0.5*(A_aff[i][j] + A_aff[j][i]));
FILE * fp = NULL;
if (pid() == 0) {
fp = fopen ("strain_rate_affine.asc", "w");
fprintf (fp, "# N err_rel\n");
}
// Three resolutions, so a flat error is distinguishable from a small one.
#if dimension == 3
int Nmin = 8, Nmax = 32;
#else
int Nmin = 32, Nmax = 128;
#endif
for (int Nres = Nmin; Nres <= Nmax; Nres *= 2) {
init_grid (Nres);
vector u[];
// Component by component: the row of A_aff differs per component, which
// foreach_dimension() cannot express.
foreach() {
#if dimension == 3
double px = x, py = y, pz = z;
u.x[] = A_aff[0][0]*px + A_aff[0][1]*py + A_aff[0][2]*pz;
u.y[] = A_aff[1][0]*px + A_aff[1][1]*py + A_aff[1][2]*pz;
u.z[] = A_aff[2][0]*px + A_aff[2][1]*py + A_aff[2][2]*pz;
#else
double px = x, py = y;
u.x[] = A_aff[0][0]*px + A_aff[0][1]*py;
u.y[] = A_aff[1][0]*px + A_aff[1][1]*py;
#endif
}
double err_max = 0.;
foreach (reduction(max:err_max)) {
bool interior = fabs(x) < L0/2. - 1.1*Delta && fabs(y) < L0/2. - 1.1*Delta;
#if dimension == 3
interior = interior && fabs(z) < L0/2. - 1.1*Delta;
#endif
if (interior) {
double e = fabs (strain_rate_sq (point, u) - s2_exact);
if (e > err_max)
err_max = e;
}
}
if (pid() == 0) {
fprintf (fp, "%d %.17g\n", Nres, err_max/s2_exact);
fflush (fp);
}
}
if (pid() == 0) {
fclose (fp);The report goes to stderr, i.e. to the log diffed
against test_strain_rate_affine.ref.
system ("python3 ../test_strain_rate.py "
"--affine strain_rate_affine.asc 1>&2");
}
}