[petsc-users] How to set boundary conditions for a structured finite volume (FV) discretization when using TS/SNES?

zhfreewill zhfreewill at gmail.com
Fri Nov 26 03:02:21 CST 2021


Hi all,
I have a basic question on how to apply B.C. for a cell-centered structured
FV discretization when using the SNES and Ts object.
For instance, for a 1-D transient diffusion equation

*u_t = u_xx, 0 < x < 1*

with IC:

*u(x,t=0) = 0;*

and Dirichlet BC:

*u(x=0) = u_A = 0.0;*
*u(x=1) = u_B = 1.0;*

or Neumann BC:

*du/dx(x=0.0) = q_A = 0.0;*
*du/dx(x=1.0) = q_B = 1.0;*


When using TS of PETSc, the equation can be organized in form of
    *U_t = G(t,u)*
where *G* is the right-hand-side (RHS) function regardless of the specific
method of discretization.
*(1) For FD discretization*

*A               |---dx--|               B*
*|-------|-------|-------|-------|-------| grid size = nx*
*0              i-1      i      i+1     nx-1*

the vertex-centered FD discretization of the domain is

*x(i) = i*dx (i = 0,..., nx)), where dx = 1/nx*

and the RHS function G of the equation is

*G[i] = (u[i+1]-2*u[i]+u[i-1])/dx^2*

There have been dozens of examples demonstrating way of BC setting with a
finite difference medthod, e.g.,
https://github.com/petsc/petsc/blob/386ebab930a846575609b49074a40c46e7f8ed75/src/ts/tutorials/ex26.c#L293-L343
which I think I have understood how it works and the following lines of
code evaluate the RHS function *G(t,u)* in PETSc's *TSSetRHSFunction()*
routine
/*------------------FD discretization-------------------------*/
*for (i = xs; i < xs + xm; i++) {*

*// left boundary*
*if (i == 0) {*

*G[i] = u[i] - u_A;                **// Dirichlet BC: u(x=0) = u_A;*
*G[i] = (u[i] - u[i+1])/dx - q_A;  **// Neumann BC:   du/dx(x=0.0) = q_A;*

*} *
*// right boundary*
*else if (i == mx - 1) {*

*G[i] = u[i] - u_B;                **// Dirichlet BC: u(x=1.0) = u_B;*
*G[i] = (u[i]-u[i-1])/dx - q_B;    **// Neumann BC:   du/dx(x=0.0) = q_A;*

*}*
*// internal*
*else {*

*G[i] = (u[i-1] - 2 * u[i] + u[i + 1])/dx^2; **//u_xx*

*}*

*}**/*------------------------------------------------------------*/*

The BCs, e.g., at the left boudnary, can be straightforwardly set as
follows:
Dirichlet BC:
    *G[0] = u[0] - u_A*
    which indicates *G[0] = u[0] - u_A = 0* and Dirichlet BC *u[0] = u_A* is
thus applied
Neumann BC:
    *G[0] = (u[0] - u[1])/dx - q_A*
    which indicates *G[0] = (u[0] - u[1])/dx - q_A = 0* and Neumann BC *du/dx
= (u[0] - u[1])/dx = q_A* is applied
This is the way the above examples apply BCs.

For a structured, cell-centered FVM discretization, however, I tried and
found the BCs can not be applied in a similar way. I will explain how I
tried this as follows.
*(2) FV discretization*

*A               |---dx--|               B*
*|---o---|---o---|---o---|---o---|---o---| cell size = nx*
*W   w   P   e   E           *
*0      i-1      i      i+1     nx-1*

(NOTE: the center cell is denoted as P and its neighbouring cells as W, E; cell
faces are denoted as w, e; the left and right boundary faces are A and B,
respectively.)

The cell-centered FV discretization of the domain is

*x(i) = dx/2 + i*dx (i = 0,..., nx-1)), where dx = 1/nx*

the diffusion term u_xx can be reorganized by using divergence theorem

*(u_E-u_P)   (u_P-u_W)*
*--------- - ---------*
*    dx         dx*

and the RHS function G of the equation is

*G[i] = (u_E-u_P)/dx - (u_P-u_W)/dx = (u[i+1]-2*u[i]+u[i-1])/dx*

the key lines of code in RHS function G(t,u) in PETSc's *TSSetRHSFunction()*
 routine can be

*/*------------------FV discretization-------------------------*/*
*for (i = xs; i < xs + xm; i++) {*

*// left boundary*
*if (i == 0) {*

*G[i] = 3.0 * u[i] - u[i+1] - 2.0 * u_A; **//Dirichlet BC: u(x=0.0) = u_A,
does not work*
*G[i] = (u[i+1] - u[i]) - q_A;           **//Neumann BC:   du/dx(x=0.0) =
q_A;*

*}*
*// right boundary*
*else if (i == mx - 1) {*

*G[i] = 3.0 * u[i] - u[i-1] - 2.0 * u_B; **//Dirichlet BC: u(x=1.0) = u_B,
does not work*
*G[i] = (u[i]-u[i-1])/dx - q_B;          **//Neumann BC:   du/dx(x=1.0) =
q_B, does not work*

*}*
*// internal*
*else {*

*G[i] = (u[i-1] - 2*u[i] + u[i+1])/dx;   **//u_x*

*}*

*}**/*------------------------------------------------------------*/*

I tried to apply BCs in a way similar to that of the FD discretization.
For the Dirichlet BC on the left boundary, because of the cell-centered
arrangement of u[i], the left BC is given as *u_A* at cell face A instead
of cell center.
So, I first applied a linear interpolation to get the cell-centered value
of *u[0]* from the left boundary value *u_A* and neighbouring *u[1]*

    *u[0] = (u[1]+2*u_A)/3.0 (equivalent to 3*u[0] - u[1] - 2*u_A = 0.0)*

*    |-dx/2-|------dx-----|*
*    |------o------|------o------| linear interpolation: u[0] =
(u[1]+2*u_A)/3.0*
*    A      P      e      E*
*   u_A   u[0]          u[1]*

Dirichlet BC:
    *G[0] = 3.0*u[0] - u[1] - 2.0*u_A*
    in which *u[0] = (u[1]+2*u_A)/3.0* is implicitly calculated and I
expect the Dirichlet BC *u(x=0) = u_A* is applied

For the Neumann BC, left BC is given as a gradient of *u*, *q_A*, at cell
face A
Neumann BC:
    *G[i] = (u[1] - u[0])/dx - q_A*
    in which Neumann BC *du/dx = (u[1] - u[0])/dx = q_A* is expected to be
applied.

However, this FV discretization failed to work. Is there anything
wrong or could
you give me a hint?

Best,
Qw
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mcs.anl.gov/pipermail/petsc-users/attachments/20211126/f8c408e4/attachment-0001.html>


More information about the petsc-users mailing list