Actual source code: ex4.c

  1: #include <petscsnes.h>
  2: #include <petscdmda.h>

  4: static const char help[] = "Minimum surface area problem in 2D using DMDA.\n\
  5: It solves an unconstrained minimization problem. This example is based on a \n\
  6: problem from the MINPACK-2 test suite. Given a rectangular 2-D domain and \n\
  7: boundary values along the edges of the domain, the objective is to find the\n\
  8: surface with the minimal area that satisfies the boundary conditions.\n\
  9: \n\
 10: The command line options are:\n\
 11:   -da_grid_x <nx>, where <nx> = number of grid points in the 1st coordinate direction\n\
 12:   -da_grid_y <ny>, where <ny> = number of grid points in the 2nd coordinate direction\n\
 13:   \n";

 15: /*
 16:    User-defined application context - contains data needed by the
 17:    application-provided call-back routines, FormJacobianLocal() and
 18:    FormFunctionLocal().
 19: */

 21: typedef enum {
 22:   PROBLEM_ENNEPER,
 23:   PROBLEM_SINS,
 24: } ProblemType;
 25: static const char *const ProblemTypes[] = {"ENNEPER", "SINS", "ProblemType", "PROBLEM_", 0};

 27: typedef struct {
 28:   PetscScalar *bottom, *top, *left, *right;
 29: } AppCtx;

 31: /* -------- User-defined Routines --------- */

 33: static PetscErrorCode FormBoundaryConditions_Enneper(SNES, AppCtx **);
 34: static PetscErrorCode FormBoundaryConditions_Sins(SNES, AppCtx **);
 35: static PetscErrorCode DestroyBoundaryConditions(AppCtx **);
 36: static PetscErrorCode FormObjectiveLocal(DMDALocalInfo *, PetscScalar **, PetscReal *, void *);
 37: static PetscErrorCode FormFunctionLocal(DMDALocalInfo *, PetscScalar **, PetscScalar **, void *);
 38: static PetscErrorCode FormJacobianLocal(DMDALocalInfo *, PetscScalar **, Mat, Mat, void *);

 40: int main(int argc, char **argv)
 41: {
 42:   Vec         x;
 43:   SNES        snes;
 44:   DM          da;
 45:   ProblemType ptype   = PROBLEM_ENNEPER;
 46:   PetscBool   use_obj = PETSC_TRUE;
 47:   PetscReal   bbox[4] = {0.};
 48:   AppCtx     *user;
 49:   PetscErrorCode (*form_bc)(SNES, AppCtx **) = NULL;

 51:   PetscFunctionBeginUser;
 52:   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));

 54:   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "Minimal surface options", __FILE__);
 55:   PetscCall(PetscOptionsEnum("-problem_type", "Problem type", NULL, ProblemTypes, (PetscEnum)ptype, (PetscEnum *)&ptype, NULL));
 56:   PetscCall(PetscOptionsBool("-use_objective", "Use objective function", NULL, use_obj, &use_obj, NULL));
 57:   PetscOptionsEnd();
 58:   switch (ptype) {
 59:   case PROBLEM_ENNEPER:
 60:     bbox[0] = -0.5;
 61:     bbox[1] = 0.5;
 62:     bbox[2] = -0.5;
 63:     bbox[3] = 0.5;
 64:     form_bc = FormBoundaryConditions_Enneper;
 65:     break;
 66:   case PROBLEM_SINS:
 67:     bbox[0] = 0.0;
 68:     bbox[1] = 1.0;
 69:     bbox[2] = 0.0;
 70:     bbox[3] = 1.0;
 71:     form_bc = FormBoundaryConditions_Sins;
 72:     break;
 73:   }

 75:   /* Create distributed array to manage the 2d grid */
 76:   PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 4, 4, PETSC_DECIDE, PETSC_DECIDE, 1, 1, NULL, NULL, &da));
 77:   PetscCall(DMSetFromOptions(da));
 78:   PetscCall(DMSetUp(da));
 79:   PetscCall(DMDASetUniformCoordinates(da, bbox[0], bbox[1], bbox[2], bbox[3], PETSC_DECIDE, PETSC_DECIDE));

 81:   /* Extract global vectors from DMDA; */
 82:   PetscCall(DMCreateGlobalVector(da, &x));

 84:   /* Create nonlinear solver context */
 85:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
 86:   PetscCall(SNESSetDM(snes, da));
 87:   PetscCall((*form_bc)(snes, &user));
 88:   PetscCall(SNESSetApplicationContext(snes, user));

 90:   /*  Set local callbacks */
 91:   if (use_obj) PetscCall(DMDASNESSetObjectiveLocal(da, (DMDASNESObjectiveFn *)FormObjectiveLocal, NULL));
 92:   PetscCall(DMDASNESSetFunctionLocal(da, INSERT_VALUES, (DMDASNESFunctionFn *)FormFunctionLocal, NULL));
 93:   PetscCall(DMDASNESSetJacobianLocal(da, (DMDASNESJacobianFn *)FormJacobianLocal, NULL));

 95:   /* Customize from command line */
 96:   PetscCall(SNESSetFromOptions(snes));

 98:   /* Solve the application */
 99:   PetscCall(SNESSolve(snes, NULL, x));

