sandbox/acastillo/output_fields/tests_quantities/test_strain_rate_smooth.c
Testing
strain_rate_sq() on a smooth field
Where test_strain_rate_affine.c removes the truncation error to isolate the algebra, this checks the truncation error itself: on a smooth field the centred differences in strain_rate.h are second-order, so the error must fall as \Delta^2.
2D, from \psi = \cos(k_1 x)\cos(k_2 y) with \mathbf{u} = (\partial_y\psi, -\partial_x\psi):
S_{xx} = -S_{yy} = k_1k_2\sin(k_1x)\sin(k_2y), \qquad S_{xy} = \tfrac{1}{2}(k_1^2-k_2^2)\cos(k_1x)\cos(k_2y)
k_1 \neq k_2 is required: otherwise S_{xy} \equiv 0 and the off-diagonal strain goes untested. 3D uses the ABC flow, which has S_{xx} = S_{yy} = S_{zz} = 0 and all three off-diagonal terms non-zero; distinct A, B, C keep them from coinciding.
Cells are inset one layer from the boundary, since the stencil would
otherwise reach a ghost cell – which is also why no periodicity is
imposed. strain_rate_smooth.asc gets one row per
resolution, N err_max err_l2, both normalised by \max|S^2|; test_strain_rate.py
turns them into convergence orders.
#include "run.h"
#include "acastillo/output_fields/strain_rate.h"
double k1, k2, kabc;
double Aabc = 1.0, Babc = 2.0, Cabc = 3.0;
double S2_smooth (double x, double y, double z) {
#if dimension == 3
double Sxy = 0.5*kabc*(Babc*cos(kabc*x) - Cabc*sin(kabc*y));
double Sxz = 0.5*kabc*(Aabc*cos(kabc*z) - Babc*sin(kabc*x));
double Syz = 0.5*kabc*(Cabc*cos(kabc*y) - Aabc*sin(kabc*z));
return 2.*(sq(Sxy) + sq(Sxz) + sq(Syz));
#else
double Sxx = k1*k2*sin(k1*x)*sin(k2*y);
double Sxy = 0.5*(sq(k1) - sq(k2))*cos(k1*x)*cos(k2*y);
return 2.*(sq(Sxx) + sq(Sxy));
#endif
}
int main() {
L0 = 1.0;
X0 = Y0 = Z0 = -L0 / 2;
k1 = 2.*pi/L0;
k2 = 4.*pi/L0;
kabc = 2.*pi/L0;
FILE * fp = NULL;
if (pid() == 0) {
fp = fopen ("strain_rate_smooth.asc", "w");
fprintf (fp, "# N err_max err_l2\n");
}
// Three resolutions give two independent convergence rates. The coarsest 3D
// grid still resolves the single wavelength with 8 cells.
#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[];
foreach() {
#if dimension == 3
u.x[] = Aabc*sin(kabc*z) + Cabc*cos(kabc*y);
u.y[] = Babc*sin(kabc*x) + Aabc*cos(kabc*z);
u.z[] = Cabc*sin(kabc*y) + Babc*cos(kabc*x);
#else
u.x[] = -k2*cos(k1*x)*sin(k2*y);
u.y[] = k1*sin(k1*x)*cos(k2*y);
#endif
}
double err_max = 0., err_sq = 0., s2_max = 0., vol = 0.;
foreach (reduction(max:err_max) reduction(+:err_sq)
reduction(max:s2_max) reduction(+:vol)) {
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 s2_exact = S2_smooth (x, y, z);
double e = fabs (strain_rate_sq (point, u) - s2_exact);
if (e > err_max)
err_max = e;
if (fabs(s2_exact) > s2_max)
s2_max = fabs(s2_exact);
err_sq += dv()*sq(e);
vol += dv();
}
}
if (pid() == 0) {
fprintf (fp, "%d %.17g %.17g\n", Nres, err_max/s2_max,
sqrt(err_sq/vol)/s2_max);
fflush (fp);
}
}
if (pid() == 0) {
fclose (fp);The report goes to stderr, i.e. to the log diffed
against test_strain_rate_smooth.ref.
system ("python3 ../test_strain_rate.py "
"--smooth strain_rate_smooth.asc 1>&2");
}
}