Actual source code: ex18.c

      1: static char help[] = "Nonlinear Radiative Transport PDE with multigrid in 2d.\n\
      2: Uses 2-dimensional distributed arrays.\n\
      3: A 2-dim simplified Radiative Transport test problem is used, with analytic Jacobian. \n\
      4: \n\
      5:   Solves the linear systems via multilevel methods \n\
      6: \n\
      7: The command line\n\
      8: options are:\n\
      9:   -tleft <tl>, where <tl> indicates the left Diriclet BC \n\
     10:   -tright <tr>, where <tr> indicates the right Diriclet BC \n\
     11:   -beta <beta>, where <beta> indicates the exponent in T \n\n";

     13: /*

     15:     This example models the partial differential equation

     17:          - Div(alpha* T^beta (GRAD T)) = 0.

     19:     where beta = 2.5 and alpha = 1.0

     21:     BC: T_left = 1.0, T_right = 0.1, dT/dn_top = dTdn_bottom = 0.

     23:     in the unit square, which is uniformly discretized in each of x and
     24:     y in this simple encoding.  The degrees of freedom are cell centered.

     26:     A finite volume approximation with the usual 5-point stencil
     27:     is used to discretize the boundary value problem to obtain a
     28:     nonlinear system of equations.

     30:     This code was contributed by David Keyes

     32: */

     34: #include <petscsnes.h>
     35: #include <petscdm.h>
     36: #include <petscdmda.h>

     38: /* User-defined application context */

     40: typedef struct {
     41:   PetscReal tleft, tright;   /* Dirichlet boundary conditions */
     42:   PetscReal beta, bm1, coef; /* nonlinear diffusivity parameterizations */
     43: } AppCtx;

     45: #define POWFLOP 5 /* assume a pow() takes five flops */

     47: extern PetscErrorCode FormInitialGuess(SNES, Vec, void *);
     48: extern PetscErrorCode FormFunction(SNES, Vec, Vec, void *);
     49: extern PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *);

     51: int main(int argc, char **argv)
     52: {
     53:   SNES      snes;
     54:   AppCtx    user;
     55:   PetscInt  its, lits;
     56:   PetscReal litspit;
     57:   DM        da;

     59:   PetscFunctionBeginUser;
     60:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));

     62:   /* set problem parameters */
     63:   user.tleft  = 1.0;
     64:   user.tright = 0.1;
     65:   user.beta   = 2.5;
     66:   PetscCall(PetscOptionsGetReal(NULL, NULL, "-tleft", &user.tleft, NULL));
     67:   PetscCall(PetscOptionsGetReal(NULL, NULL, "-tright", &user.tright, NULL));
     68:   PetscCall(PetscOptionsGetReal(NULL, NULL, "-beta", &user.beta, NULL));
     69:   user.bm1  = user.beta - 1.0;
     70:   user.coef = user.beta / 2.0;

     72:   /*
     73:       Create the multilevel DM data structure
     74:   */
     75:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));

     77:   /*
     78:       Set the DMDA (grid structure) for the grids.
     79:   */
     80:   PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_STAR, 5, 5, PETSC_DECIDE, PETSC_DECIDE, 1, 1, 0, 0, &da));
     81:   PetscCall(DMSetFromOptions(da));
     82:   PetscCall(DMSetUp(da));
     83:   PetscCall(DMSetApplicationContext(da, &user));
     84:   PetscCall(SNESSetDM(snes, (DM)da));

     86:   /*
     87:      Create the nonlinear solver, and tell it the functions to use
     88:   */
     89:   PetscCall(SNESSetFunction(snes, NULL, FormFunction, &user));
     90:   PetscCall(SNESSetJacobian(snes, NULL, NULL, FormJacobian, &user));
     91:   PetscCall(SNESSetFromOptions(snes));
     92:   PetscCall(SNESSetComputeInitialGuess(snes, FormInitialGuess, NULL));

     94:   PetscCall(SNESSolve(snes, NULL, NULL));
     95:   PetscCall(SNESGetIterationNumber(snes, &its));
     96:   PetscCall(SNESGetLinearSolveIterations(snes, &lits));
     97:   litspit = ((PetscReal)lits) / ((PetscReal)its);
     98:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %" PetscInt_FMT "\n", its));
     99:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of Linear iterations = %" PetscInt_FMT "\n", lits));
    100:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Average Linear its / SNES = %e\n", (double)litspit));

    102:   PetscCall(DMDestroy(&da));
    103:   PetscCall(SNESDestroy(&snes));
    104:   PetscCall(PetscFinalize());
    105:   return 0;
    106: }
    107: /* --------------------  Form initial approximation ----------------- */
    108: PetscErrorCode FormInitialGuess(SNES snes, Vec X, PetscCtx ctx)
    109: {
    110:   AppCtx       *user;
    111:   PetscInt      i, j, xs, ys, xm, ym;
    112:   PetscReal     tleft;
    113:   PetscScalar **x;
    114:   DM            da;

    116:   PetscFunctionBeginUser;
    117:   PetscCall(SNESGetDM(snes, &da));
    118:   PetscCall(DMGetApplicationContext(da, &user));
    119:   tleft = user->tleft;
    120:   /* Get ghost points */
    121:   PetscCall(DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0));
    122:   PetscCall(DMDAVecGetArray(da, X, &x));

    124:   /* Compute initial guess */
    125:   for (j = ys; j < ys + ym; j++) {
    126:     for (i = xs; i < xs + xm; i++) x[j][i] = tleft;
    127:   }
    128:   PetscCall(DMDAVecRestoreArray(da, X, &x));
    129:   PetscFunctionReturn(PETSC_SUCCESS);
    130: }
    131: /* --------------------  Evaluate Function F(x) --------------------- */
    132: PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *ptr)
    133: {
    134:   AppCtx       *user = (AppCtx *)ptr;
    135:   PetscInt      i, j, mx, my, xs, ys, xm, ym;
    136:   PetscScalar   zero = 0.0, one = 1.0;
    137:   PetscScalar   hx, hy, hxdhy, hydhx;
    138:   PetscScalar   t0, tn, ts, te, tw, an, as, ae, aw, dn, ds, de, dw, fn = 0.0, fs = 0.0, fe = 0.0, fw = 0.0;
    139:   PetscScalar   tleft, tright, beta;
    140:   PetscScalar **x, **f;
    141:   Vec           localX;
    142:   DM            da;

    144:   PetscFunctionBeginUser;
    145:   PetscCall(SNESGetDM(snes, &da));
    146:   PetscCall(DMGetLocalVector(da, &localX));
    147:   PetscCall(DMDAGetInfo(da, NULL, &mx, &my, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
    148:   hx     = one / (PetscReal)(mx - 1);
    149:   hy     = one / (PetscReal)(my - 1);
    150:   hxdhy  = hx / hy;
    151:   hydhx  = hy / hx;
    152:   tleft  = user->tleft;
    153:   tright = user->tright;
    154:   beta   = user->beta;

    156:   /* Get ghost points */
    157:   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX));
    158:   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX));
    159:   PetscCall(DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0));
    160:   PetscCall(DMDAVecGetArray(da, localX, &x));
    161:   PetscCall(DMDAVecGetArray(da, F, &f));

    163:   /* Evaluate function */
    164:   for (j = ys; j < ys + ym; j++) {
    165:     for (i = xs; i < xs + xm; i++) {
    166:       t0 = x[j][i];

    168:       if (i > 0 && i < mx - 1 && j > 0 && j < my - 1) {
    169:         /* general interior volume */

    171:         tw = x[j][i - 1];
    172:         aw = 0.5 * (t0 + tw);
    173:         dw = PetscPowScalar(aw, beta);
    174:         fw = dw * (t0 - tw);

    176:         te = x[j][i + 1];
    177:         ae = 0.5 * (t0 + te);
    178:         de = PetscPowScalar(ae, beta);
    179:         fe = de * (te - t0);

    181:         ts = x[j - 1][i];
    182:         as = 0.5 * (t0 + ts);
    183:         ds = PetscPowScalar(as, beta);
    184:         fs = ds * (t0 - ts);

    186:         tn = x[j + 1][i];
    187:         an = 0.5 * (t0 + tn);
    188:         dn = PetscPowScalar(an, beta);
    189:         fn = dn * (tn - t0);

    191:       } else if (i == 0) {
    192:         /* left-hand boundary */
    193:         tw = tleft;
    194:         aw = 0.5 * (t0 + tw);
    195:         dw = PetscPowScalar(aw, beta);
    196:         fw = dw * (t0 - tw);

    198:         te = x[j][i + 1];
    199:         ae = 0.5 * (t0 + te);
    200:         de = PetscPowScalar(ae, beta);
    201:         fe = de * (te - t0);

    203:         if (j > 0) {
    204:           ts = x[j - 1][i];
    205:           as = 0.5 * (t0 + ts);
    206:           ds = PetscPowScalar(as, beta);
    207:           fs = ds * (t0 - ts);
    208:         } else fs = zero;

    210:         if (j < my - 1) {
    211:           tn = x[j + 1][i];
    212:           an = 0.5 * (t0 + tn);
    213:           dn = PetscPowScalar(an, beta);
    214:           fn = dn * (tn - t0);
    215:         } else fn = zero;

    217:       } else if (i == mx - 1) {
    218:         /* right-hand boundary */
    219:         tw = x[j][i - 1];
    220:         aw = 0.5 * (t0 + tw);
    221:         dw = PetscPowScalar(aw, beta);
    222:         fw = dw * (t0 - tw);

    224:         te = tright;
    225:         ae = 0.5 * (t0 + te);
    226:         de = PetscPowScalar(ae, beta);
    227:         fe = de * (te - t0);

    229:         if (j > 0) {
    230:           ts = x[j - 1][i];
    231:           as = 0.5 * (t0 + ts);
    232:           ds = PetscPowScalar(as, beta);
    233:           fs = ds * (t0 - ts);
    234:         } else fs = zero;

    236:         if (j < my - 1) {
    237:           tn = x[j + 1][i];
    238:           an = 0.5 * (t0 + tn);
    239:           dn = PetscPowScalar(an, beta);
    240:           fn = dn * (tn - t0);
    241:         } else fn = zero;

    243:       } else if (j == 0) {
    244:         /* bottom boundary,and i <> 0 or mx-1 */
    245:         tw = x[j][i - 1];
    246:         aw = 0.5 * (t0 + tw);
    247:         dw = PetscPowScalar(aw, beta);
    248:         fw = dw * (t0 - tw);

    250:         te = x[j][i + 1];
    251:         ae = 0.5 * (t0 + te);
    252:         de = PetscPowScalar(ae, beta);
    253:         fe = de * (te - t0);

    255:         fs = zero;

    257:         tn = x[j + 1][i];
    258:         an = 0.5 * (t0 + tn);
    259:         dn = PetscPowScalar(an, beta);
    260:         fn = dn * (tn - t0);

    262:       } else if (j == my - 1) {
    263:         /* top boundary,and i <> 0 or mx-1 */
    264:         tw = x[j][i - 1];
    265:         aw = 0.5 * (t0 + tw);
    266:         dw = PetscPowScalar(aw, beta);
    267:         fw = dw * (t0 - tw);

    269:         te = x[j][i + 1];
    270:         ae = 0.5 * (t0 + te);
    271:         de = PetscPowScalar(ae, beta);
    272:         fe = de * (te - t0);

    274:         ts = x[j - 1][i];
    275:         as = 0.5 * (t0 + ts);
    276:         ds = PetscPowScalar(as, beta);
    277:         fs = ds * (t0 - ts);

    279:         fn = zero;
    280:       }

    282:       f[j][i] = -hydhx * (fe - fw) - hxdhy * (fn - fs);
    283:     }
    284:   }
    285:   PetscCall(DMDAVecRestoreArray(da, localX, &x));
    286:   PetscCall(DMDAVecRestoreArray(da, F, &f));
    287:   PetscCall(DMRestoreLocalVector(da, &localX));
    288:   PetscCall(PetscLogFlops((22.0 + 4.0 * POWFLOP) * ym * xm));
    289:   PetscFunctionReturn(PETSC_SUCCESS);
    290: }
    291: /* --------------------  Evaluate Jacobian F(x) --------------------- */
    292: PetscErrorCode FormJacobian(SNES snes, Vec X, Mat jac, Mat B, void *ptr)
    293: {
    294:   AppCtx     *user = (AppCtx *)ptr;
    295:   PetscInt    i, j, mx, my, xs, ys, xm, ym;
    296:   PetscScalar one = 1.0, hx, hy, hxdhy, hydhx, t0, tn, ts, te, tw;
    297:   PetscScalar dn, ds, de, dw, an, as, ae, aw, bn, bs, be, bw, gn, gs, ge, gw;
    298:   PetscScalar tleft, tright, beta, bm1, coef;
    299:   PetscScalar v[5], **x;
    300:   Vec         localX;
    301:   MatStencil  col[5], row;
    302:   DM          da;

    304:   PetscFunctionBeginUser;
    305:   PetscCall(SNESGetDM(snes, &da));
    306:   PetscCall(DMGetLocalVector(da, &localX));
    307:   PetscCall(DMDAGetInfo(da, NULL, &mx, &my, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
    308:   hx     = one / (PetscReal)(mx - 1);
    309:   hy     = one / (PetscReal)(my - 1);
    310:   hxdhy  = hx / hy;
    311:   hydhx  = hy / hx;
    312:   tleft  = user->tleft;
    313:   tright = user->tright;
    314:   beta   = user->beta;
    315:   bm1    = user->bm1;
    316:   coef   = user->coef;

    318:   /* Get ghost points */
    319:   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX));
    320:   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX));
    321:   PetscCall(DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0));
    322:   PetscCall(DMDAVecGetArray(da, localX, &x));

    324:   /* Evaluate Jacobian of function */
    325:   for (j = ys; j < ys + ym; j++) {
    326:     for (i = xs; i < xs + xm; i++) {
    327:       t0 = x[j][i];

    329:       if (i > 0 && i < mx - 1 && j > 0 && j < my - 1) {
    330:         /* general interior volume */

    332:         tw = x[j][i - 1];
    333:         aw = 0.5 * (t0 + tw);
    334:         bw = PetscPowScalar(aw, bm1);
    335:         /* dw = bw * aw */
    336:         dw = PetscPowScalar(aw, beta);
    337:         gw = coef * bw * (t0 - tw);

    339:         te = x[j][i + 1];
    340:         ae = 0.5 * (t0 + te);
    341:         be = PetscPowScalar(ae, bm1);
    342:         /* de = be * ae; */
    343:         de = PetscPowScalar(ae, beta);
    344:         ge = coef * be * (te - t0);

    346:         ts = x[j - 1][i];
    347:         as = 0.5 * (t0 + ts);
    348:         bs = PetscPowScalar(as, bm1);
    349:         /* ds = bs * as; */
    350:         ds = PetscPowScalar(as, beta);
    351:         gs = coef * bs * (t0 - ts);

    353:         tn = x[j + 1][i];
    354:         an = 0.5 * (t0 + tn);
    355:         bn = PetscPowScalar(an, bm1);
    356:         /* dn = bn * an; */
    357:         dn = PetscPowScalar(an, beta);
    358:         gn = coef * bn * (tn - t0);

    360:         v[0]     = -hxdhy * (ds - gs);
    361:         col[0].j = j - 1;
    362:         col[0].i = i;
    363:         v[1]     = -hydhx * (dw - gw);
    364:         col[1].j = j;
    365:         col[1].i = i - 1;
    366:         v[2]     = hxdhy * (ds + dn + gs - gn) + hydhx * (dw + de + gw - ge);
    367:         col[2].j = row.j = j;
    368:         col[2].i = row.i = i;
    369:         v[3]             = -hydhx * (de + ge);
    370:         col[3].j         = j;
    371:         col[3].i         = i + 1;
    372:         v[4]             = -hxdhy * (dn + gn);
    373:         col[4].j         = j + 1;
    374:         col[4].i         = i;
    375:         PetscCall(MatSetValuesStencil(B, 1, &row, 5, col, v, INSERT_VALUES));

    377:       } else if (i == 0) {
    378:         /* left-hand boundary */
    379:         tw = tleft;
    380:         aw = 0.5 * (t0 + tw);
    381:         bw = PetscPowScalar(aw, bm1);
    382:         /* dw = bw * aw */
    383:         dw = PetscPowScalar(aw, beta);
    384:         gw = coef * bw * (t0 - tw);

    386:         te = x[j][i + 1];
    387:         ae = 0.5 * (t0 + te);
    388:         be = PetscPowScalar(ae, bm1);
    389:         /* de = be * ae; */
    390:         de = PetscPowScalar(ae, beta);
    391:         ge = coef * be * (te - t0);

    393:         /* left-hand bottom boundary */
    394:         if (j == 0) {
    395:           tn = x[j + 1][i];
    396:           an = 0.5 * (t0 + tn);
    397:           bn = PetscPowScalar(an, bm1);
    398:           /* dn = bn * an; */
    399:           dn = PetscPowScalar(an, beta);
    400:           gn = coef * bn * (tn - t0);

    402:           v[0]     = hxdhy * (dn - gn) + hydhx * (dw + de + gw - ge);
    403:           col[0].j = row.j = j;
    404:           col[0].i = row.i = i;
    405:           v[1]             = -hydhx * (de + ge);
    406:           col[1].j         = j;
    407:           col[1].i         = i + 1;
    408:           v[2]             = -hxdhy * (dn + gn);
    409:           col[2].j         = j + 1;
    410:           col[2].i         = i;
    411:           PetscCall(MatSetValuesStencil(B, 1, &row, 3, col, v, INSERT_VALUES));

    413:           /* left-hand interior boundary */
    414:         } else if (j < my - 1) {
    415:           ts = x[j - 1][i];
    416:           as = 0.5 * (t0 + ts);
    417:           bs = PetscPowScalar(as, bm1);
    418:           /* ds = bs * as; */
    419:           ds = PetscPowScalar(as, beta);
    420:           gs = coef * bs * (t0 - ts);

    422:           tn = x[j + 1][i];
    423:           an = 0.5 * (t0 + tn);
    424:           bn = PetscPowScalar(an, bm1);
    425:           /* dn = bn * an; */
    426:           dn = PetscPowScalar(an, beta);
    427:           gn = coef * bn * (tn - t0);

    429:           v[0]     = -hxdhy * (ds - gs);
    430:           col[0].j = j - 1;
    431:           col[0].i = i;
    432:           v[1]     = hxdhy * (ds + dn + gs - gn) + hydhx * (dw + de + gw - ge);
    433:           col[1].j = row.j = j;
    434:           col[1].i = row.i = i;
    435:           v[2]             = -hydhx * (de + ge);
    436:           col[2].j         = j;
    437:           col[2].i         = i + 1;
    438:           v[3]             = -hxdhy * (dn + gn);
    439:           col[3].j         = j + 1;
    440:           col[3].i         = i;
    441:           PetscCall(MatSetValuesStencil(B, 1, &row, 4, col, v, INSERT_VALUES));
    442:           /* left-hand top boundary */
    443:         } else {
    444:           ts = x[j - 1][i];
    445:           as = 0.5 * (t0 + ts);
    446:           bs = PetscPowScalar(as, bm1);
    447:           /* ds = bs * as; */
    448:           ds = PetscPowScalar(as, beta);
    449:           gs = coef * bs * (t0 - ts);

    451:           v[0]     = -hxdhy * (ds - gs);
    452:           col[0].j = j - 1;
    453:           col[0].i = i;
    454:           v[1]     = hxdhy * (ds + gs) + hydhx * (dw + de + gw - ge);
    455:           col[1].j = row.j = j;
    456:           col[1].i = row.i = i;
    457:           v[2]             = -hydhx * (de + ge);
    458:           col[2].j         = j;
    459:           col[2].i         = i + 1;
    460:           PetscCall(MatSetValuesStencil(B, 1, &row, 3, col, v, INSERT_VALUES));
    461:         }

    463:       } else if (i == mx - 1) {
    464:         /* right-hand boundary */
    465:         tw = x[j][i - 1];
    466:         aw = 0.5 * (t0 + tw);
    467:         bw = PetscPowScalar(aw, bm1);
    468:         /* dw = bw * aw */
    469:         dw = PetscPowScalar(aw, beta);
    470:         gw = coef * bw * (t0 - tw);

    472:         te = tright;
    473:         ae = 0.5 * (t0 + te);
    474:         be = PetscPowScalar(ae, bm1);
    475:         /* de = be * ae; */
    476:         de = PetscPowScalar(ae, beta);
    477:         ge = coef * be * (te - t0);

    479:         /* right-hand bottom boundary */
    480:         if (j == 0) {
    481:           tn = x[j + 1][i];
    482:           an = 0.5 * (t0 + tn);
    483:           bn = PetscPowScalar(an, bm1);
    484:           /* dn = bn * an; */
    485:           dn = PetscPowScalar(an, beta);
    486:           gn = coef * bn * (tn - t0);

    488:           v[0]     = -hydhx * (dw - gw);
    489:           col[0].j = j;
    490:           col[0].i = i - 1;
    491:           v[1]     = hxdhy * (dn - gn) + hydhx * (dw + de + gw - ge);
    492:           col[1].j = row.j = j;
    493:           col[1].i = row.i = i;
    494:           v[2]             = -hxdhy * (dn + gn);
    495:           col[2].j         = j + 1;
    496:           col[2].i         = i;
    497:           PetscCall(MatSetValuesStencil(B, 1, &row, 3, col, v, INSERT_VALUES));

    499:           /* right-hand interior boundary */
    500:         } else if (j < my - 1) {
    501:           ts = x[j - 1][i];
    502:           as = 0.5 * (t0 + ts);
    503:           bs = PetscPowScalar(as, bm1);
    504:           /* ds = bs * as; */
    505:           ds = PetscPowScalar(as, beta);
    506:           gs = coef * bs * (t0 - ts);

    508:           tn = x[j + 1][i];
    509:           an = 0.5 * (t0 + tn);
    510:           bn = PetscPowScalar(an, bm1);
    511:           /* dn = bn * an; */
    512:           dn = PetscPowScalar(an, beta);
    513:           gn = coef * bn * (tn - t0);

    515:           v[0]     = -hxdhy * (ds - gs);
    516:           col[0].j = j - 1;
    517:           col[0].i = i;
    518:           v[1]     = -hydhx * (dw - gw);
    519:           col[1].j = j;
    520:           col[1].i = i - 1;
    521:           v[2]     = hxdhy * (ds + dn + gs - gn) + hydhx * (dw + de + gw - ge);
    522:           col[2].j = row.j = j;
    523:           col[2].i = row.i = i;
    524:           v[3]             = -hxdhy * (dn + gn);
    525:           col[3].j         = j + 1;
    526:           col[3].i         = i;
    527:           PetscCall(MatSetValuesStencil(B, 1, &row, 4, col, v, INSERT_VALUES));
    528:           /* right-hand top boundary */
    529:         } else {
    530:           ts = x[j - 1][i];
    531:           as = 0.5 * (t0 + ts);
    532:           bs = PetscPowScalar(as, bm1);
    533:           /* ds = bs * as; */
    534:           ds = PetscPowScalar(as, beta);
    535:           gs = coef * bs * (t0 - ts);

    537:           v[0]     = -hxdhy * (ds - gs);
    538:           col[0].j = j - 1;
    539:           col[0].i = i;
    540:           v[1]     = -hydhx * (dw - gw);
    541:           col[1].j = j;
    542:           col[1].i = i - 1;
    543:           v[2]     = hxdhy * (ds + gs) + hydhx * (dw + de + gw - ge);
    544:           col[2].j = row.j = j;
    545:           col[2].i = row.i = i;
    546:           PetscCall(MatSetValuesStencil(B, 1, &row, 3, col, v, INSERT_VALUES));
    547:         }

    549:         /* bottom boundary,and i <> 0 or mx-1 */
    550:       } else if (j == 0) {
    551:         tw = x[j][i - 1];
    552:         aw = 0.5 * (t0 + tw);
    553:         bw = PetscPowScalar(aw, bm1);
    554:         /* dw = bw * aw */
    555:         dw = PetscPowScalar(aw, beta);
    556:         gw = coef * bw * (t0 - tw);

    558:         te = x[j][i + 1];
    559:         ae = 0.5 * (t0 + te);
    560:         be = PetscPowScalar(ae, bm1);
    561:         /* de = be * ae; */
    562:         de = PetscPowScalar(ae, beta);
    563:         ge = coef * be * (te - t0);

    565:         tn = x[j + 1][i];
    566:         an = 0.5 * (t0 + tn);
    567:         bn = PetscPowScalar(an, bm1);
    568:         /* dn = bn * an; */
    569:         dn = PetscPowScalar(an, beta);
    570:         gn = coef * bn * (tn - t0);

    572:         v[0]     = -hydhx * (dw - gw);
    573:         col[0].j = j;
    574:         col[0].i = i - 1;
    575:         v[1]     = hxdhy * (dn - gn) + hydhx * (dw + de + gw - ge);
    576:         col[1].j = row.j = j;
    577:         col[1].i = row.i = i;
    578:         v[2]             = -hydhx * (de + ge);
    579:         col[2].j         = j;
    580:         col[2].i         = i + 1;
    581:         v[3]             = -hxdhy * (dn + gn);
    582:         col[3].j         = j + 1;
    583:         col[3].i         = i;
    584:         PetscCall(MatSetValuesStencil(B, 1, &row, 4, col, v, INSERT_VALUES));

    586:         /* top boundary,and i <> 0 or mx-1 */
    587:       } else if (j == my - 1) {
    588:         tw = x[j][i - 1];
    589:         aw = 0.5 * (t0 + tw);
    590:         bw = PetscPowScalar(aw, bm1);
    591:         /* dw = bw * aw */
    592:         dw = PetscPowScalar(aw, beta);
    593:         gw = coef * bw * (t0 - tw);

    595:         te = x[j][i + 1];
    596:         ae = 0.5 * (t0 + te);
    597:         be = PetscPowScalar(ae, bm1);
    598:         /* de = be * ae; */
    599:         de = PetscPowScalar(ae, beta);
    600:         ge = coef * be * (te - t0);

    602:         ts = x[j - 1][i];
    603:         as = 0.5 * (t0 + ts);
    604:         bs = PetscPowScalar(as, bm1);
    605:         /* ds = bs * as; */
    606:         ds = PetscPowScalar(as, beta);
    607:         gs = coef * bs * (t0 - ts);

    609:         v[0]     = -hxdhy * (ds - gs);
    610:         col[0].j = j - 1;
    611:         col[0].i = i;
    612:         v[1]     = -hydhx * (dw - gw);
    613:         col[1].j = j;
    614:         col[1].i = i - 1;
    615:         v[2]     = hxdhy * (ds + gs) + hydhx * (dw + de + gw - ge);
    616:         col[2].j = row.j = j;
    617:         col[2].i = row.i = i;
    618:         v[3]             = -hydhx * (de + ge);
    619:         col[3].j         = j;
    620:         col[3].i         = i + 1;
    621:         PetscCall(MatSetValuesStencil(B, 1, &row, 4, col, v, INSERT_VALUES));
    622:       }
    623:     }
    624:   }
    625:   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
    626:   PetscCall(DMDAVecRestoreArray(da, localX, &x));
    627:   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
    628:   PetscCall(DMRestoreLocalVector(da, &localX));
    629:   if (jac != B) {
    630:     PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
    631:     PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
    632:   }

    634:   PetscCall(PetscLogFlops((41.0 + 8.0 * POWFLOP) * xm * ym));
    635:   PetscFunctionReturn(PETSC_SUCCESS);
    636: }

    638: /*TEST

    640:    test:
    641:       suffix: 1
    642:       args: -pc_type mg -ksp_type fgmres -da_refine 2 -pc_mg_galerkin pmat -snes_view
    643:       requires: !single

    645:    test:
    646:       suffix: 2
    647:       args: -pc_type mg -ksp_type fgmres -da_refine 2 -pc_mg_galerkin pmat -snes_view -snes_type newtontrdc
    648:       requires: !single

    650:    test:
    651:       suffix: 3
    652:       args: -pc_type mg -ksp_type fgmres -da_refine 2 -pc_mg_galerkin pmat -snes_view -snes_type newtontr -snes_tr_fallback_type dogleg
    653:       requires: !single

    655: TEST*/