101:   /* Free user-created data structures */
102:   PetscCall(VecDestroy(&x));
103:   PetscCall(SNESDestroy(&snes));
104:   PetscCall(DMDestroy(&da));
105:   PetscCall(DestroyBoundaryConditions(&user));

107:   PetscCall(PetscFinalize());
108:   return 0;
109: }

111: /* Compute objective function over the locally owned part of the mesh */
112: PetscErrorCode FormObjectiveLocal(DMDALocalInfo *info, PetscScalar **x, PetscReal *v, void *ptr)
113: {
114:   AppCtx     *user = (AppCtx *)ptr;
115:   PetscInt    mx = info->mx, my = info->my;
116:   PetscInt    xs = info->xs, xm = info->xm, ys = info->ys, ym = info->ym;
117:   PetscInt    i, j;
118:   PetscScalar hx, hy;
119:   PetscScalar f2, f4, d1, d2, d3, d4, xc, xl, xr, xt, xb;
120:   PetscReal   ft = 0, area;

122:   PetscFunctionBeginUser;
123:   PetscCheck(user, PetscObjectComm((PetscObject)info->da), PETSC_ERR_PLIB, "Missing application context");
124:   hx   = 1.0 / (mx + 1);
125:   hy   = 1.0 / (my + 1);
126:   area = 0.5 * hx * hy;
127:   for (j = ys; j < ys + ym; j++) {
128:     for (i = xs; i < xs + xm; i++) {
129:       xc = x[j][i];
130:       xl = xr = xb = xt = xc;

132:       if (i == 0) { /* left side */
133:         xl = user->left[j + 1];
134:       } else xl = x[j][i - 1];

136:       if (j == 0) { /* bottom side */
137:         xb = user->bottom[i + 1];
138:       } else xb = x[j - 1][i];

140:       if (i + 1 == mx) { /* right side */
141:         xr = user->right[j + 1];
142:       } else xr = x[j][i + 1];

144:       if (j + 1 == 0 + my) { /* top side */
145:         xt = user->top[i + 1];
146:       } else xt = x[j + 1][i];

148:       d1 = (xc - xl);
149:       d2 = (xc - xr);
150:       d3 = (xc - xt);
151:       d4 = (xc - xb);

153:       d1 /= hx;
154:       d2 /= hx;
155:       d3 /= hy;
156:       d4 /= hy;

158:       f2 = PetscSqrtScalar(1.0 + d1 * d1 + d4 * d4);
159:       f4 = PetscSqrtScalar(1.0 + d3 * d3 + d2 * d2);

161:       ft += PetscRealPart(f2 + f4);
162:     }
163:   }

165:   /* Compute triangular areas along the border of the domain. */
166:   if (xs == 0) { /* left side */
167:     for (j = ys; j < ys + ym; j++) {
168:       d3 = (user->left[j + 1] - user->left[j + 2]) / hy;
169:       d2 = (user->left[j + 1] - x[j][0]) / hx;
170:       ft += PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
171:     }
172:   }
173:   if (ys == 0) { /* bottom side */
174:     for (i = xs; i < xs + xm; i++) {
175:       d2 = (user->bottom[i + 1] - user->bottom[i + 2]) / hx;
176:       d3 = (user->bottom[i + 1] - x[0][i]) / hy;
177:       ft += PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
178:     }
179:   }
180:   if (xs + xm == mx) { /* right side */
181:     for (j = ys; j < ys + ym; j++) {
182:       d1 = (x[j][mx - 1] - user->right[j + 1]) / hx;
183:       d4 = (user->right[j] - user->right[j + 1]) / hy;
184:       ft += PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
185:     }
186:   }
187:   if (ys + ym == my) { /* top side */
188:     for (i = xs; i < xs + xm; i++) {
189:       d1 = (x[my - 1][i] - user->top[i + 1]) / hy;
190:       d4 = (user->top[i + 1] - user->top[i]) / hx;
191:       ft += PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
192:     }
193:   }
194:   if (ys == 0 && xs == 0) {
195:     d1 = (user->left[0] - user->left[1]) / hy;
196:     d2 = (user->bottom[0] - user->bottom[1]) / hx;
197:     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
198:   }
199:   if (ys + ym == my && xs + xm == mx) {
200:     d1 = (user->right[ym + 1] - user->right[ym]) / hy;
201:     d2 = (user->top[xm + 1] - user->top[xm]) / hx;
202:     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
203:   }
204:   ft *= area;
205:   *v = ft;
206:   PetscFunctionReturn(PETSC_SUCCESS);
207: }

