Linear System¶
To treat the diffusive terms implicitly, we need to solve a linear system:
\[\left\{
1
-
C
\frac{1}{J}
\dif{}{\gcs{i}}
\left(
\frac{J}{\sfact{i}}
\frac{1}{\sfact{i}}
\dif{}{\gcs{i}}
\right)
\right\}
p
=
q,\]
where \(C\) is a coefficient (e.g., coming from the diffusivity and time-step sizes).
Laplace Operators¶
Note that linear systems involve discrete Laplace operators:
\[\frac{1}{J}
\dif{}{\gcs{i}}
\left(
\frac{J}{\sfact{i}}
\frac{1}{\sfact{i}}
\dif{}{\gcs{i}}
\right),\]
which are pre-computed as follows.
Wall-normal velocity:
34const int isize = domain->glsizes[0];
35const double * hxxc = domain->hxxc;
36const double * jdxf = domain->jdxf;
37const double * jdxc = domain->jdxc;
38laplacians.lapx = memory_calloc(isize - 1, sizeof(laplacian_t));
39for (int i = 2; i <= isize; i++) {
40 const double l = 1. / JDXF(i ) * JDXC(i-1) / HXXC(i-1) / HXXC(i-1);
41 const double u = 1. / JDXF(i ) * JDXC(i ) / HXXC(i ) / HXXC(i );
42 const double c = - l - u;
43 laplacians.LAPX(i).l = l;
44 laplacians.LAPX(i).c = c;
45 laplacians.LAPX(i).u = u;
46}
50const double hy = domain->hy;
51const double l = 1. / hy / hy;
52const double u = 1. / hy / hy;
53const double c = - l - u;
54laplacians.lapy.l = l;
55laplacians.lapy.c = c;
56laplacians.lapy.u = u;
61const double hz = domain->hz;
62const double l = 1. / hz / hz;
63const double u = 1. / hz / hz;
64const double c = - l - u;
65laplacians.lapz.l = l;
66laplacians.lapz.c = c;
67laplacians.lapz.u = u;
Stream-wise velocity:
33const int isize = domain->glsizes[0];
34const double * hxxf = domain->hxxf;
35const double * jdxf = domain->jdxf;
36const double * jdxc = domain->jdxc;
37laplacians.lapx = memory_calloc(isize, sizeof(laplacian_t));
38for (int i = 1; i <= isize; i++) {
39 const double l = 1. / JDXC(i ) * JDXF(i ) / HXXF(i ) / HXXF(i );
40 const double u = 1. / JDXC(i ) * JDXF(i+1) / HXXF(i+1) / HXXF(i+1);
41 const double c = - l - u;
42 laplacians.LAPX(i).l = l;
43 laplacians.LAPX(i).c = c;
44 laplacians.LAPX(i).u = u;
45}
49const double hy = domain->hy;
50const double l = 1. / hy / hy;
51const double u = 1. / hy / hy;
52const double c = - l - u;
53laplacians.lapy.l = l;
54laplacians.lapy.c = c;
55laplacians.lapy.u = u;
60const double hz = domain->hz;
61const double l = 1. / hz / hz;
62const double u = 1. / hz / hz;
63const double c = - l - u;
64laplacians.lapz.l = l;
65laplacians.lapz.c = c;
66laplacians.lapz.u = u;
Span-wise velocity:
31const int isize = domain->glsizes[0];
32const double * hxxf = domain->hxxf;
33const double * jdxf = domain->jdxf;
34const double * jdxc = domain->jdxc;
35laplacians.lapx = memory_calloc(isize, sizeof(laplacian_t));
36for (int i = 1; i <= isize; i++) {
37 const double l = 1. / JDXC(i ) * JDXF(i ) / HXXF(i ) / HXXF(i );
38 const double u = 1. / JDXC(i ) * JDXF(i+1) / HXXF(i+1) / HXXF(i+1);
39 const double c = - l - u;
40 laplacians.LAPX(i).l = l;
41 laplacians.LAPX(i).c = c;
42 laplacians.LAPX(i).u = u;
43}
47const double hy = domain->hy;
48const double l = 1. / hy / hy;
49const double u = 1. / hy / hy;
50const double c = - l - u;
51laplacians.lapy.l = l;
52laplacians.lapy.c = c;
53laplacians.lapy.u = u;
57const double hz = domain->hz;
58const double l = 1. / hz / hz;
59const double u = 1. / hz / hz;
60const double c = - l - u;
61laplacians.lapz.l = l;
62laplacians.lapz.c = c;
63laplacians.lapz.u = u;
Temperature:
33const int isize = domain->glsizes[0];
34const double * hxxf = domain->hxxf;
35const double * jdxf = domain->jdxf;
36const double * jdxc = domain->jdxc;
37laplacians.lapx = memory_calloc(isize, sizeof(laplacian_t));
38for (int i = 1; i <= isize; i++) {
39 const double l = 1. / JDXC(i ) * JDXF(i ) / HXXF(i ) / HXXF(i );
40 const double u = 1. / JDXC(i ) * JDXF(i+1) / HXXF(i+1) / HXXF(i+1);
41 const double c = - l - u;
42 laplacians.LAPX(i).l = l;
43 laplacians.LAPX(i).c = c;
44 laplacians.LAPX(i).u = u;
45}
49const double hy = domain->hy;
50const double l = 1. / hy / hy;
51const double u = 1. / hy / hy;
52const double c = - l - u;
53laplacians.lapy.l = l;
54laplacians.lapy.c = c;
55laplacians.lapy.u = u;
60const double hz = domain->hz;
61const double l = 1. / hz / hz;
62const double u = 1. / hz / hz;
63const double c = - l - u;
64laplacians.lapz.l = l;
65laplacians.lapz.c = c;
66laplacians.lapz.u = u;
Solving Linear Systems¶
Wall-normal velocity:
465if (param_m_implicit_x) {
466 tdm_info_t * tdm_info = linear_system.tdm_x;
467 int size = 0;
468 double * restrict tdm_l = NULL;
469 double * restrict tdm_c = NULL;
470 double * restrict tdm_u = NULL;
471 tdm.get_size(tdm_info, &size);
472 tdm.get_l(tdm_info, &tdm_l);
473 tdm.get_c(tdm_info, &tdm_c);
474 tdm.get_u(tdm_info, &tdm_u);
475 const laplacian_t * lapx = laplacians.lapx;
476 for (int i = 0; i < size; i++) {
477 tdm_l[i] = - prefactor * lapx[i].l;
478 tdm_c[i] = 1. - prefactor * lapx[i].c;
479 tdm_u[i] = - prefactor * lapx[i].u;
480 }
481 tdm.solve(tdm_info, linear_system.x1pncl);
482}
484if (param_m_implicit_y) {
485 sdecomp.transpose.execute(
486 linear_system.transposer_x1_to_y1,
487 linear_system.x1pncl,
488 linear_system.y1pncl
489 );
490 tdm_info_t * tdm_info = linear_system.tdm_y;
491 int size = 0;
492 double * restrict tdm_l = NULL;
493 double * restrict tdm_c = NULL;
494 double * restrict tdm_u = NULL;
495 tdm.get_size(tdm_info, &size);
496 tdm.get_l(tdm_info, &tdm_l);
497 tdm.get_c(tdm_info, &tdm_c);
498 tdm.get_u(tdm_info, &tdm_u);
499 const laplacian_t * lapy = &laplacians.lapy;
500 for (int j = 0; j < size; j++) {
501 tdm_l[j] = - prefactor * (*lapy).l;
502 tdm_c[j] = 1. - prefactor * (*lapy).c;
503 tdm_u[j] = - prefactor * (*lapy).u;
504 }
505 tdm.solve(tdm_info, linear_system.y1pncl);
506 sdecomp.transpose.execute(
507 linear_system.transposer_y1_to_x1,
508 linear_system.y1pncl,
509 linear_system.x1pncl
510 );
511}
514if (param_m_implicit_z) {
515 sdecomp.transpose.execute(
516 linear_system.transposer_x1_to_z2,
517 linear_system.x1pncl,
518 linear_system.z2pncl
519 );
520 tdm_info_t * tdm_info = linear_system.tdm_z;
521 int size = 0;
522 double * restrict tdm_l = NULL;
523 double * restrict tdm_c = NULL;
524 double * restrict tdm_u = NULL;
525 tdm.get_size(tdm_info, &size);
526 tdm.get_l(tdm_info, &tdm_l);
527 tdm.get_c(tdm_info, &tdm_c);
528 tdm.get_u(tdm_info, &tdm_u);
529 const laplacian_t * lapz = &laplacians.lapz;
530 for (int k = 0; k < size; k++) {
531 tdm_l[k] = - prefactor * (*lapz).l;
532 tdm_c[k] = 1. - prefactor * (*lapz).c;
533 tdm_u[k] = - prefactor * (*lapz).u;
534 }
535 tdm.solve(tdm_info, linear_system.z2pncl);
536 sdecomp.transpose.execute(
537 linear_system.transposer_z2_to_x1,
538 linear_system.z2pncl,
539 linear_system.x1pncl
540 );
541}
Stream-wise velocity:
424if (param_m_implicit_x) {
425 tdm_info_t * tdm_info = linear_system.tdm_x;
426 int size = 0;
427 double * restrict tdm_l = NULL;
428 double * restrict tdm_c = NULL;
429 double * restrict tdm_u = NULL;
430 tdm.get_size(tdm_info, &size);
431 tdm.get_l(tdm_info, &tdm_l);
432 tdm.get_c(tdm_info, &tdm_c);
433 tdm.get_u(tdm_info, &tdm_u);
434 const laplacian_t * lapx = laplacians.lapx;
435 for (int i = 0; i < size; i++) {
436 tdm_l[i] = - prefactor * lapx[i].l;
437 tdm_c[i] = 1. - prefactor * lapx[i].c;
438 tdm_u[i] = - prefactor * lapx[i].u;
439 }
440 tdm.solve(tdm_info, linear_system.x1pncl);
441}
443if (param_m_implicit_y) {
444 sdecomp.transpose.execute(
445 linear_system.transposer_x1_to_y1,
446 linear_system.x1pncl,
447 linear_system.y1pncl
448 );
449 tdm_info_t * tdm_info = linear_system.tdm_y;
450 int size = 0;
451 double * restrict tdm_l = NULL;
452 double * restrict tdm_c = NULL;
453 double * restrict tdm_u = NULL;
454 tdm.get_size(tdm_info, &size);
455 tdm.get_l(tdm_info, &tdm_l);
456 tdm.get_c(tdm_info, &tdm_c);
457 tdm.get_u(tdm_info, &tdm_u);
458 const laplacian_t * lapy = &laplacians.lapy;
459 for (int j = 0; j < size; j++) {
460 tdm_l[j] = - prefactor * (*lapy).l;
461 tdm_c[j] = 1. - prefactor * (*lapy).c;
462 tdm_u[j] = - prefactor * (*lapy).u;
463 }
464 tdm.solve(tdm_info, linear_system.y1pncl);
465 sdecomp.transpose.execute(
466 linear_system.transposer_y1_to_x1,
467 linear_system.y1pncl,
468 linear_system.x1pncl
469 );
470}
473if (param_m_implicit_z) {
474 sdecomp.transpose.execute(
475 linear_system.transposer_x1_to_z2,
476 linear_system.x1pncl,
477 linear_system.z2pncl
478 );
479 tdm_info_t * tdm_info = linear_system.tdm_z;
480 int size = 0;
481 double * restrict tdm_l = NULL;
482 double * restrict tdm_c = NULL;
483 double * restrict tdm_u = NULL;
484 tdm.get_size(tdm_info, &size);
485 tdm.get_l(tdm_info, &tdm_l);
486 tdm.get_c(tdm_info, &tdm_c);
487 tdm.get_u(tdm_info, &tdm_u);
488 const laplacian_t * lapz = &laplacians.lapz;
489 for (int k = 0; k < size; k++) {
490 tdm_l[k] = - prefactor * (*lapz).l;
491 tdm_c[k] = 1. - prefactor * (*lapz).c;
492 tdm_u[k] = - prefactor * (*lapz).u;
493 }
494 tdm.solve(tdm_info, linear_system.z2pncl);
495 sdecomp.transpose.execute(
496 linear_system.transposer_z2_to_x1,
497 linear_system.z2pncl,
498 linear_system.x1pncl
499 );
500}
Span-wise velocity:
338if (param_m_implicit_x) {
339 tdm_info_t * tdm_info = linear_system.tdm_x;
340 int size = 0;
341 double * restrict tdm_l = NULL;
342 double * restrict tdm_c = NULL;
343 double * restrict tdm_u = NULL;
344 tdm.get_size(tdm_info, &size);
345 tdm.get_l(tdm_info, &tdm_l);
346 tdm.get_c(tdm_info, &tdm_c);
347 tdm.get_u(tdm_info, &tdm_u);
348 const laplacian_t * lapx = laplacians.lapx;
349 for (int i = 0; i < size; i++) {
350 tdm_l[i] = - prefactor * lapx[i].l;
351 tdm_c[i] = 1. - prefactor * lapx[i].c;
352 tdm_u[i] = - prefactor * lapx[i].u;
353 }
354 tdm.solve(tdm_info, linear_system.x1pncl);
355}
357if (param_m_implicit_y) {
358 sdecomp.transpose.execute(
359 linear_system.transposer_x1_to_y1,
360 linear_system.x1pncl,
361 linear_system.y1pncl
362 );
363 tdm_info_t * tdm_info = linear_system.tdm_y;
364 int size = 0;
365 double * restrict tdm_l = NULL;
366 double * restrict tdm_c = NULL;
367 double * restrict tdm_u = NULL;
368 tdm.get_size(tdm_info, &size);
369 tdm.get_l(tdm_info, &tdm_l);
370 tdm.get_c(tdm_info, &tdm_c);
371 tdm.get_u(tdm_info, &tdm_u);
372 const laplacian_t * lapy = &laplacians.lapy;
373 for (int j = 0; j < size; j++) {
374 tdm_l[j] = - prefactor * (*lapy).l;
375 tdm_c[j] = 1. - prefactor * (*lapy).c;
376 tdm_u[j] = - prefactor * (*lapy).u;
377 }
378 tdm.solve(tdm_info, linear_system.y1pncl);
379 sdecomp.transpose.execute(
380 linear_system.transposer_y1_to_x1,
381 linear_system.y1pncl,
382 linear_system.x1pncl
383 );
384}
386if (param_m_implicit_z) {
387 sdecomp.transpose.execute(
388 linear_system.transposer_x1_to_z2,
389 linear_system.x1pncl,
390 linear_system.z2pncl
391 );
392 tdm_info_t * tdm_info = linear_system.tdm_z;
393 int size = 0;
394 double * restrict tdm_l = NULL;
395 double * restrict tdm_c = NULL;
396 double * restrict tdm_u = NULL;
397 tdm.get_size(tdm_info, &size);
398 tdm.get_l(tdm_info, &tdm_l);
399 tdm.get_c(tdm_info, &tdm_c);
400 tdm.get_u(tdm_info, &tdm_u);
401 const laplacian_t * lapz = &laplacians.lapz;
402 for (int k = 0; k < size; k++) {
403 tdm_l[k] = - prefactor * (*lapz).l;
404 tdm_c[k] = 1. - prefactor * (*lapz).c;
405 tdm_u[k] = - prefactor * (*lapz).u;
406 }
407 tdm.solve(tdm_info, linear_system.z2pncl);
408 sdecomp.transpose.execute(
409 linear_system.transposer_z2_to_x1,
410 linear_system.z2pncl,
411 linear_system.x1pncl
412 );
413}
Temperature:
390if (param_t_implicit_x) {
391 // prepare tri-diagonal coefficients
392 tdm_info_t * tdm_info = linear_system.tdm_x;
393 int size = 0;
394 double * restrict tdm_l = NULL;
395 double * restrict tdm_c = NULL;
396 double * restrict tdm_u = NULL;
397 tdm.get_size(tdm_info, &size);
398 tdm.get_l(tdm_info, &tdm_l);
399 tdm.get_c(tdm_info, &tdm_c);
400 tdm.get_u(tdm_info, &tdm_u);
401 const laplacian_t * lapx = laplacians.lapx;
402 for (int i = 0; i < size; i++) {
403 tdm_l[i] = - prefactor * lapx[i].l;
404 tdm_c[i] = 1. - prefactor * lapx[i].c;
405 tdm_u[i] = - prefactor * lapx[i].u;
406 }
407 // solve all
408 tdm.solve(tdm_info, linear_system.x1pncl);
409}
411if (param_t_implicit_y) {
412 // make all y data accessible
413 sdecomp.transpose.execute(
414 linear_system.transposer_x1_to_y1,
415 linear_system.x1pncl,
416 linear_system.y1pncl
417 );
418 // prepare tri-diagonal coefficients
419 tdm_info_t * tdm_info = linear_system.tdm_y;
420 int size = 0;
421 double * restrict tdm_l = NULL;
422 double * restrict tdm_c = NULL;
423 double * restrict tdm_u = NULL;
424 tdm.get_size(tdm_info, &size);
425 tdm.get_l(tdm_info, &tdm_l);
426 tdm.get_c(tdm_info, &tdm_c);
427 tdm.get_u(tdm_info, &tdm_u);
428 const laplacian_t * lapy = &laplacians.lapy;
429 for (int j = 0; j < size; j++) {
430 tdm_l[j] = - prefactor * (*lapy).l;
431 tdm_c[j] = 1. - prefactor * (*lapy).c;
432 tdm_u[j] = - prefactor * (*lapy).u;
433 }
434 // solve all
435 tdm.solve(tdm_info, linear_system.y1pncl);
436 // recover original memory alignment
437 sdecomp.transpose.execute(
438 linear_system.transposer_y1_to_x1,
439 linear_system.y1pncl,
440 linear_system.x1pncl
441 );
442}
445if (param_t_implicit_z) {
446 // make all z data accessible
447 sdecomp.transpose.execute(
448 linear_system.transposer_x1_to_z2,
449 linear_system.x1pncl,
450 linear_system.z2pncl
451 );
452 // prepare tri-diagonal coefficients
453 tdm_info_t * tdm_info = linear_system.tdm_z;
454 int size = 0;
455 double * restrict tdm_l = NULL;
456 double * restrict tdm_c = NULL;
457 double * restrict tdm_u = NULL;
458 tdm.get_size(tdm_info, &size);
459 tdm.get_l(tdm_info, &tdm_l);
460 tdm.get_c(tdm_info, &tdm_c);
461 tdm.get_u(tdm_info, &tdm_u);
462 const laplacian_t * lapz = &laplacians.lapz;
463 for (int k = 0; k < size; k++) {
464 tdm_l[k] = - prefactor * (*lapz).l;
465 tdm_c[k] = 1. - prefactor * (*lapz).c;
466 tdm_u[k] = - prefactor * (*lapz).u;
467 }
468 // solve all
469 tdm.solve(tdm_info, linear_system.z2pncl);
470 // recover original memory alignment
471 sdecomp.transpose.execute(
472 linear_system.transposer_z2_to_x1,
473 linear_system.z2pncl,
474 linear_system.x1pncl
475 );
476}
We need to solve tri-diagonal matrix.