Correction step¶
Updated but still non-solenoidal velocity field \(u_i^*\) is corrected to be divergence-free by solving a Poisson equation with respect to the scalar potential \(\phi\):
\[\frac{1}{J}
\dif{}{\gcs{1}}
\left(
\frac{J}{\sfact{1}}
\frac{1}{\sfact{1}}
\dif{\phi}{\gcs{1}}
\right)
+
\frac{1}{J}
\dif{}{\gcs{2}}
\left(
\frac{J}{\sfact{2}}
\frac{1}{\sfact{2}}
\dif{\phi}{\gcs{2}}
\right)
+
\frac{1}{J}
\dif{}{\gcs{3}}
\left(
\frac{J}{\sfact{3}}
\frac{1}{\sfact{3}}
\dif{\phi}{\gcs{3}}
\right)
=
\frac{1}{\Delta t}
\dif{\vel{i}^*}{\gcs{i}}.\]
The eigenvalues are computed as follows:
src/fluid/compute_potential.c¶
383size_t myjsize = 0;
384size_t myjoffs = 0;
385sdecomp.get_pencil_mysize(info, pencil, SDECOMP_YDIR, c_gl_sizes[SDECOMP_YDIR], &myjsize);
386sdecomp.get_pencil_offset(info, pencil, SDECOMP_YDIR, c_gl_sizes[SDECOMP_YDIR], &myjoffs);
387*eval_ys = memory_calloc(myjsize, sizeof(double));
388for(size_t local_n = 0; local_n < myjsize; local_n++){
389 const size_t global_n = local_n + myjoffs;
390 (*eval_ys)[local_n] =
391 - 4. * pow(
392 sin( g_pi * global_n / r_gl_sizes[SDECOMP_YDIR] ),
393 2.
394 );
395}
src/fluid/compute_potential.c¶
398size_t myksize = 0;
399size_t mykoffs = 0;
400sdecomp.get_pencil_mysize(info, pencil, SDECOMP_ZDIR, c_gl_sizes[SDECOMP_ZDIR], &myksize);
401sdecomp.get_pencil_offset(info, pencil, SDECOMP_ZDIR, c_gl_sizes[SDECOMP_ZDIR], &mykoffs);
402*eval_zs = memory_calloc(myksize, sizeof(double));
403for(size_t local_n = 0; local_n < myksize; local_n++){
404 const size_t global_n = local_n + mykoffs;
405 (*eval_zs)[local_n] =
406 - 4. * pow(
407 sin( g_pi * global_n / r_gl_sizes[SDECOMP_ZDIR] ),
408 2.
409 );
410}
In the radial direction, tri-diagonal matrices are to be solved for each \(y\) and \(z\):
src/fluid/compute_potential.c¶
575// set center diagonal components
576for(size_t i = 1; i <= isize; i++){
577 tdm_c[i-1] =
578 - tdm_l[i-1]
579 - tdm_u[i-1]
580 + eval_y / HYXC(i ) / HYXC(i );
581}
582// boundary treatment (Neumann boundary condition)
583tdm_c[ 0] += tdm_l[ 0];
584tdm_c[isize - 1] += tdm_u[isize - 1];
585// solve
586tdm.solve(tdm_info, rhs + j * isize);
src/fluid/compute_potential.c¶
594// set center diagonal components
595for(size_t i = 1; i <= isize; i++){
596 tdm_c[i-1] =
597 - tdm_l[i-1]
598 - tdm_u[i-1]
599 + eval_y / HYXC(i ) / HYXC(i )
600 + eval_z / hz / hz;
601}
602// boundary treatment (Neumann boundary condition)
603tdm_c[ 0] += tdm_l[ 0];
604tdm_c[isize - 1] += tdm_u[isize - 1];
605// solve
606tdm.solve(tdm_info, rhs + (k * jsize + j) * isize);
After computing the scalar potential \(\phi\), the velocity field is corrected using its gradient:
\[\pder{\phi}{x_i}
\approx
\vec{e_{\gcs{1}}}
\frac{1}{\sfact{1}}
\dif{\phi}{\gcs{1}}
+
\vec{e_{\gcs{2}}}
\frac{1}{\sfact{2}}
\dif{\phi}{\gcs{2}}
+
\vec{e_{\gcs{3}}}
\frac{1}{\sfact{3}}
\dif{\phi}{\gcs{3}}.\]
src/fluid/correct/ux.c¶
48 BEGIN
49 const double hx = HXXF(i );
50#if NDIMS == 2
51 const double psi_xm = PSI(i-1, j );
52 const double psi_xp = PSI(i , j );
53 double * vel = &UX(i, j);
54#else
55 const double psi_xm = PSI(i-1, j , k );
56 const double psi_xp = PSI(i , j , k );
57 double * vel = &UX(i, j, k);
58#endif
59 *vel -= prefactor / hx * (
60 - psi_xm
61 + psi_xp
62 );
63 END
src/fluid/correct/uy.c¶
48 BEGIN
49 const double hy = HYXC(i );
50#if NDIMS == 2
51 const double psi_ym = PSI(i , j-1);
52 const double psi_yp = PSI(i , j );
53 double * vel = &UY(i, j);
54#else
55 const double psi_ym = PSI(i , j-1, k );
56 const double psi_yp = PSI(i , j , k );
57 double * vel = &UY(i, j, k);
58#endif
59 *vel -= prefactor / hy * (
60 - psi_ym
61 + psi_yp
62 );
63 END
src/fluid/correct/uz.c¶
28for(int k = 1; k <= ksize; k++){
29 for(int j = 1; j <= jsize; j++){
30 for(int i = 1; i <= isize; i++){
31 const double psi_zm = PSI(i , j , k-1);
32 const double psi_zp = PSI(i , j , k );
33 UZ(i, j, k) -= prefactor / hz * (
34 - psi_zm
35 + psi_zp
36 );
37 }
38 }
39}