209: /* Compute gradient over the locally owned part of the mesh */
210: PetscErrorCode FormFunctionLocal(DMDALocalInfo *info, PetscScalar **x, PetscScalar **g, void *ptr)
211: {
212:   AppCtx     *user = (AppCtx *)ptr;
213:   PetscInt    mx = info->mx, my = info->my;
214:   PetscInt    xs = info->xs, xm = info->xm, ys = info->ys, ym = info->ym;
215:   PetscInt    i, j;
216:   PetscScalar hx, hy, hydhx, hxdhy;
217:   PetscScalar f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb;
218:   PetscScalar df1dxc, df2dxc, df3dxc, df4dxc, df5dxc, df6dxc;

220:   PetscFunctionBeginUser;
221:   PetscCheck(user, PetscObjectComm((PetscObject)info->da), PETSC_ERR_PLIB, "Missing application context");
222:   hx    = 1.0 / (mx + 1);
223:   hy    = 1.0 / (my + 1);
224:   hydhx = hy / hx;
225:   hxdhy = hx / hy;

227:   for (j = ys; j < ys + ym; j++) {
228:     for (i = xs; i < xs + xm; i++) {
229:       xc  = x[j][i];
230:       xlt = xrb = xl = xr = xb = xt = xc;

232:       if (i == 0) { /* left side */
233:         xl  = user->left[j + 1];
234:         xlt = user->left[j + 2];
235:       } else xl = x[j][i - 1];

237:       if (j == 0) { /* bottom side */
238:         xb  = user->bottom[i + 1];
239:         xrb = user->bottom[i + 2];
240:       } else xb = x[j - 1][i];

242:       if (i + 1 == mx) { /* right side */
243:         xr  = user->right[j + 1];
244:         xrb = user->right[j];
245:       } else xr = x[j][i + 1];

247:       if (j + 1 == 0 + my) { /* top side */
248:         xt  = user->top[i + 1];
249:         xlt = user->top[i];
250:       } else xt = x[j + 1][i];

252:       if (i > 0 && j + 1 < my) xlt = x[j + 1][i - 1]; /* left top side */
253:       if (j > 0 && i + 1 < mx) xrb = x[j - 1][i + 1]; /* right bottom */

255:       d1 = (xc - xl);
256:       d2 = (xc - xr);
257:       d3 = (xc - xt);
258:       d4 = (xc - xb);
259:       d5 = (xr - xrb);
260:       d6 = (xrb - xb);
261:       d7 = (xlt - xl);
262:       d8 = (xt - xlt);

264:       df1dxc = d1 * hydhx;
265:       df2dxc = (d1 * hydhx + d4 * hxdhy);
266:       df3dxc = d3 * hxdhy;
267:       df4dxc = (d2 * hydhx + d3 * hxdhy);
268:       df5dxc = d2 * hydhx;
269:       df6dxc = d4 * hxdhy;

271:       d1 /= hx;
272:       d2 /= hx;
273:       d3 /= hy;
274:       d4 /= hy;
275:       d5 /= hy;
276:       d6 /= hx;
277:       d7 /= hy;
278:       d8 /= hx;

280:       f1 = PetscSqrtScalar(1.0 + d1 * d1 + d7 * d7);
281:       f2 = PetscSqrtScalar(1.0 + d1 * d1 + d4 * d4);
282:       f3 = PetscSqrtScalar(1.0 + d3 * d3 + d8 * d8);
283:       f4 = PetscSqrtScalar(1.0 + d3 * d3 + d2 * d2);
284:       f5 = PetscSqrtScalar(1.0 + d2 * d2 + d5 * d5);
285:       f6 = PetscSqrtScalar(1.0 + d4 * d4 + d6 * d6);

287:       df1dxc /= f1;
288:       df2dxc /= f2;
289:       df3dxc /= f3;
290:       df4dxc /= f4;
291:       df5dxc /= f5;
292:       df6dxc /= f6;

294:       g[j][i] = (df1dxc + df2dxc + df3dxc + df4dxc + df5dxc + df6dxc) / 2.0;
295:     }
296:   }
297:   PetscFunctionReturn(PETSC_SUCCESS);
298: }

