xref: /petsc/src/snes/tutorials/ex55.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1c5566c22SJunchao Zhang static char help[] = "Copy of ex5.c\n";
2c5566c22SJunchao Zhang 
3c5566c22SJunchao Zhang /* ------------------------------------------------------------------------
4c5566c22SJunchao Zhang 
5c5566c22SJunchao Zhang   Copy of ex5.c.
6c5566c22SJunchao Zhang   Once petsc test harness supports conditional linking, we can remove this duplicate.
7c5566c22SJunchao Zhang   See https://gitlab.com/petsc/petsc/-/issues/1173
8c5566c22SJunchao Zhang   ------------------------------------------------------------------------- */
9c5566c22SJunchao Zhang 
10c5566c22SJunchao Zhang /*
11c5566c22SJunchao Zhang    Include "petscdmda.h" so that we can use distributed arrays (DMDAs).
12c5566c22SJunchao Zhang    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
13c5566c22SJunchao Zhang */
14c5566c22SJunchao Zhang #include <petscdm.h>
15c5566c22SJunchao Zhang #include <petscdmda.h>
16c5566c22SJunchao Zhang #include <petscsnes.h>
17c5566c22SJunchao Zhang #include <petscmatlab.h>
18c5566c22SJunchao Zhang #include <petsc/private/snesimpl.h> /* For SNES_Solve event */
19c5566c22SJunchao Zhang #include "ex55.h"
20c5566c22SJunchao Zhang 
21c5566c22SJunchao Zhang /* ------------------------------------------------------------------- */
22c5566c22SJunchao Zhang /*
23c5566c22SJunchao Zhang    FormInitialGuess - Forms initial approximation.
24c5566c22SJunchao Zhang 
25c5566c22SJunchao Zhang    Input Parameters:
26c5566c22SJunchao Zhang    da - The DM
27c5566c22SJunchao Zhang    user - user-defined application context
28c5566c22SJunchao Zhang 
29c5566c22SJunchao Zhang    Output Parameter:
30c5566c22SJunchao Zhang    X - vector
31c5566c22SJunchao Zhang  */
329371c9d4SSatish Balay static PetscErrorCode FormInitialGuess(DM da, AppCtx *user, Vec X) {
33c5566c22SJunchao Zhang   PetscInt      i, j, Mx, My, xs, ys, xm, ym;
34c5566c22SJunchao Zhang   PetscReal     lambda, temp1, temp, hx, hy;
35c5566c22SJunchao Zhang   PetscScalar **x;
36c5566c22SJunchao Zhang 
37c5566c22SJunchao Zhang   PetscFunctionBeginUser;
38c5566c22SJunchao Zhang   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));
39c5566c22SJunchao Zhang 
40c5566c22SJunchao Zhang   lambda = user->param;
41c5566c22SJunchao Zhang   hx     = 1.0 / (PetscReal)(Mx - 1);
42c5566c22SJunchao Zhang   hy     = 1.0 / (PetscReal)(My - 1);
43c5566c22SJunchao Zhang   temp1  = lambda / (lambda + 1.0);
44c5566c22SJunchao Zhang 
45c5566c22SJunchao Zhang   /*
46c5566c22SJunchao Zhang      Get a pointer to vector data.
47c5566c22SJunchao Zhang        - For default PETSc vectors, VecGetArray() returns a pointer to
48c5566c22SJunchao Zhang          the data array.  Otherwise, the routine is implementation dependent.
49c5566c22SJunchao Zhang        - You MUST call VecRestoreArray() when you no longer need access to
50c5566c22SJunchao Zhang          the array.
51c5566c22SJunchao Zhang   */
52c5566c22SJunchao Zhang   PetscCall(DMDAVecGetArray(da, X, &x));
53c5566c22SJunchao Zhang 
54c5566c22SJunchao Zhang   /*
55c5566c22SJunchao Zhang      Get local grid boundaries (for 2-dimensional DMDA):
56c5566c22SJunchao Zhang        xs, ys   - starting grid indices (no ghost points)
57c5566c22SJunchao Zhang        xm, ym   - widths of local grid (no ghost points)
58c5566c22SJunchao Zhang 
59c5566c22SJunchao Zhang   */
60c5566c22SJunchao Zhang   PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
61c5566c22SJunchao Zhang 
62c5566c22SJunchao Zhang   /*
63c5566c22SJunchao Zhang      Compute initial guess over the locally owned part of the grid
64c5566c22SJunchao Zhang   */
65c5566c22SJunchao Zhang   for (j = ys; j < ys + ym; j++) {
66c5566c22SJunchao Zhang     temp = (PetscReal)(PetscMin(j, My - j - 1)) * hy;
67c5566c22SJunchao Zhang     for (i = xs; i < xs + xm; i++) {
68c5566c22SJunchao Zhang       if (i == 0 || j == 0 || i == Mx - 1 || j == My - 1) {
69c5566c22SJunchao Zhang         /* boundary conditions are all zero Dirichlet */
70c5566c22SJunchao Zhang         x[j][i] = 0.0;
71c5566c22SJunchao Zhang       } else {
72c5566c22SJunchao Zhang         x[j][i] = temp1 * PetscSqrtReal(PetscMin((PetscReal)(PetscMin(i, Mx - i - 1)) * hx, temp));
73c5566c22SJunchao Zhang       }
74c5566c22SJunchao Zhang     }
75c5566c22SJunchao Zhang   }
76c5566c22SJunchao Zhang 
77c5566c22SJunchao Zhang   /*
78c5566c22SJunchao Zhang      Restore vector
79c5566c22SJunchao Zhang   */
80c5566c22SJunchao Zhang   PetscCall(DMDAVecRestoreArray(da, X, &x));
81c5566c22SJunchao Zhang   PetscFunctionReturn(0);
82c5566c22SJunchao Zhang }
83c5566c22SJunchao Zhang 
84c5566c22SJunchao Zhang /*
85c5566c22SJunchao Zhang   FormExactSolution - Forms MMS solution
86c5566c22SJunchao Zhang 
87c5566c22SJunchao Zhang   Input Parameters:
88c5566c22SJunchao Zhang   da - The DM
89c5566c22SJunchao Zhang   user - user-defined application context
90c5566c22SJunchao Zhang 
91c5566c22SJunchao Zhang   Output Parameter:
92c5566c22SJunchao Zhang   X - vector
93c5566c22SJunchao Zhang  */
949371c9d4SSatish Balay static PetscErrorCode FormExactSolution(DM da, AppCtx *user, Vec U) {
95c5566c22SJunchao Zhang   DM            coordDA;
96c5566c22SJunchao Zhang   Vec           coordinates;
97c5566c22SJunchao Zhang   DMDACoor2d  **coords;
98c5566c22SJunchao Zhang   PetscScalar **u;
99c5566c22SJunchao Zhang   PetscInt      xs, ys, xm, ym, i, j;
100c5566c22SJunchao Zhang 
101c5566c22SJunchao Zhang   PetscFunctionBeginUser;
102c5566c22SJunchao Zhang   PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
103c5566c22SJunchao Zhang   PetscCall(DMGetCoordinateDM(da, &coordDA));
104c5566c22SJunchao Zhang   PetscCall(DMGetCoordinates(da, &coordinates));
105c5566c22SJunchao Zhang   PetscCall(DMDAVecGetArray(coordDA, coordinates, &coords));
106c5566c22SJunchao Zhang   PetscCall(DMDAVecGetArray(da, U, &u));
107c5566c22SJunchao Zhang   for (j = ys; j < ys + ym; ++j) {
1089371c9d4SSatish Balay     for (i = xs; i < xs + xm; ++i) { user->mms_solution(user, &coords[j][i], &u[j][i]); }
109c5566c22SJunchao Zhang   }
110c5566c22SJunchao Zhang   PetscCall(DMDAVecRestoreArray(da, U, &u));
111c5566c22SJunchao Zhang   PetscCall(DMDAVecRestoreArray(coordDA, coordinates, &coords));
112c5566c22SJunchao Zhang   PetscFunctionReturn(0);
113c5566c22SJunchao Zhang }
114c5566c22SJunchao Zhang 
1159371c9d4SSatish Balay static PetscErrorCode ZeroBCSolution(AppCtx *user, const DMDACoor2d *c, PetscScalar *u) {
116c5566c22SJunchao Zhang   u[0] = 0.;
117c5566c22SJunchao Zhang   return 0;
118c5566c22SJunchao Zhang }
119c5566c22SJunchao Zhang 
120c5566c22SJunchao Zhang /* The functions below evaluate the MMS solution u(x,y) and associated forcing
121c5566c22SJunchao Zhang 
122c5566c22SJunchao Zhang      f(x,y) = -u_xx - u_yy - lambda exp(u)
123c5566c22SJunchao Zhang 
124c5566c22SJunchao Zhang   such that u(x,y) is an exact solution with f(x,y) as the right hand side forcing term.
125c5566c22SJunchao Zhang  */
1269371c9d4SSatish Balay static PetscErrorCode MMSSolution1(AppCtx *user, const DMDACoor2d *c, PetscScalar *u) {
127c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
128c5566c22SJunchao Zhang   u[0] = x * (1 - x) * y * (1 - y);
129c5566c22SJunchao Zhang   PetscLogFlops(5);
130c5566c22SJunchao Zhang   return 0;
131c5566c22SJunchao Zhang }
1329371c9d4SSatish Balay static PetscErrorCode MMSForcing1(AppCtx *user, const DMDACoor2d *c, PetscScalar *f) {
133c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
134c5566c22SJunchao Zhang   f[0] = 2 * x * (1 - x) + 2 * y * (1 - y) - user->param * PetscExpReal(x * (1 - x) * y * (1 - y));
135c5566c22SJunchao Zhang   return 0;
136c5566c22SJunchao Zhang }
137c5566c22SJunchao Zhang 
1389371c9d4SSatish Balay static PetscErrorCode MMSSolution2(AppCtx *user, const DMDACoor2d *c, PetscScalar *u) {
139c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
140c5566c22SJunchao Zhang   u[0] = PetscSinReal(PETSC_PI * x) * PetscSinReal(PETSC_PI * y);
141c5566c22SJunchao Zhang   PetscLogFlops(5);
142c5566c22SJunchao Zhang   return 0;
143c5566c22SJunchao Zhang }
1449371c9d4SSatish Balay static PetscErrorCode MMSForcing2(AppCtx *user, const DMDACoor2d *c, PetscScalar *f) {
145c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
146c5566c22SJunchao Zhang   f[0] = 2 * PetscSqr(PETSC_PI) * PetscSinReal(PETSC_PI * x) * PetscSinReal(PETSC_PI * y) - user->param * PetscExpReal(PetscSinReal(PETSC_PI * x) * PetscSinReal(PETSC_PI * y));
147c5566c22SJunchao Zhang   return 0;
148c5566c22SJunchao Zhang }
149c5566c22SJunchao Zhang 
1509371c9d4SSatish Balay static PetscErrorCode MMSSolution3(AppCtx *user, const DMDACoor2d *c, PetscScalar *u) {
151c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
152c5566c22SJunchao Zhang   u[0] = PetscSinReal(user->m * PETSC_PI * x * (1 - y)) * PetscSinReal(user->n * PETSC_PI * y * (1 - x));
153c5566c22SJunchao Zhang   PetscLogFlops(5);
154c5566c22SJunchao Zhang   return 0;
155c5566c22SJunchao Zhang }
1569371c9d4SSatish Balay static PetscErrorCode MMSForcing3(AppCtx *user, const DMDACoor2d *c, PetscScalar *f) {
157c5566c22SJunchao Zhang   PetscReal x = PetscRealPart(c->x), y = PetscRealPart(c->y);
158c5566c22SJunchao Zhang   PetscReal m = user->m, n = user->n, lambda = user->param;
1599371c9d4SSatish Balay   f[0] = (-(PetscExpReal(PetscSinReal(m * PETSC_PI * x * (1 - y)) * PetscSinReal(n * PETSC_PI * (1 - x) * y)) * lambda) + PetscSqr(PETSC_PI) * (-2 * m * n * ((-1 + x) * x + (-1 + y) * y) * PetscCosReal(m * PETSC_PI * x * (-1 + y)) * PetscCosReal(n * PETSC_PI * (-1 + x) * y) + (PetscSqr(m) * (PetscSqr(x) + PetscSqr(-1 + y)) + PetscSqr(n) * (PetscSqr(-1 + x) + PetscSqr(y))) * PetscSinReal(m * PETSC_PI * x * (-1 + y)) * PetscSinReal(n * PETSC_PI * (-1 + x) * y)));
160c5566c22SJunchao Zhang   return 0;
161c5566c22SJunchao Zhang }
162c5566c22SJunchao Zhang 
1639371c9d4SSatish Balay static PetscErrorCode MMSSolution4(AppCtx *user, const DMDACoor2d *c, PetscScalar *u) {
164c5566c22SJunchao Zhang   const PetscReal Lx = 1., Ly = 1.;
165c5566c22SJunchao Zhang   PetscReal       x = PetscRealPart(c->x), y = PetscRealPart(c->y);
166c5566c22SJunchao Zhang   u[0] = (PetscPowReal(x, 4) - PetscSqr(Lx) * PetscSqr(x)) * (PetscPowReal(y, 4) - PetscSqr(Ly) * PetscSqr(y));
167c5566c22SJunchao Zhang   PetscLogFlops(9);
168c5566c22SJunchao Zhang   return 0;
169c5566c22SJunchao Zhang }
1709371c9d4SSatish Balay static PetscErrorCode MMSForcing4(AppCtx *user, const DMDACoor2d *c, PetscScalar *f) {
171c5566c22SJunchao Zhang   const PetscReal Lx = 1., Ly = 1.;
172c5566c22SJunchao Zhang   PetscReal       x = PetscRealPart(c->x), y = PetscRealPart(c->y);
1739371c9d4SSatish Balay   f[0] = (2 * PetscSqr(x) * (PetscSqr(x) - PetscSqr(Lx)) * (PetscSqr(Ly) - 6 * PetscSqr(y)) + 2 * PetscSqr(y) * (PetscSqr(Lx) - 6 * PetscSqr(x)) * (PetscSqr(y) - PetscSqr(Ly)) - user->param * PetscExpReal((PetscPowReal(x, 4) - PetscSqr(Lx) * PetscSqr(x)) * (PetscPowReal(y, 4) - PetscSqr(Ly) * PetscSqr(y))));
174c5566c22SJunchao Zhang   return 0;
175c5566c22SJunchao Zhang }
176c5566c22SJunchao Zhang 
177c5566c22SJunchao Zhang /* ------------------------------------------------------------------- */
178c5566c22SJunchao Zhang /*
179c5566c22SJunchao Zhang    FormFunctionLocal - Evaluates nonlinear function, F(x) on local process patch
180c5566c22SJunchao Zhang 
181c5566c22SJunchao Zhang  */
1829371c9d4SSatish Balay static PetscErrorCode FormFunctionLocal(DMDALocalInfo *info, PetscScalar **x, PetscScalar **f, AppCtx *user) {
183c5566c22SJunchao Zhang   PetscInt    i, j;
184c5566c22SJunchao Zhang   PetscReal   lambda, hx, hy, hxdhy, hydhx;
185c5566c22SJunchao Zhang   PetscScalar u, ue, uw, un, us, uxx, uyy, mms_solution, mms_forcing;
186c5566c22SJunchao Zhang   DMDACoor2d  c;
187c5566c22SJunchao Zhang 
188c5566c22SJunchao Zhang   PetscFunctionBeginUser;
189c5566c22SJunchao Zhang   lambda = user->param;
190c5566c22SJunchao Zhang   hx     = 1.0 / (PetscReal)(info->mx - 1);
191c5566c22SJunchao Zhang   hy     = 1.0 / (PetscReal)(info->my - 1);
192c5566c22SJunchao Zhang   hxdhy  = hx / hy;
193c5566c22SJunchao Zhang   hydhx  = hy / hx;
194c5566c22SJunchao Zhang   /*
195c5566c22SJunchao Zhang      Compute function over the locally owned part of the grid
196c5566c22SJunchao Zhang   */
197c5566c22SJunchao Zhang   for (j = info->ys; j < info->ys + info->ym; j++) {
198c5566c22SJunchao Zhang     for (i = info->xs; i < info->xs + info->xm; i++) {
199c5566c22SJunchao Zhang       if (i == 0 || j == 0 || i == info->mx - 1 || j == info->my - 1) {
2009371c9d4SSatish Balay         c.x = i * hx;
2019371c9d4SSatish Balay         c.y = j * hy;
202c5566c22SJunchao Zhang         PetscCall(user->mms_solution(user, &c, &mms_solution));
203c5566c22SJunchao Zhang         f[j][i] = 2.0 * (hydhx + hxdhy) * (x[j][i] - mms_solution);
204c5566c22SJunchao Zhang       } else {
205c5566c22SJunchao Zhang         u  = x[j][i];
206c5566c22SJunchao Zhang         uw = x[j][i - 1];
207c5566c22SJunchao Zhang         ue = x[j][i + 1];
208c5566c22SJunchao Zhang         un = x[j - 1][i];
209c5566c22SJunchao Zhang         us = x[j + 1][i];
210c5566c22SJunchao Zhang 
211c5566c22SJunchao Zhang         /* Enforce boundary conditions at neighboring points -- setting these values causes the Jacobian to be symmetric. */
2129371c9d4SSatish Balay         if (i - 1 == 0) {
2139371c9d4SSatish Balay           c.x = (i - 1) * hx;
2149371c9d4SSatish Balay           c.y = j * hy;
2159371c9d4SSatish Balay           PetscCall(user->mms_solution(user, &c, &uw));
2169371c9d4SSatish Balay         }
2179371c9d4SSatish Balay         if (i + 1 == info->mx - 1) {
2189371c9d4SSatish Balay           c.x = (i + 1) * hx;
2199371c9d4SSatish Balay           c.y = j * hy;
2209371c9d4SSatish Balay           PetscCall(user->mms_solution(user, &c, &ue));
2219371c9d4SSatish Balay         }
2229371c9d4SSatish Balay         if (j - 1 == 0) {
2239371c9d4SSatish Balay           c.x = i * hx;
2249371c9d4SSatish Balay           c.y = (j - 1) * hy;
2259371c9d4SSatish Balay           PetscCall(user->mms_solution(user, &c, &un));
2269371c9d4SSatish Balay         }
2279371c9d4SSatish Balay         if (j + 1 == info->my - 1) {
2289371c9d4SSatish Balay           c.x = i * hx;
2299371c9d4SSatish Balay           c.y = (j + 1) * hy;
2309371c9d4SSatish Balay           PetscCall(user->mms_solution(user, &c, &us));
2319371c9d4SSatish Balay         }
232c5566c22SJunchao Zhang 
233c5566c22SJunchao Zhang         uxx         = (2.0 * u - uw - ue) * hydhx;
234c5566c22SJunchao Zhang         uyy         = (2.0 * u - un - us) * hxdhy;
235c5566c22SJunchao Zhang         mms_forcing = 0;
2369371c9d4SSatish Balay         c.x         = i * hx;
2379371c9d4SSatish Balay         c.y         = j * hy;
238c5566c22SJunchao Zhang         if (user->mms_forcing) PetscCall(user->mms_forcing(user, &c, &mms_forcing));
239c5566c22SJunchao Zhang         f[j][i] = uxx + uyy - hx * hy * (lambda * PetscExpScalar(u) + mms_forcing);
240c5566c22SJunchao Zhang       }
241c5566c22SJunchao Zhang     }
242c5566c22SJunchao Zhang   }
243c5566c22SJunchao Zhang   PetscCall(PetscLogFlops(11.0 * info->ym * info->xm));
244c5566c22SJunchao Zhang   PetscFunctionReturn(0);
245c5566c22SJunchao Zhang }
246c5566c22SJunchao Zhang 
247c5566c22SJunchao Zhang /* FormObjectiveLocal - Evaluates nonlinear function, F(x) on local process patch */
2489371c9d4SSatish Balay static PetscErrorCode FormObjectiveLocal(DMDALocalInfo *info, PetscScalar **x, PetscReal *obj, AppCtx *user) {
249c5566c22SJunchao Zhang   PetscInt    i, j;
250c5566c22SJunchao Zhang   PetscReal   lambda, hx, hy, hxdhy, hydhx, sc, lobj = 0;
251c5566c22SJunchao Zhang   PetscScalar u, ue, uw, un, us, uxux, uyuy;
252c5566c22SJunchao Zhang   MPI_Comm    comm;
253c5566c22SJunchao Zhang 
254c5566c22SJunchao Zhang   PetscFunctionBeginUser;
255c5566c22SJunchao Zhang   *obj = 0;
256c5566c22SJunchao Zhang   PetscCall(PetscObjectGetComm((PetscObject)info->da, &comm));
257c5566c22SJunchao Zhang   lambda = user->param;
258c5566c22SJunchao Zhang   hx     = 1.0 / (PetscReal)(info->mx - 1);
259c5566c22SJunchao Zhang   hy     = 1.0 / (PetscReal)(info->my - 1);
260c5566c22SJunchao Zhang   sc     = hx * hy * lambda;
261c5566c22SJunchao Zhang   hxdhy  = hx / hy;
262c5566c22SJunchao Zhang   hydhx  = hy / hx;
263c5566c22SJunchao Zhang   /*
264c5566c22SJunchao Zhang      Compute function over the locally owned part of the grid
265c5566c22SJunchao Zhang   */
266c5566c22SJunchao Zhang   for (j = info->ys; j < info->ys + info->ym; j++) {
267c5566c22SJunchao Zhang     for (i = info->xs; i < info->xs + info->xm; i++) {
268c5566c22SJunchao Zhang       if (i == 0 || j == 0 || i == info->mx - 1 || j == info->my - 1) {
269c5566c22SJunchao Zhang         lobj += PetscRealPart((hydhx + hxdhy) * x[j][i] * x[j][i]);
270c5566c22SJunchao Zhang       } else {
271c5566c22SJunchao Zhang         u  = x[j][i];
272c5566c22SJunchao Zhang         uw = x[j][i - 1];
273c5566c22SJunchao Zhang         ue = x[j][i + 1];
274c5566c22SJunchao Zhang         un = x[j - 1][i];
275c5566c22SJunchao Zhang         us = x[j + 1][i];
276c5566c22SJunchao Zhang 
277c5566c22SJunchao Zhang         if (i - 1 == 0) uw = 0.;
278c5566c22SJunchao Zhang         if (i + 1 == info->mx - 1) ue = 0.;
279c5566c22SJunchao Zhang         if (j - 1 == 0) un = 0.;
280c5566c22SJunchao Zhang         if (j + 1 == info->my - 1) us = 0.;
281c5566c22SJunchao Zhang 
282c5566c22SJunchao Zhang         /* F[u] = 1/2\int_{\omega}\nabla^2u(x)*u(x)*dx */
283c5566c22SJunchao Zhang 
284c5566c22SJunchao Zhang         uxux = u * (2. * u - ue - uw) * hydhx;
285c5566c22SJunchao Zhang         uyuy = u * (2. * u - un - us) * hxdhy;
286c5566c22SJunchao Zhang 
287c5566c22SJunchao Zhang         lobj += PetscRealPart(0.5 * (uxux + uyuy) - sc * PetscExpScalar(u));
288c5566c22SJunchao Zhang       }
289c5566c22SJunchao Zhang     }
290c5566c22SJunchao Zhang   }
291c5566c22SJunchao Zhang   PetscCall(PetscLogFlops(12.0 * info->ym * info->xm));
292c5566c22SJunchao Zhang   PetscCallMPI(MPI_Allreduce(&lobj, obj, 1, MPIU_REAL, MPIU_SUM, comm));
293c5566c22SJunchao Zhang   PetscFunctionReturn(0);
294c5566c22SJunchao Zhang }
295c5566c22SJunchao Zhang 
296c5566c22SJunchao Zhang /*
297c5566c22SJunchao Zhang    FormJacobianLocal - Evaluates Jacobian matrix on local process patch
298c5566c22SJunchao Zhang */
2999371c9d4SSatish Balay static PetscErrorCode FormJacobianLocal(DMDALocalInfo *info, PetscScalar **x, Mat jac, Mat jacpre, AppCtx *user) {
300c5566c22SJunchao Zhang   PetscInt     i, j, k;
301c5566c22SJunchao Zhang   MatStencil   col[5], row;
302c5566c22SJunchao Zhang   PetscScalar  lambda, v[5], hx, hy, hxdhy, hydhx, sc;
303c5566c22SJunchao Zhang   DM           coordDA;
304c5566c22SJunchao Zhang   Vec          coordinates;
305c5566c22SJunchao Zhang   DMDACoor2d **coords;
306c5566c22SJunchao Zhang 
307c5566c22SJunchao Zhang   PetscFunctionBeginUser;
308c5566c22SJunchao Zhang   lambda = user->param;
309c5566c22SJunchao Zhang   /* Extract coordinates */
310c5566c22SJunchao Zhang   PetscCall(DMGetCoordinateDM(info->da, &coordDA));
311c5566c22SJunchao Zhang   PetscCall(DMGetCoordinates(info->da, &coordinates));
312c5566c22SJunchao Zhang   PetscCall(DMDAVecGetArray(coordDA, coordinates, &coords));
313c5566c22SJunchao Zhang   hx = info->xm > 1 ? PetscRealPart(coords[info->ys][info->xs + 1].x) - PetscRealPart(coords[info->ys][info->xs].x) : 1.0;
314c5566c22SJunchao Zhang   hy = info->ym > 1 ? PetscRealPart(coords[info->ys + 1][info->xs].y) - PetscRealPart(coords[info->ys][info->xs].y) : 1.0;
315c5566c22SJunchao Zhang   PetscCall(DMDAVecRestoreArray(coordDA, coordinates, &coords));
316c5566c22SJunchao Zhang   hxdhy = hx / hy;
317c5566c22SJunchao Zhang   hydhx = hy / hx;
318c5566c22SJunchao Zhang   sc    = hx * hy * lambda;
319c5566c22SJunchao Zhang 
320c5566c22SJunchao Zhang   /*
321c5566c22SJunchao Zhang      Compute entries for the locally owned part of the Jacobian.
322c5566c22SJunchao Zhang       - Currently, all PETSc parallel matrix formats are partitioned by
323c5566c22SJunchao Zhang         contiguous chunks of rows across the processors.
324c5566c22SJunchao Zhang       - Each processor needs to insert only elements that it owns
325c5566c22SJunchao Zhang         locally (but any non-local elements will be sent to the
326c5566c22SJunchao Zhang         appropriate processor during matrix assembly).
327c5566c22SJunchao Zhang       - Here, we set all entries for a particular row at once.
328c5566c22SJunchao Zhang       - We can set matrix entries either using either
329c5566c22SJunchao Zhang         MatSetValuesLocal() or MatSetValues(), as discussed above.
330c5566c22SJunchao Zhang   */
331c5566c22SJunchao Zhang   for (j = info->ys; j < info->ys + info->ym; j++) {
332c5566c22SJunchao Zhang     for (i = info->xs; i < info->xs + info->xm; i++) {
3339371c9d4SSatish Balay       row.j = j;
3349371c9d4SSatish Balay       row.i = i;
335c5566c22SJunchao Zhang       /* boundary points */
336c5566c22SJunchao Zhang       if (i == 0 || j == 0 || i == info->mx - 1 || j == info->my - 1) {
337c5566c22SJunchao Zhang         v[0] = 2.0 * (hydhx + hxdhy);
338c5566c22SJunchao Zhang         PetscCall(MatSetValuesStencil(jacpre, 1, &row, 1, &row, v, INSERT_VALUES));
339c5566c22SJunchao Zhang       } else {
340c5566c22SJunchao Zhang         k = 0;
341c5566c22SJunchao Zhang         /* interior grid points */
342c5566c22SJunchao Zhang         if (j - 1 != 0) {
343c5566c22SJunchao Zhang           v[k]     = -hxdhy;
3449371c9d4SSatish Balay           col[k].j = j - 1;
3459371c9d4SSatish Balay           col[k].i = i;
346c5566c22SJunchao Zhang           k++;
347c5566c22SJunchao Zhang         }
348c5566c22SJunchao Zhang         if (i - 1 != 0) {
349c5566c22SJunchao Zhang           v[k]     = -hydhx;
3509371c9d4SSatish Balay           col[k].j = j;
3519371c9d4SSatish Balay           col[k].i = i - 1;
352c5566c22SJunchao Zhang           k++;
353c5566c22SJunchao Zhang         }
354c5566c22SJunchao Zhang 
3559371c9d4SSatish Balay         v[k]     = 2.0 * (hydhx + hxdhy) - sc * PetscExpScalar(x[j][i]);
3569371c9d4SSatish Balay         col[k].j = row.j;
3579371c9d4SSatish Balay         col[k].i = row.i;
3589371c9d4SSatish Balay         k++;
359c5566c22SJunchao Zhang 
360c5566c22SJunchao Zhang         if (i + 1 != info->mx - 1) {
361c5566c22SJunchao Zhang           v[k]     = -hydhx;
3629371c9d4SSatish Balay           col[k].j = j;
3639371c9d4SSatish Balay           col[k].i = i + 1;
364c5566c22SJunchao Zhang           k++;
365c5566c22SJunchao Zhang         }
366c5566c22SJunchao Zhang         if (j + 1 != info->mx - 1) {
367c5566c22SJunchao Zhang           v[k]     = -hxdhy;
3689371c9d4SSatish Balay           col[k].j = j + 1;
3699371c9d4SSatish Balay           col[k].i = i;
370c5566c22SJunchao Zhang           k++;
371c5566c22SJunchao Zhang         }
372c5566c22SJunchao Zhang         PetscCall(MatSetValuesStencil(jacpre, 1, &row, k, col, v, INSERT_VALUES));
373c5566c22SJunchao Zhang       }
374c5566c22SJunchao Zhang     }
375c5566c22SJunchao Zhang   }
376c5566c22SJunchao Zhang 
377c5566c22SJunchao Zhang   /*
378c5566c22SJunchao Zhang      Assemble matrix, using the 2-step process:
379c5566c22SJunchao Zhang        MatAssemblyBegin(), MatAssemblyEnd().
380c5566c22SJunchao Zhang   */
381c5566c22SJunchao Zhang   PetscCall(MatAssemblyBegin(jacpre, MAT_FINAL_ASSEMBLY));
382c5566c22SJunchao Zhang   PetscCall(MatAssemblyEnd(jacpre, MAT_FINAL_ASSEMBLY));
383c5566c22SJunchao Zhang 
384c5566c22SJunchao Zhang   /*
385c5566c22SJunchao Zhang      Tell the matrix we will never add a new nonzero location to the
386c5566c22SJunchao Zhang      matrix. If we do, it will generate an error.
387c5566c22SJunchao Zhang   */
388c5566c22SJunchao Zhang   PetscCall(MatSetOption(jac, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
389c5566c22SJunchao Zhang   PetscFunctionReturn(0);
390c5566c22SJunchao Zhang }
391c5566c22SJunchao Zhang 
3929371c9d4SSatish Balay static PetscErrorCode FormFunctionMatlab(SNES snes, Vec X, Vec F, void *ptr) {
393c5566c22SJunchao Zhang #if PetscDefined(HAVE_MATLAB_ENGINE)
394c5566c22SJunchao Zhang   AppCtx   *user = (AppCtx *)ptr;
395c5566c22SJunchao Zhang   PetscInt  Mx, My;
396c5566c22SJunchao Zhang   PetscReal lambda, hx, hy;
397c5566c22SJunchao Zhang   Vec       localX, localF;
398c5566c22SJunchao Zhang   MPI_Comm  comm;
399c5566c22SJunchao Zhang   DM        da;
400c5566c22SJunchao Zhang 
401c5566c22SJunchao Zhang   PetscFunctionBeginUser;
402c5566c22SJunchao Zhang   PetscCall(SNESGetDM(snes, &da));
403c5566c22SJunchao Zhang   PetscCall(DMGetLocalVector(da, &localX));
404c5566c22SJunchao Zhang   PetscCall(DMGetLocalVector(da, &localF));
405c5566c22SJunchao Zhang   PetscCall(PetscObjectSetName((PetscObject)localX, "localX"));
406c5566c22SJunchao Zhang   PetscCall(PetscObjectSetName((PetscObject)localF, "localF"));
407c5566c22SJunchao Zhang   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));
408c5566c22SJunchao Zhang 
409c5566c22SJunchao Zhang   lambda = user->param;
410c5566c22SJunchao Zhang   hx     = 1.0 / (PetscReal)(Mx - 1);
411c5566c22SJunchao Zhang   hy     = 1.0 / (PetscReal)(My - 1);
412c5566c22SJunchao Zhang 
413c5566c22SJunchao Zhang   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
414c5566c22SJunchao Zhang   /*
415c5566c22SJunchao Zhang      Scatter ghost points to local vector,using the 2-step process
416c5566c22SJunchao Zhang         DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
417c5566c22SJunchao Zhang      By placing code between these two statements, computations can be
418c5566c22SJunchao Zhang      done while messages are in transition.
419c5566c22SJunchao Zhang   */
420c5566c22SJunchao Zhang   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX));
421c5566c22SJunchao Zhang   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX));
422c5566c22SJunchao Zhang   PetscCall(PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(comm), (PetscObject)localX));
423c5566c22SJunchao Zhang   PetscCall(PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(comm), "localF=ex5m(localX,%18.16e,%18.16e,%18.16e)", (double)hx, (double)hy, (double)lambda));
424c5566c22SJunchao Zhang   PetscCall(PetscMatlabEngineGet(PETSC_MATLAB_ENGINE_(comm), (PetscObject)localF));
425c5566c22SJunchao Zhang 
426c5566c22SJunchao Zhang   /*
427c5566c22SJunchao Zhang      Insert values into global vector
428c5566c22SJunchao Zhang   */
429c5566c22SJunchao Zhang   PetscCall(DMLocalToGlobalBegin(da, localF, INSERT_VALUES, F));
430c5566c22SJunchao Zhang   PetscCall(DMLocalToGlobalEnd(da, localF, INSERT_VALUES, F));
431c5566c22SJunchao Zhang   PetscCall(DMRestoreLocalVector(da, &localX));
432c5566c22SJunchao Zhang   PetscCall(DMRestoreLocalVector(da, &localF));
433c5566c22SJunchao Zhang   PetscFunctionReturn(0);
434c5566c22SJunchao Zhang #else
435c5566c22SJunchao Zhang   return 0; /* Never called */
436c5566c22SJunchao Zhang #endif
437c5566c22SJunchao Zhang }
438c5566c22SJunchao Zhang 
439c5566c22SJunchao Zhang /* ------------------------------------------------------------------- */
440c5566c22SJunchao Zhang /*
441c5566c22SJunchao Zhang       Applies some sweeps on nonlinear Gauss-Seidel on each process
442c5566c22SJunchao Zhang 
443c5566c22SJunchao Zhang  */
4449371c9d4SSatish Balay static PetscErrorCode NonlinearGS(SNES snes, Vec X, Vec B, void *ctx) {
445c5566c22SJunchao Zhang   PetscInt      i, j, k, Mx, My, xs, ys, xm, ym, its, tot_its, sweeps, l;
446c5566c22SJunchao Zhang   PetscReal     lambda, hx, hy, hxdhy, hydhx, sc;
447c5566c22SJunchao Zhang   PetscScalar **x, **b, bij, F, F0 = 0, J, u, un, us, ue, eu, uw, uxx, uyy, y;
448c5566c22SJunchao Zhang   PetscReal     atol, rtol, stol;
449c5566c22SJunchao Zhang   DM            da;
450c5566c22SJunchao Zhang   AppCtx       *user;
451c5566c22SJunchao Zhang   Vec           localX, localB;
452c5566c22SJunchao Zhang 
453c5566c22SJunchao Zhang   PetscFunctionBeginUser;
454c5566c22SJunchao Zhang   tot_its = 0;
455c5566c22SJunchao Zhang   PetscCall(SNESNGSGetSweeps(snes, &sweeps));
456c5566c22SJunchao Zhang   PetscCall(SNESNGSGetTolerances(snes, &atol, &rtol, &stol, &its));
457c5566c22SJunchao Zhang   PetscCall(SNESGetDM(snes, &da));
458c5566c22SJunchao Zhang   PetscCall(DMGetApplicationContext(da, &user));
459c5566c22SJunchao Zhang 
460c5566c22SJunchao Zhang   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));
461c5566c22SJunchao Zhang 
462c5566c22SJunchao Zhang   lambda = user->param;
463c5566c22SJunchao Zhang   hx     = 1.0 / (PetscReal)(Mx - 1);
464c5566c22SJunchao Zhang   hy     = 1.0 / (PetscReal)(My - 1);
465c5566c22SJunchao Zhang   sc     = hx * hy * lambda;
466c5566c22SJunchao Zhang   hxdhy  = hx / hy;
467c5566c22SJunchao Zhang   hydhx  = hy / hx;
468c5566c22SJunchao Zhang 
469c5566c22SJunchao Zhang   PetscCall(DMGetLocalVector(da, &localX));
470*48a46eb9SPierre Jolivet   if (B) PetscCall(DMGetLocalVector(da, &localB));
471c5566c22SJunchao Zhang   for (l = 0; l < sweeps; l++) {
472c5566c22SJunchao Zhang     PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX));
473c5566c22SJunchao Zhang     PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX));
474c5566c22SJunchao Zhang     if (B) {
475c5566c22SJunchao Zhang       PetscCall(DMGlobalToLocalBegin(da, B, INSERT_VALUES, localB));
476c5566c22SJunchao Zhang       PetscCall(DMGlobalToLocalEnd(da, B, INSERT_VALUES, localB));
477c5566c22SJunchao Zhang     }
478c5566c22SJunchao Zhang     /*
479c5566c22SJunchao Zhang      Get a pointer to vector data.
480c5566c22SJunchao Zhang      - For default PETSc vectors, VecGetArray() returns a pointer to
481c5566c22SJunchao Zhang      the data array.  Otherwise, the routine is implementation dependent.
482c5566c22SJunchao Zhang      - You MUST call VecRestoreArray() when you no longer need access to
483c5566c22SJunchao Zhang      the array.
484c5566c22SJunchao Zhang      */
485c5566c22SJunchao Zhang     PetscCall(DMDAVecGetArray(da, localX, &x));
486c5566c22SJunchao Zhang     if (B) PetscCall(DMDAVecGetArray(da, localB, &b));
487c5566c22SJunchao Zhang     /*
488c5566c22SJunchao Zhang      Get local grid boundaries (for 2-dimensional DMDA):
489c5566c22SJunchao Zhang      xs, ys   - starting grid indices (no ghost points)
490c5566c22SJunchao Zhang      xm, ym   - widths of local grid (no ghost points)
491c5566c22SJunchao Zhang      */
492c5566c22SJunchao Zhang     PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
493c5566c22SJunchao Zhang 
494c5566c22SJunchao Zhang     for (j = ys; j < ys + ym; j++) {
495c5566c22SJunchao Zhang       for (i = xs; i < xs + xm; i++) {
496c5566c22SJunchao Zhang         if (i == 0 || j == 0 || i == Mx - 1 || j == My - 1) {
497c5566c22SJunchao Zhang           /* boundary conditions are all zero Dirichlet */
498c5566c22SJunchao Zhang           x[j][i] = 0.0;
499c5566c22SJunchao Zhang         } else {
500c5566c22SJunchao Zhang           if (B) bij = b[j][i];
501c5566c22SJunchao Zhang           else bij = 0.;
502c5566c22SJunchao Zhang 
503c5566c22SJunchao Zhang           u  = x[j][i];
504c5566c22SJunchao Zhang           un = x[j - 1][i];
505c5566c22SJunchao Zhang           us = x[j + 1][i];
506c5566c22SJunchao Zhang           ue = x[j][i - 1];
507c5566c22SJunchao Zhang           uw = x[j][i + 1];
508c5566c22SJunchao Zhang 
509c5566c22SJunchao Zhang           for (k = 0; k < its; k++) {
510c5566c22SJunchao Zhang             eu  = PetscExpScalar(u);
511c5566c22SJunchao Zhang             uxx = (2.0 * u - ue - uw) * hydhx;
512c5566c22SJunchao Zhang             uyy = (2.0 * u - un - us) * hxdhy;
513c5566c22SJunchao Zhang             F   = uxx + uyy - sc * eu - bij;
514c5566c22SJunchao Zhang             if (k == 0) F0 = F;
515c5566c22SJunchao Zhang             J = 2.0 * (hydhx + hxdhy) - sc * eu;
516c5566c22SJunchao Zhang             y = F / J;
517c5566c22SJunchao Zhang             u -= y;
518c5566c22SJunchao Zhang             tot_its++;
519c5566c22SJunchao Zhang 
5209371c9d4SSatish Balay             if (atol > PetscAbsReal(PetscRealPart(F)) || rtol * PetscAbsReal(PetscRealPart(F0)) > PetscAbsReal(PetscRealPart(F)) || stol * PetscAbsReal(PetscRealPart(u)) > PetscAbsReal(PetscRealPart(y))) { break; }
521c5566c22SJunchao Zhang           }
522c5566c22SJunchao Zhang           x[j][i] = u;
523c5566c22SJunchao Zhang         }
524c5566c22SJunchao Zhang       }
525c5566c22SJunchao Zhang     }
526c5566c22SJunchao Zhang     /*
527c5566c22SJunchao Zhang      Restore vector
528c5566c22SJunchao Zhang      */
529c5566c22SJunchao Zhang     PetscCall(DMDAVecRestoreArray(da, localX, &x));
530c5566c22SJunchao Zhang     PetscCall(DMLocalToGlobalBegin(da, localX, INSERT_VALUES, X));
531c5566c22SJunchao Zhang     PetscCall(DMLocalToGlobalEnd(da, localX, INSERT_VALUES, X));
532c5566c22SJunchao Zhang   }
533c5566c22SJunchao Zhang   PetscCall(PetscLogFlops(tot_its * (21.0)));
534c5566c22SJunchao Zhang   PetscCall(DMRestoreLocalVector(da, &localX));
535c5566c22SJunchao Zhang   if (B) {
536c5566c22SJunchao Zhang     PetscCall(DMDAVecRestoreArray(da, localB, &b));
537c5566c22SJunchao Zhang     PetscCall(DMRestoreLocalVector(da, &localB));
538c5566c22SJunchao Zhang   }
539c5566c22SJunchao Zhang   PetscFunctionReturn(0);
540c5566c22SJunchao Zhang }
541c5566c22SJunchao Zhang 
5429371c9d4SSatish Balay int main(int argc, char **argv) {
543c5566c22SJunchao Zhang   SNES      snes; /* nonlinear solver */
544c5566c22SJunchao Zhang   Vec       x;    /* solution vector */
545c5566c22SJunchao Zhang   AppCtx    user; /* user-defined work context */
546c5566c22SJunchao Zhang   PetscInt  its;  /* iterations for convergence */
547c5566c22SJunchao Zhang   PetscReal bratu_lambda_max = 6.81;
548c5566c22SJunchao Zhang   PetscReal bratu_lambda_min = 0.;
549c5566c22SJunchao Zhang   PetscInt  MMS              = 1;
550c5566c22SJunchao Zhang   PetscBool flg              = PETSC_FALSE, setMMS;
551c5566c22SJunchao Zhang   DM        da;
552c5566c22SJunchao Zhang   Vec       r = NULL;
553c5566c22SJunchao Zhang   KSP       ksp;
554c5566c22SJunchao Zhang   PetscInt  lits, slits;
555c5566c22SJunchao Zhang   PetscBool useKokkos = PETSC_FALSE;
556c5566c22SJunchao Zhang 
557c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
558c5566c22SJunchao Zhang      Initialize program
559c5566c22SJunchao Zhang      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
560c5566c22SJunchao Zhang 
561327415f7SBarry Smith   PetscFunctionBeginUser;
562c5566c22SJunchao Zhang   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
563c5566c22SJunchao Zhang 
564c5566c22SJunchao Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_kokkos", &useKokkos, NULL));
565c5566c22SJunchao Zhang 
566c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
567c5566c22SJunchao Zhang      Initialize problem parameters
568c5566c22SJunchao Zhang   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
569c5566c22SJunchao Zhang   user.param = 6.0;
570c5566c22SJunchao Zhang   PetscCall(PetscOptionsGetReal(NULL, NULL, "-par", &user.param, NULL));
571c5566c22SJunchao Zhang   PetscCheck(user.param <= bratu_lambda_max && user.param >= bratu_lambda_min, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lambda, %g, is out of range, [%g, %g]", (double)user.param, (double)bratu_lambda_min, (double)bratu_lambda_max);
572c5566c22SJunchao Zhang   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mms", &MMS, &setMMS));
573c5566c22SJunchao Zhang   if (MMS == 3) {
574c5566c22SJunchao Zhang     PetscInt mPar = 2, nPar = 1;
575c5566c22SJunchao Zhang     PetscCall(PetscOptionsGetInt(NULL, NULL, "-m_par", &mPar, NULL));
576c5566c22SJunchao Zhang     PetscCall(PetscOptionsGetInt(NULL, NULL, "-n_par", &nPar, NULL));
577c5566c22SJunchao Zhang     user.m = PetscPowInt(2, mPar);
578c5566c22SJunchao Zhang     user.n = PetscPowInt(2, nPar);
579c5566c22SJunchao Zhang   }
580c5566c22SJunchao Zhang 
581c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
582c5566c22SJunchao Zhang      Create nonlinear solver context
583c5566c22SJunchao Zhang      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
584c5566c22SJunchao Zhang   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
585c5566c22SJunchao Zhang   PetscCall(SNESSetCountersReset(snes, PETSC_FALSE));
586c5566c22SJunchao Zhang   PetscCall(SNESSetNGS(snes, NonlinearGS, NULL));
587c5566c22SJunchao Zhang 
588c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
589c5566c22SJunchao Zhang      Create distributed array (DMDA) to manage parallel grid and vectors
590c5566c22SJunchao Zhang   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
591c5566c22SJunchao Zhang   PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_STAR, 4, 4, PETSC_DECIDE, PETSC_DECIDE, 1, 1, NULL, NULL, &da));
592c5566c22SJunchao Zhang   PetscCall(DMSetFromOptions(da));
593c5566c22SJunchao Zhang   PetscCall(DMSetUp(da));
594c5566c22SJunchao Zhang   PetscCall(DMDASetUniformCoordinates(da, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0));
595c5566c22SJunchao Zhang   PetscCall(DMSetApplicationContext(da, &user));
596c5566c22SJunchao Zhang   PetscCall(SNESSetDM(snes, da));
597c5566c22SJunchao Zhang   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
598c5566c22SJunchao Zhang      Extract global vectors from DMDA; then duplicate for remaining
599c5566c22SJunchao Zhang      vectors that are the same types
600c5566c22SJunchao Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
601c5566c22SJunchao Zhang   PetscCall(DMCreateGlobalVector(da, &x));
602c5566c22SJunchao Zhang 
603c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
604c5566c22SJunchao Zhang      Set local function evaluation routine
605c5566c22SJunchao Zhang   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
606c5566c22SJunchao Zhang   switch (MMS) {
6079371c9d4SSatish Balay   case 0:
6089371c9d4SSatish Balay     user.mms_solution = ZeroBCSolution;
6099371c9d4SSatish Balay     user.mms_forcing  = NULL;
6109371c9d4SSatish Balay     break;
6119371c9d4SSatish Balay   case 1:
6129371c9d4SSatish Balay     user.mms_solution = MMSSolution1;
6139371c9d4SSatish Balay     user.mms_forcing  = MMSForcing1;
6149371c9d4SSatish Balay     break;
6159371c9d4SSatish Balay   case 2:
6169371c9d4SSatish Balay     user.mms_solution = MMSSolution2;
6179371c9d4SSatish Balay     user.mms_forcing  = MMSForcing2;
6189371c9d4SSatish Balay     break;
6199371c9d4SSatish Balay   case 3:
6209371c9d4SSatish Balay     user.mms_solution = MMSSolution3;
6219371c9d4SSatish Balay     user.mms_forcing  = MMSForcing3;
6229371c9d4SSatish Balay     break;
6239371c9d4SSatish Balay   case 4:
6249371c9d4SSatish Balay     user.mms_solution = MMSSolution4;
6259371c9d4SSatish Balay     user.mms_forcing  = MMSForcing4;
6269371c9d4SSatish Balay     break;
627c5566c22SJunchao Zhang   default: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_USER, "Unknown MMS type %" PetscInt_FMT, MMS);
628c5566c22SJunchao Zhang   }
629c5566c22SJunchao Zhang 
630c5566c22SJunchao Zhang   if (useKokkos) {
631c5566c22SJunchao Zhang     PetscCheck(MMS == 1, PETSC_COMM_WORLD, PETSC_ERR_USER, "FormFunctionLocalVec_Kokkos only works with MMS 1");
632c5566c22SJunchao Zhang     PetscCall(DMDASNESSetFunctionLocalVec(da, INSERT_VALUES, (DMDASNESFunctionVec)FormFunctionLocalVec, &user));
633c5566c22SJunchao Zhang   } else {
634c5566c22SJunchao Zhang     PetscCall(DMDASNESSetFunctionLocal(da, INSERT_VALUES, (DMDASNESFunction)FormFunctionLocal, &user));
635c5566c22SJunchao Zhang   }
636c5566c22SJunchao Zhang 
637c5566c22SJunchao Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-fd", &flg, NULL));
638c5566c22SJunchao Zhang   if (!flg) {
639c5566c22SJunchao Zhang     if (useKokkos) PetscCall(DMDASNESSetJacobianLocalVec(da, (DMDASNESJacobianVec)FormJacobianLocalVec, &user));
640c5566c22SJunchao Zhang     else PetscCall(DMDASNESSetJacobianLocal(da, (DMDASNESJacobian)FormJacobianLocal, &user));
641c5566c22SJunchao Zhang   }
642c5566c22SJunchao Zhang 
643c5566c22SJunchao Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-obj", &flg, NULL));
644c5566c22SJunchao Zhang   if (flg) {
645c5566c22SJunchao Zhang     if (useKokkos) PetscCall(DMDASNESSetObjectiveLocalVec(da, (DMDASNESObjectiveVec)FormObjectiveLocalVec, &user));
646c5566c22SJunchao Zhang     else PetscCall(DMDASNESSetObjectiveLocal(da, (DMDASNESObjective)FormObjectiveLocal, &user));
647c5566c22SJunchao Zhang   }
648c5566c22SJunchao Zhang 
649c5566c22SJunchao Zhang   if (PetscDefined(HAVE_MATLAB_ENGINE)) {
650c5566c22SJunchao Zhang     PetscBool matlab_function = PETSC_FALSE;
651c5566c22SJunchao Zhang     PetscCall(PetscOptionsGetBool(NULL, NULL, "-matlab_function", &matlab_function, 0));
652c5566c22SJunchao Zhang     if (matlab_function) {
653c5566c22SJunchao Zhang       PetscCall(VecDuplicate(x, &r));
654c5566c22SJunchao Zhang       PetscCall(SNESSetFunction(snes, r, FormFunctionMatlab, &user));
655c5566c22SJunchao Zhang     }
656c5566c22SJunchao Zhang   }
657c5566c22SJunchao Zhang 
658c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
659c5566c22SJunchao Zhang      Customize nonlinear solver; set runtime options
660c5566c22SJunchao Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
661c5566c22SJunchao Zhang   PetscCall(SNESSetFromOptions(snes));
662c5566c22SJunchao Zhang 
663c5566c22SJunchao Zhang   PetscCall(FormInitialGuess(da, &user, x));
664c5566c22SJunchao Zhang 
665c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
666c5566c22SJunchao Zhang      Solve nonlinear system
667c5566c22SJunchao Zhang      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
668c5566c22SJunchao Zhang   PetscCall(SNESSolve(snes, NULL, x));
669c5566c22SJunchao Zhang   PetscCall(SNESGetIterationNumber(snes, &its));
670c5566c22SJunchao Zhang 
671c5566c22SJunchao Zhang   PetscCall(SNESGetLinearSolveIterations(snes, &slits));
672c5566c22SJunchao Zhang   PetscCall(SNESGetKSP(snes, &ksp));
673c5566c22SJunchao Zhang   PetscCall(KSPGetTotalIterations(ksp, &lits));
674c5566c22SJunchao Zhang   PetscCheck(lits == slits, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Number of total linear iterations reported by SNES %" PetscInt_FMT " does not match reported by KSP %" PetscInt_FMT, slits, lits);
675c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
676c5566c22SJunchao Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
677c5566c22SJunchao Zhang 
678c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
679c5566c22SJunchao Zhang      If using MMS, check the l_2 error
680c5566c22SJunchao Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
681c5566c22SJunchao Zhang   if (setMMS) {
682c5566c22SJunchao Zhang     Vec       e;
683c5566c22SJunchao Zhang     PetscReal errorl2, errorinf;
684c5566c22SJunchao Zhang     PetscInt  N;
685c5566c22SJunchao Zhang 
686c5566c22SJunchao Zhang     PetscCall(VecDuplicate(x, &e));
687c5566c22SJunchao Zhang     PetscCall(PetscObjectViewFromOptions((PetscObject)x, NULL, "-sol_view"));
688c5566c22SJunchao Zhang     PetscCall(FormExactSolution(da, &user, e));
689c5566c22SJunchao Zhang     PetscCall(PetscObjectViewFromOptions((PetscObject)e, NULL, "-exact_view"));
690c5566c22SJunchao Zhang     PetscCall(VecAXPY(e, -1.0, x));
691c5566c22SJunchao Zhang     PetscCall(PetscObjectViewFromOptions((PetscObject)e, NULL, "-error_view"));
692c5566c22SJunchao Zhang     PetscCall(VecNorm(e, NORM_2, &errorl2));
693c5566c22SJunchao Zhang     PetscCall(VecNorm(e, NORM_INFINITY, &errorinf));
694c5566c22SJunchao Zhang     PetscCall(VecGetSize(e, &N));
695c5566c22SJunchao Zhang     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "N: %" PetscInt_FMT " error L2 %g inf %g\n", N, (double)(errorl2 / PetscSqrtReal((PetscReal)N)), (double)errorinf));
696c5566c22SJunchao Zhang     PetscCall(VecDestroy(&e));
697c5566c22SJunchao Zhang     PetscCall(PetscLogEventSetDof(SNES_Solve, 0, N));
698c5566c22SJunchao Zhang     PetscCall(PetscLogEventSetError(SNES_Solve, 0, errorl2 / PetscSqrtReal(N)));
699c5566c22SJunchao Zhang   }
700c5566c22SJunchao Zhang 
701c5566c22SJunchao Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
702c5566c22SJunchao Zhang      Free work space.  All PETSc objects should be destroyed when they
703c5566c22SJunchao Zhang      are no longer needed.
704c5566c22SJunchao Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
705c5566c22SJunchao Zhang   PetscCall(VecDestroy(&r));
706c5566c22SJunchao Zhang   PetscCall(VecDestroy(&x));
707c5566c22SJunchao Zhang   PetscCall(SNESDestroy(&snes));
708c5566c22SJunchao Zhang   PetscCall(DMDestroy(&da));
709c5566c22SJunchao Zhang   PetscCall(PetscFinalize());
710c5566c22SJunchao Zhang   return 0;
711c5566c22SJunchao Zhang }
712c5566c22SJunchao Zhang 
713c5566c22SJunchao Zhang /*TEST
714c5566c22SJunchao Zhang   build:
715c5566c22SJunchao Zhang     requires: kokkos_kernels
716c5566c22SJunchao Zhang     depends: ex55k.kokkos.cxx
717c5566c22SJunchao Zhang 
718c5566c22SJunchao Zhang   testset:
719c5566c22SJunchao Zhang     output_file: output/ex55_asm_0.out
720c5566c22SJunchao Zhang     requires: !single
721c5566c22SJunchao Zhang     args: -mms 1 -par 0.0 -snes_monitor_short -snes_converged_reason -ksp_rtol 1.0e-9 -ksp_monitor_short -ksp_type richardson -pc_type asm -pc_asm_blocks 2 -pc_asm_overlap 0 -pc_asm_local_type additive -sub_pc_type lu
722c5566c22SJunchao Zhang     filter: grep -v "type"
723c5566c22SJunchao Zhang 
724c5566c22SJunchao Zhang     test:
725c5566c22SJunchao Zhang       suffix: asm_0
726c5566c22SJunchao Zhang     test:
727c5566c22SJunchao Zhang       suffix: asm_0_kok
728c5566c22SJunchao Zhang       args: -use_kokkos 1 -dm_mat_type aijkokkos -dm_vec_type kokkos
729c5566c22SJunchao Zhang 
730c5566c22SJunchao Zhang TEST*/
731