Equations in Strong Conservation Form¶
As explained in the domain setup, non-uniform grid spacings are adopted in the wall-normal direction to resolve boundary layers. This makes interpolations of quantities ambiguous, as linear interpolations, arithmetic averages, and volumetric averages all yield different results. As Ham et al., J. Comput. Phys. (177), 2002 pointed out, to obtain discrete advective terms that are energy-conserving, we need to utilize the volumetric averages to average some quantities, while arithmetic averages should be used for others, which is cumbersome and error-prone to implement. To mitigate this issue, we perform a coordinate transform from the original coordinate (physical coordinate) to a new coordinate (computational coordinate):
Since the cell-face distances are always unity in the new coordinate system, arithmetic averages suffice for all interpolations. This is a versatile approach and is applicable to the other coordinate systems as well.
Note, however, that the new coordinate system has different basis vectors compared to the original system. The wall-normal basis vectors in the physical coordinate system are \(\basis{1}\) with a unique length everywhere, while \(\gbasis{1}\) varies in size. We need to take this kind of stretching of the coordinates into account. To this end, we write down the governing equations in a more general way, incorporating the spatial changes in the basis vectors (strong conservation form for rectilinear coordinates), giving the following relations:
\(\gvel{i}\) are the contra-variant components of the velocity vector with co-variant basis vectors, i.e.,
The basis vectors and the components of the two coordinate systems are related by
or for rectilinear coordinates simply
where \(\sfact{i}\) is the scale factor. Since we design the computational coordinate systems such that the grid sizes are unitary, the scale factors are given by the grid sizes in the physical coordinates:
which are implemented in the code as follows.
Note that, since the wall-normal grid sizes may differ, the wall-normal scale factors \(\sfact{1}\) are stored at every wall-normal cell face and center. At the faces, we calculate them using the cell-center distance
256static double * allocate_and_init_hxxf (
257 const int isize,
258 const double * xc
259) {
260 double * hxxf = memory_calloc(isize + 1, sizeof(double));
261 for (int i = 1; i <= isize + 1; i++) {
262 HXXF(i ) = XC(i ) - XC(i-1);
263 }
264 return hxxf;
265}
At the centers, we calculate them using the cell-face distance
268static double * allocate_and_init_hxxc (
269 const int isize,
270 const double * xf
271) {
272 double * hxxc = memory_calloc(isize, sizeof(double));
273 for (int i = 1; i <= isize; i++) {
274 HXXC(i ) = XF(i+1) - XF(i );
275 }
276 return hxxc;
277}
The scale factors in the other directions (\(\sfact{2}, \sfact{3}\)) are constant across the whole domain as we fix the grid sizes equidistant:
375*hy = lengths[1] / glsizes[1];
378*hz = lengths[2] / glsizes[2];
Note that, by definition, the Jacobian determinant is given by
which are implemented in the code as follows. Note that they are also defined at the wall-normal cell faces and centers:
280static double * allocate_and_init_jdxf (
281 const int isize,
282 const double * hxxf,
283#if NDIMS == 2
284 const double hy
285#else
286 const double hy,
287 const double hz
288#endif
289) {
290 double * jdxf = memory_calloc(isize + 1, sizeof(double));
291 for (int i = 1; i <= isize + 1; i++) {
292#if NDIMS == 2
293 JDXF(i ) = HXXF(i ) * hy;
294#else
295 JDXF(i ) = HXXF(i ) * hy * hz;
296#endif
297 }
298 return jdxf;
299}
302static double * allocate_and_init_jdxc (
303 const int isize,
304 const double * hxxc,
305#if NDIMS == 2
306 const double hy
307#else
308 const double hy,
309 const double hz
310#endif
311) {
312 double * jdxc = memory_calloc(isize, sizeof(double));
313 for (int i = 1; i <= isize; i++) {
314#if NDIMS == 2
315 JDXC(i ) = HXXC(i ) * hy;
316#else
317 JDXC(i ) = HXXC(i ) * hy * hz;
318#endif
319 }
320 return jdxc;
321}
Finally, since we usually discuss everything on the physical coordinate systems rather than on the computational coordinate systems, it is convenient to keep the velocity vector descriptions using \(\vel{i}\) rather than \(\gvel{i}\), giving
as a set of conclusive equations.
See also
For detailed derivation of the mentioned relations, visit this page.