300: /* Compute Hessian over the locally owned part of the mesh */
301: PetscErrorCode FormJacobianLocal(DMDALocalInfo *info, PetscScalar **x, Mat H, Mat Hp, void *ptr)
302: {
303:   AppCtx     *user = (AppCtx *)ptr;
304:   PetscInt    mx = info->mx, my = info->my;
305:   PetscInt    xs = info->xs, xm = info->xm, ys = info->ys, ym = info->ym;
306:   PetscInt    i, j, k;
307:   MatStencil  row, col[7];
308:   PetscScalar hx, hy, hydhx, hxdhy;
309:   PetscScalar f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb;
310:   PetscScalar hl, hr, ht, hb, hc, htl, hbr;
311:   PetscScalar v[7];

313:   PetscFunctionBeginUser;
314:   PetscCheck(user, PetscObjectComm((PetscObject)info->da), PETSC_ERR_PLIB, "Missing application context");
315:   hx    = 1.0 / (mx + 1);
316:   hy    = 1.0 / (my + 1);
317:   hydhx = hy / hx;
318:   hxdhy = hx / hy;

320:   for (j = ys; j < ys + ym; j++) {
321:     for (i = xs; i < xs + xm; i++) {
322:       xc  = x[j][i];
323:       xlt = xrb = xl = xr = xb = xt = xc;

325:       /* Left */
326:       if (i == 0) {
327:         xl  = user->left[j + 1];
328:         xlt = user->left[j + 2];
329:       } else xl = x[j][i - 1];

331:       /* Bottom */
332:       if (j == 0) {
333:         xb  = user->bottom[i + 1];
334:         xrb = user->bottom[i + 2];
335:       } else xb = x[j - 1][i];

337:       /* Right */
338:       if (i + 1 == mx) {
339:         xr  = user->right[j + 1];
340:         xrb = user->right[j];
341:       } else xr = x[j][i + 1];

343:       /* Top */
344:       if (j + 1 == my) {
345:         xt  = user->top[i + 1];
346:         xlt = user->top[i];
347:       } else xt = x[j + 1][i];

349:       /* Top left */
350:       if (i > 0 && j + 1 < my) xlt = x[j + 1][i - 1];

352:       /* Bottom right */
353:       if (j > 0 && i + 1 < mx) xrb = x[j - 1][i + 1];

355:       d1 = (xc - xl) / hx;
356:       d2 = (xc - xr) / hx;
357:       d3 = (xc - xt) / hy;
358:       d4 = (xc - xb) / hy;
359:       d5 = (xrb - xr) / hy;
360:       d6 = (xrb - xb) / hx;
361:       d7 = (xlt - xl) / hy;
362:       d8 = (xlt - xt) / hx;

364:       f1 = PetscSqrtScalar(1.0 + d1 * d1 + d7 * d7);
365:       f2 = PetscSqrtScalar(1.0 + d1 * d1 + d4 * d4);
366:       f3 = PetscSqrtScalar(1.0 + d3 * d3 + d8 * d8);
367:       f4 = PetscSqrtScalar(1.0 + d3 * d3 + d2 * d2);
368:       f5 = PetscSqrtScalar(1.0 + d2 * d2 + d5 * d5);
369:       f6 = PetscSqrtScalar(1.0 + d4 * d4 + d6 * d6);

371:       hl = (-hydhx * (1.0 + d7 * d7) + d1 * d7) / (f1 * f1 * f1) + (-hydhx * (1.0 + d4 * d4) + d1 * d4) / (f2 * f2 * f2);
372:       hr = (-hydhx * (1.0 + d5 * d5) + d2 * d5) / (f5 * f5 * f5) + (-hydhx * (1.0 + d3 * d3) + d2 * d3) / (f4 * f4 * f4);
373:       ht = (-hxdhy * (1.0 + d8 * d8) + d3 * d8) / (f3 * f3 * f3) + (-hxdhy * (1.0 + d2 * d2) + d2 * d3) / (f4 * f4 * f4);
374:       hb = (-hxdhy * (1.0 + d6 * d6) + d4 * d6) / (f6 * f6 * f6) + (-hxdhy * (1.0 + d1 * d1) + d1 * d4) / (f2 * f2 * f2);

376:       hbr = -d2 * d5 / (f5 * f5 * f5) - d4 * d6 / (f6 * f6 * f6);
377:       htl = -d1 * d7 / (f1 * f1 * f1) - d3 * d8 / (f3 * f3 * f3);

379:       hc = hydhx * (1.0 + d7 * d7) / (f1 * f1 * f1) + hxdhy * (1.0 + d8 * d8) / (f3 * f3 * f3) + hydhx * (1.0 + d5 * d5) / (f5 * f5 * f5) + hxdhy * (1.0 + d6 * d6) / (f6 * f6 * f6) + (hxdhy * (1.0 + d1 * d1) + hydhx * (1.0 + d4 * d4) - 2.0 * d1 * d4) / (f2 * f2 * f2) + (hxdhy * (1.0 + d2 * d2) + hydhx * (1.0 + d3 * d3) - 2.0 * d2 * d3) / (f4 * f4 * f4);

381:       hl /= 2.0;
382:       hr /= 2.0;
383:       ht /= 2.0;
384:       hb /= 2.0;
385:       hbr /= 2.0;
386:       htl /= 2.0;
387:       hc /= 2.0;

389:       k     = 0;
390:       row.i = i;
391:       row.j = j;
392:       /* Bottom */
393:       if (j > 0) {
394:         v[k]     = hb;
395:         col[k].i = i;
396:         col[k].j = j - 1;
397:         k++;
398:       }

400:       /* Bottom right */
401:       if (j > 0 && i < mx - 1) {
402:         v[k]     = hbr;
403:         col[k].i = i + 1;
404:         col[k].j = j - 1;
405:         k++;
406:       }

408:       /* left */
409:       if (i > 0) {
410:         v[k]     = hl;
411:         col[k].i = i - 1;
412:         col[k].j = j;
413:         k++;
414:       }

416:       /* Centre */
417:       v[k]     = hc;
418:       col[k].i = row.i;
419:       col[k].j = row.j;
420:       k++;

422:       /* Right */
423:       if (i < mx - 1) {
424:         v[k]     = hr;
425:         col[k].i = i + 1;
426:         col[k].j = j;
427:         k++;
428:       }

430:       /* Top left */
431:       if (i > 0 && j < my - 1) {
432:         v[k]     = htl;
433:         col[k].i = i - 1;
434:         col[k].j = j + 1;
435:         k++;
436:       }

438:       /* Top */
439:       if (j < my - 1) {
440:         v[k]     = ht;
441:         col[k].i = i;
442:         col[k].j = j + 1;
443:         k++;
444:       }

446:       PetscCall(MatSetValuesStencil(Hp, 1, &row, k, col, v, INSERT_VALUES));
447:     }
448:   }

450:   /* Assemble the matrix */
451:   PetscCall(MatAssemblyBegin(Hp, MAT_FINAL_ASSEMBLY));
452:   PetscCall(MatAssemblyEnd(Hp, MAT_FINAL_ASSEMBLY));
453:   PetscFunctionReturn(PETSC_SUCCESS);
454: }

