Date: 2025-03-28T21:11:18+00:00

Actual source code: ex32.c

      1: static char help[] = "Solves a time-dependent linear PDE with discontinuous right-hand side.\n";

      3: /* ------------------------------------------------------------------------

      5:    This program solves the one-dimensional quench front problem modeling a cooled
      6:    liquid rising on a hot metal rod
      7:        u_t = u_xx + g(u),
      8:    with
      9:        g(u) = -Au if u <= u_c,
     10:             =   0 if u >  u_c
     11:    on the domain 0 <= x <= 1, with the boundary conditions
     12:        u(t,0) = 0, u_x(t,1) = 0,
     13:    and the initial condition
     14:        u(0,x) = 0              if 0 <= x <= 0.1,
     15:               = (x - 0.1)/0.15 if 0.1 < x < 0.25
     16:               = 1              if 0.25 <= x <= 1
     17:    We discretize the right-hand side using finite differences with
     18:    uniform grid spacing h:
     19:        u_xx = (u_{i+1} - 2u_{i} + u_{i-1})/(h^2)

     21: Reference: L. Shampine and S. Thompson, "Event Location for Ordinary Differential Equations",
     22:            http://www.radford.edu/~thompson/webddes/eventsweb.pdf
     23:   ------------------------------------------------------------------------- */

     25: #include <petscdmda.h>
     26: #include <petscts.h>
     27: /*
     28:    User-defined application context - contains data needed by the
     29:    application-provided call-back routines.
     30: */
     31: typedef struct {
     32:   PetscReal A;
     33:   PetscReal uc;
     34:   PetscInt *sw;
     35: } AppCtx;

     37: PetscErrorCode InitialConditions(Vec U, DM da, AppCtx *app)
     38: {
     39:   Vec          xcoord;
     40:   PetscScalar *x, *u;
     41:   PetscInt     lsize, M, xs, xm, i;

     43:   PetscFunctionBeginUser;
     44:   PetscCall(DMGetCoordinates(da, &xcoord));
     45:   PetscCall(DMDAVecGetArrayRead(da, xcoord, &x));

     47:   PetscCall(VecGetLocalSize(U, &lsize));
     48:   PetscCall(PetscMalloc1(lsize, &app->sw));

     50:   PetscCall(DMDAVecGetArray(da, U, &u));

     52:   PetscCall(DMDAGetInfo(da, 0, &M, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
     53:   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));

     55:   for (i = xs; i < xs + xm; i++) {
     56:     if (x[i] <= 0.1) u[i] = 0.;
     57:     else if (x[i] > 0.1 && x[i] < 0.25) u[i] = (x[i] - 0.1) / 0.15;
     58:     else u[i] = 1.0;

     60:     app->sw[i - xs] = 1;
     61:   }
     62:   PetscCall(DMDAVecRestoreArray(da, U, &u));
     63:   PetscCall(DMDAVecRestoreArrayRead(da, xcoord, &x));
     64:   PetscFunctionReturn(PETSC_SUCCESS);
     65: }

     67: PetscErrorCode EventFunction(TS ts, PetscReal t, Vec U, PetscReal *fvalue, void *ctx)
     68: {
     69:   AppCtx            *app = (AppCtx *)ctx;
     70:   const PetscScalar *u;
     71:   PetscInt           i, lsize;

     73:   PetscFunctionBeginUser;
     74:   PetscCall(VecGetLocalSize(U, &lsize));
     75:   PetscCall(VecGetArrayRead(U, &u));
     76:   for (i = 0; i < lsize; i++) fvalue[i] = PetscRealPart(u[i]) - app->uc;
     77:   PetscCall(VecRestoreArrayRead(U, &u));
     78:   PetscFunctionReturn(PETSC_SUCCESS);
     79: }

     81: PetscErrorCode PostEventFunction(TS ts, PetscInt nevents_zero, PetscInt events_zero[], PetscReal t, Vec U, PetscBool forwardsolve, void *ctx)
     82: {
     83:   AppCtx  *app = (AppCtx *)ctx;
     84:   PetscInt i, idx;

     86:   PetscFunctionBeginUser;
     87:   for (i = 0; i < nevents_zero; i++) {
     88:     idx          = events_zero[i];
     89:     app->sw[idx] = 0;
     90:   }
     91:   PetscFunctionReturn(PETSC_SUCCESS);
     92: }

     94: /*
     95:      Defines the ODE passed to the ODE solver
     96: */
     97: static PetscErrorCode IFunction(TS ts, PetscReal t, Vec U, Vec Udot, Vec F, void *ctx)
     98: {
     99:   AppCtx            *app = (AppCtx *)ctx;
    100:   PetscScalar       *f;
    101:   const PetscScalar *u, *udot;
    102:   DM                 da;
    103:   PetscInt           M, xs, xm, i;
    104:   PetscReal          h, h2;
    105:   Vec                Ulocal;

    107:   PetscFunctionBeginUser;
    108:   PetscCall(TSGetDM(ts, &da));

    110:   PetscCall(DMDAGetInfo(da, 0, &M, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
    111:   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));

    113:   PetscCall(DMGetLocalVector(da, &Ulocal));
    114:   PetscCall(DMGlobalToLocalBegin(da, U, INSERT_VALUES, Ulocal));
    115:   PetscCall(DMGlobalToLocalEnd(da, U, INSERT_VALUES, Ulocal));

    117:   h  = 1.0 / (M - 1);
    118:   h2 = h * h;
    119:   PetscCall(DMDAVecGetArrayRead(da, Udot, &udot));
    120:   PetscCall(DMDAVecGetArrayRead(da, Ulocal, &u));
    121:   PetscCall(DMDAVecGetArray(da, F, &f));

    123:   for (i = xs; i < xs + xm; i++) {
    124:     if (i == 0) {
    125:       f[i] = u[i];
    126:     } else if (i == M - 1) {
    127:       f[i] = (u[i] - u[i - 1]) / h;
    128:     } else {
    129:       f[i] = (u[i + 1] - 2 * u[i] + u[i - 1]) / h2 + app->sw[i - xs] * (-app->A * u[i]) - udot[i];
    130:     }
    131:   }

    133:   PetscCall(DMDAVecRestoreArrayRead(da, Udot, &udot));
    134:   PetscCall(DMDAVecRestoreArrayRead(da, Ulocal, &u));
    135:   PetscCall(DMDAVecRestoreArray(da, F, &f));
    136:   PetscCall(DMRestoreLocalVector(da, &Ulocal));
    137:   PetscFunctionReturn(PETSC_SUCCESS);
    138: }

    140: /*
    141:      Defines the Jacobian of the ODE passed to the ODE solver. See TSSetIJacobian() for the meaning of a and the Jacobian.
    142: */
    143: static PetscErrorCode IJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal a, Mat A, Mat B, void *ctx)
    144: {
    145:   AppCtx     *app = (AppCtx *)ctx;
    146:   DM          da;
    147:   MatStencil  row, col[3];
    148:   PetscScalar v[3];
    149:   PetscInt    M, xs, xm, i;
    150:   PetscReal   h, h2;

    152:   PetscFunctionBeginUser;
    153:   PetscCall(TSGetDM(ts, &da));

    155:   PetscCall(DMDAGetInfo(da, 0, &M, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
    156:   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));

    158:   h  = 1.0 / (M - 1);
    159:   h2 = h * h;
    160:   for (i = xs; i < xs + xm; i++) {
    161:     row.i = i;
    162:     if (i == 0) {
    163:       v[0] = 1.0;
    164:       PetscCall(MatSetValuesStencil(A, 1, &row, 1, &row, v, INSERT_VALUES));
    165:     } else if (i == M - 1) {
    166:       col[0].i = i;
    167:       v[0]     = 1 / h;
    168:       col[1].i = i - 1;
    169:       v[1]     = -1 / h;
    170:       PetscCall(MatSetValuesStencil(A, 1, &row, 2, col, v, INSERT_VALUES));
    171:     } else {
    172:       col[0].i = i + 1;
    173:       v[0]     = 1 / h2;
    174:       col[1].i = i;
    175:       v[1]     = -2 / h2 + app->sw[i - xs] * (-app->A) - a;
    176:       col[2].i = i - 1;
    177:       v[2]     = 1 / h2;
    178:       PetscCall(MatSetValuesStencil(A, 1, &row, 3, col, v, INSERT_VALUES));
    179:     }
    180:   }
    181:   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
    182:   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
    183:   PetscFunctionReturn(PETSC_SUCCESS);
    184: }

    186: int main(int argc, char **argv)
    187: {
    188:   TS       ts; /* ODE integrator */
    189:   Vec      U;  /* solution will be stored here */
    190:   Mat      J;  /* Jacobian matrix */
    191:   PetscInt n = 16;
    192:   AppCtx   app;
    193:   DM       da;

    195:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    196:      Initialize program
    197:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    198:   PetscFunctionBeginUser;
    199:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));

    201:   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "ex22 options", "");
    202:   {
    203:     app.A = 200000;
    204:     PetscCall(PetscOptionsReal("-A", "", "", app.A, &app.A, NULL));
    205:     app.uc = 0.5;
    206:     PetscCall(PetscOptionsReal("-uc", "", "", app.uc, &app.uc, NULL));
    207:   }
    208:   PetscOptionsEnd();

    210:   PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, -n, 1, 1, 0, &da));
    211:   PetscCall(DMSetFromOptions(da));
    212:   PetscCall(DMSetUp(da));
    213:   PetscCall(DMDASetUniformCoordinates(da, 0.0, 1.0, 0, 0, 0, 0));
    214:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    215:     Create necessary matrix and vectors
    216:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    217:   PetscCall(DMCreateMatrix(da, &J));
    218:   PetscCall(DMCreateGlobalVector(da, &U));

    220:   PetscCall(InitialConditions(U, da, &app));
    221:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    222:      Create timestepping solver context
    223:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    224:   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
    225:   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
    226:   PetscCall(TSSetType(ts, TSROSW));
    227:   PetscCall(TSSetIFunction(ts, NULL, (TSIFunctionFn *)IFunction, (void *)&app));
    228:   PetscCall(TSSetIJacobian(ts, J, J, (TSIJacobianFn *)IJacobian, (void *)&app));

    230:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    231:      Set initial conditions
    232:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    233:   PetscCall(TSSetSolution(ts, U));

    235:   PetscCall(TSSetDM(ts, da));
    236:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    237:      Set solver options
    238:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    239:   PetscCall(TSSetTimeStep(ts, 0.1));
    240:   PetscCall(TSSetMaxTime(ts, 30.0));
    241:   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
    242:   PetscCall(TSSetFromOptions(ts));

    244:   PetscInt lsize;
    245:   PetscCall(VecGetLocalSize(U, &lsize));
    246:   PetscInt  *direction;
    247:   PetscBool *terminate;
    248:   PetscInt   i;
    249:   PetscCall(PetscMalloc1(lsize, &direction));
    250:   PetscCall(PetscMalloc1(lsize, &terminate));
    251:   for (i = 0; i < lsize; i++) {
    252:     direction[i] = -1;
    253:     terminate[i] = PETSC_FALSE;
    254:   }
    255:   PetscCall(TSSetEventHandler(ts, lsize, direction, terminate, EventFunction, PostEventFunction, (void *)&app));

    257:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    258:      Run timestepping solver
    259:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    260:   PetscCall(TSSolve(ts, U));

    262:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    263:      Free work space.  All PETSc objects should be destroyed when they are no longer needed.
    264:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    266:   PetscCall(MatDestroy(&J));
    267:   PetscCall(VecDestroy(&U));
    268:   PetscCall(DMDestroy(&da));
    269:   PetscCall(TSDestroy(&ts));
    270:   PetscCall(PetscFree(direction));
    271:   PetscCall(PetscFree(terminate));

    273:   PetscCall(PetscFree(app.sw));
    274:   PetscCall(PetscFinalize());
    275:   return 0;
    276: }