456: PetscErrorCode FormBoundaryConditions_Enneper(SNES snes, AppCtx **ouser)
457: {
458:   PetscInt     i, j, k, limit = 0, maxits = 5;
459:   PetscInt     mx, my;
460:   PetscInt     bsize = 0, lsize = 0, tsize = 0, rsize = 0;
461:   PetscScalar  one = 1.0, two = 2.0, three = 3.0;
462:   PetscScalar  det, hx, hy, xt = 0, yt = 0;
463:   PetscReal    fnorm, tol = 1e-10;
464:   PetscScalar  u1, u2, nf1, nf2, njac11, njac12, njac21, njac22;
465:   PetscScalar  b = -0.5, t = 0.5, l = -0.5, r = 0.5;
466:   PetscScalar *boundary;
467:   AppCtx      *user;
468:   DM           da;

470:   PetscFunctionBeginUser;
471:   PetscCall(SNESGetDM(snes, &da));
472:   PetscCall(PetscNew(&user));
473:   *ouser = user;
474:   PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
475:   bsize = mx + 2;
476:   lsize = my + 2;
477:   rsize = my + 2;
478:   tsize = mx + 2;

480:   PetscCall(PetscMalloc1(bsize, &user->bottom));
481:   PetscCall(PetscMalloc1(tsize, &user->top));
482:   PetscCall(PetscMalloc1(lsize, &user->left));
483:   PetscCall(PetscMalloc1(rsize, &user->right));

485:   hx = 1.0 / (mx + 1.0);
486:   hy = 1.0 / (my + 1.0);

488:   for (j = 0; j < 4; j++) {
489:     if (j == 0) {
490:       yt       = b;
491:       xt       = l;
492:       limit    = bsize;
493:       boundary = user->bottom;
494:     } else if (j == 1) {
495:       yt       = t;
496:       xt       = l;
497:       limit    = tsize;
498:       boundary = user->top;
499:     } else if (j == 2) {
500:       yt       = b;
501:       xt       = l;
502:       limit    = lsize;
503:       boundary = user->left;
504:     } else { /* if  (j==3) */
505:       yt       = b;
506:       xt       = r;
507:       limit    = rsize;
508:       boundary = user->right;
509:     }

511:     for (i = 0; i < limit; i++) {
512:       u1 = xt;
513:       u2 = -yt;
514:       for (k = 0; k < maxits; k++) {
515:         nf1   = u1 + u1 * u2 * u2 - u1 * u1 * u1 / three - xt;
516:         nf2   = -u2 - u1 * u1 * u2 + u2 * u2 * u2 / three - yt;
517:         fnorm = PetscRealPart(PetscSqrtScalar(nf1 * nf1 + nf2 * nf2));
518:         if (fnorm <= tol) break;
519:         njac11 = one + u2 * u2 - u1 * u1;
520:         njac12 = two * u1 * u2;
521:         njac21 = -two * u1 * u2;
522:         njac22 = -one - u1 * u1 + u2 * u2;
523:         det    = njac11 * njac22 - njac21 * njac12;
524:         u1     = u1 - (njac22 * nf1 - njac12 * nf2) / det;
525:         u2     = u2 - (njac11 * nf2 - njac21 * nf1) / det;
526:       }

528:       boundary[i] = u1 * u1 - u2 * u2;
529:       if (j == 0 || j == 1) xt = xt + hx;
530:       else yt = yt + hy; /* if (j==2 || j==3) */
531:     }
532:   }
533:   PetscFunctionReturn(PETSC_SUCCESS);
534: }

536: PetscErrorCode DestroyBoundaryConditions(AppCtx **ouser)
537: {
538:   AppCtx *user = *ouser;

540:   PetscFunctionBeginUser;
541:   PetscCall(PetscFree(user->bottom));
542:   PetscCall(PetscFree(user->top));
543:   PetscCall(PetscFree(user->left));
544:   PetscCall(PetscFree(user->right));
545:   PetscCall(PetscFree(*ouser));
546:   PetscFunctionReturn(PETSC_SUCCESS);
547: }

549: PetscErrorCode FormBoundaryConditions_Sins(SNES snes, AppCtx **ouser)
550: {
551:   PetscInt     i, j;
552:   PetscInt     mx, my;
553:   PetscInt     limit, bsize = 0, lsize = 0, tsize = 0, rsize = 0;
554:   PetscScalar  hx, hy, xt = 0, yt = 0;
555:   PetscScalar  b = 0.0, t = 1.0, l = 0.0, r = 1.0;
556:   PetscScalar *boundary;
557:   AppCtx      *user;
558:   DM           da;
559:   PetscReal    pi2 = 2 * PETSC_PI;

561:   PetscFunctionBeginUser;
562:   PetscCall(SNESGetDM(snes, &da));
563:   PetscCall(PetscNew(&user));
564:   *ouser = user;
565:   PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
566:   bsize = mx + 2;
567:   lsize = my + 2;
568:   rsize = my + 2;
569:   tsize = mx + 2;

571:   PetscCall(PetscMalloc1(bsize, &user->bottom));
572:   PetscCall(PetscMalloc1(tsize, &user->top));
573:   PetscCall(PetscMalloc1(lsize, &user->left));
574:   PetscCall(PetscMalloc1(rsize, &user->right));

576:   hx = 1.0 / (mx + 1.0);
577:   hy = 1.0 / (my + 1.0);

579:   for (j = 0; j < 4; j++) {
580:     if (j == 0) {
581:       yt       = b;
582:       xt       = l;
583:       limit    = bsize;
584:       boundary = user->bottom;
585:     } else if (j == 1) {
586:       yt       = t;
587:       xt       = l;
588:       limit    = tsize;
589:       boundary = user->top;
590:     } else if (j == 2) {
591:       yt       = b;
592:       xt       = l;
593:       limit    = lsize;
594:       boundary = user->left;
595:     } else { /* if  (j==3) */
596:       yt       = b;
597:       xt       = r;
598:       limit    = rsize;
599:       boundary = user->right;
600:     }

602:     for (i = 0; i < limit; i++) {
603:       if (j == 0) { /* bottom */
604:         boundary[i] = -0.5 * PetscSinReal(pi2 * xt);
605:       } else if (j == 1) { /* top */
606:         boundary[i] = 0.5 * PetscSinReal(pi2 * xt);
607:       } else if (j == 2) { /* left */
608:         boundary[i] = -0.5 * PetscSinReal(pi2 * yt);
609:       } else { /* right */
610:         boundary[i] = 0.5 * PetscSinReal(pi2 * yt);
611:       }
612:       if (j == 0 || j == 1) xt = xt + hx;
613:       else yt = yt + hy;
614:     }
615:   }
616:   PetscFunctionReturn(PETSC_SUCCESS);
617: }

619: /*TEST

621:   build:
622:     requires: !complex

624:   test:
625:     requires: !single
626:     filter: sed -e "s/CONVERGED_FNORM_ABS/CONVERGED_FNORM_RELATIVE/g"
627:     suffix: qn_nasm
628:     args: -snes_type qn -snes_npc_side {{left right}separate output} -npc_snes_type nasm -snes_converged_reason -da_local_subdomains 4 -use_objective {{0 1}separate output}

630: TEST*/