xref: /petsc/src/ts/tutorials/ex17.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
1c4762a1bSJed Brown static const char help[] = "Time-dependent PDE in 1d. Simplified from ex15.c for illustrating how to solve DAEs. \n";
2c4762a1bSJed Brown /*
3c4762a1bSJed Brown    u_t = uxx
4c4762a1bSJed Brown    0 < x < 1;
5c4762a1bSJed Brown    At t=0: u(x) = exp(c*r*r*r), if r=PetscSqrtReal((x-.5)*(x-.5)) < .125
6c4762a1bSJed Brown            u(x) = 0.0           if r >= .125
7c4762a1bSJed Brown 
8c4762a1bSJed Brown    Boundary conditions:
9c4762a1bSJed Brown    Dirichlet BC:
10c4762a1bSJed Brown    At x=0, x=1, u = 0.0
11c4762a1bSJed Brown 
12c4762a1bSJed Brown    Neumann BC:
13c4762a1bSJed Brown    At x=0, x=1: du(x,t)/dx = 0
14c4762a1bSJed Brown 
15c4762a1bSJed Brown    mpiexec -n 2 ./ex17 -da_grid_x 40 -ts_max_steps 2 -snes_monitor -ksp_monitor
16c4762a1bSJed Brown          ./ex17 -da_grid_x 40 -monitor_solution
17c4762a1bSJed Brown          ./ex17 -da_grid_x 100  -ts_type theta -ts_theta_theta 0.5 # Midpoint is not L-stable
18c4762a1bSJed Brown          ./ex17 -jac_type fd_coloring  -da_grid_x 500 -boundary 1
19c4762a1bSJed Brown          ./ex17 -da_grid_x 100  -ts_type gl -ts_adapt_type none -ts_max_steps 2
20c4762a1bSJed Brown */
21c4762a1bSJed Brown 
22c4762a1bSJed Brown #include <petscdm.h>
23c4762a1bSJed Brown #include <petscdmda.h>
24c4762a1bSJed Brown #include <petscts.h>
25c4762a1bSJed Brown 
26*9371c9d4SSatish Balay typedef enum {
27*9371c9d4SSatish Balay   JACOBIAN_ANALYTIC,
28*9371c9d4SSatish Balay   JACOBIAN_FD_COLORING,
29*9371c9d4SSatish Balay   JACOBIAN_FD_FULL
30*9371c9d4SSatish Balay } JacobianType;
31c4762a1bSJed Brown static const char *const JacobianTypes[] = {"analytic", "fd_coloring", "fd_full", "JacobianType", "fd_", 0};
32c4762a1bSJed Brown 
33c4762a1bSJed Brown /*
34c4762a1bSJed Brown    User-defined data structures and routines
35c4762a1bSJed Brown */
36c4762a1bSJed Brown typedef struct {
37c4762a1bSJed Brown   PetscReal c;
38c4762a1bSJed Brown   PetscInt  boundary; /* Type of boundary condition */
39c4762a1bSJed Brown   PetscBool viewJacobian;
40c4762a1bSJed Brown } AppCtx;
41c4762a1bSJed Brown 
42c4762a1bSJed Brown static PetscErrorCode FormIFunction(TS, PetscReal, Vec, Vec, Vec, void *);
43c4762a1bSJed Brown static PetscErrorCode FormIJacobian(TS, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *);
44c4762a1bSJed Brown static PetscErrorCode FormInitialSolution(TS, Vec, void *);
45c4762a1bSJed Brown 
46*9371c9d4SSatish Balay int main(int argc, char **argv) {
47c4762a1bSJed Brown   TS           ts; /* nonlinear solver */
48c4762a1bSJed Brown   Vec          u;  /* solution, residual vectors */
49c4762a1bSJed Brown   Mat          J;  /* Jacobian matrix */
50c4762a1bSJed Brown   PetscInt     nsteps;
51c4762a1bSJed Brown   PetscReal    vmin, vmax, norm;
52c4762a1bSJed Brown   DM           da;
53c4762a1bSJed Brown   PetscReal    ftime, dt;
54c4762a1bSJed Brown   AppCtx       user; /* user-defined work context */
55c4762a1bSJed Brown   JacobianType jacType;
56c4762a1bSJed Brown 
57327415f7SBarry Smith   PetscFunctionBeginUser;
589566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
59c4762a1bSJed Brown 
60c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
61c4762a1bSJed Brown      Create distributed array (DMDA) to manage parallel grid and vectors
62c4762a1bSJed Brown   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
639566063dSJacob Faibussowitsch   PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, 11, 1, 1, NULL, &da));
649566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(da));
659566063dSJacob Faibussowitsch   PetscCall(DMSetUp(da));
66c4762a1bSJed Brown 
67c4762a1bSJed Brown   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68c4762a1bSJed Brown      Extract global vectors from DMDA;
69c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
709566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(da, &u));
71c4762a1bSJed Brown 
72c4762a1bSJed Brown   /* Initialize user application context */
73c4762a1bSJed Brown   user.c            = -30.0;
74c4762a1bSJed Brown   user.boundary     = 0; /* 0: Dirichlet BC; 1: Neumann BC */
75c4762a1bSJed Brown   user.viewJacobian = PETSC_FALSE;
76c4762a1bSJed Brown 
779566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-boundary", &user.boundary, NULL));
789566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-viewJacobian", &user.viewJacobian));
79c4762a1bSJed Brown 
80c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81c4762a1bSJed Brown      Create timestepping solver context
82c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
839566063dSJacob Faibussowitsch   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
849566063dSJacob Faibussowitsch   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
859566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSTHETA));
869566063dSJacob Faibussowitsch   PetscCall(TSThetaSetTheta(ts, 1.0)); /* Make the Theta method behave like backward Euler */
879566063dSJacob Faibussowitsch   PetscCall(TSSetIFunction(ts, NULL, FormIFunction, &user));
88c4762a1bSJed Brown 
899566063dSJacob Faibussowitsch   PetscCall(DMSetMatType(da, MATAIJ));
909566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(da, &J));
91c4762a1bSJed Brown   jacType = JACOBIAN_ANALYTIC; /* use user-provide Jacobian */
92c4762a1bSJed Brown 
939566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, da)); /* Use TSGetDM() to access. Setting here allows easy use of geometric multigrid. */
94c4762a1bSJed Brown 
95c4762a1bSJed Brown   ftime = 1.0;
969566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, ftime));
979566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
98c4762a1bSJed Brown 
99c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100c4762a1bSJed Brown      Set initial conditions
101c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1029566063dSJacob Faibussowitsch   PetscCall(FormInitialSolution(ts, u, &user));
1039566063dSJacob Faibussowitsch   PetscCall(TSSetSolution(ts, u));
104c4762a1bSJed Brown   dt = .01;
1059566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, dt));
106c4762a1bSJed Brown 
107c4762a1bSJed Brown   /* Use slow fd Jacobian or fast fd Jacobian with colorings.
108c4762a1bSJed Brown      Note: this requirs snes which is not created until TSSetUp()/TSSetFromOptions() is called */
109d0609cedSBarry Smith   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "Options for Jacobian evaluation", NULL);
1109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-jac_type", "Type of Jacobian", "", JacobianTypes, (PetscEnum)jacType, (PetscEnum *)&jacType, 0));
111d0609cedSBarry Smith   PetscOptionsEnd();
112c4762a1bSJed Brown   if (jacType == JACOBIAN_ANALYTIC) {
1139566063dSJacob Faibussowitsch     PetscCall(TSSetIJacobian(ts, J, J, FormIJacobian, &user));
114c4762a1bSJed Brown   } else if (jacType == JACOBIAN_FD_COLORING) {
115c4762a1bSJed Brown     SNES snes;
1169566063dSJacob Faibussowitsch     PetscCall(TSGetSNES(ts, &snes));
1179566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, J, J, SNESComputeJacobianDefaultColor, 0));
118c4762a1bSJed Brown   } else if (jacType == JACOBIAN_FD_FULL) {
119c4762a1bSJed Brown     SNES snes;
1209566063dSJacob Faibussowitsch     PetscCall(TSGetSNES(ts, &snes));
1219566063dSJacob Faibussowitsch     PetscCall(SNESSetJacobian(snes, J, J, SNESComputeJacobianDefault, &user));
122c4762a1bSJed Brown   }
123c4762a1bSJed Brown 
124c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125c4762a1bSJed Brown      Set runtime options
126c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1279566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts));
128c4762a1bSJed Brown 
129c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
130c4762a1bSJed Brown      Integrate ODE system
131c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1329566063dSJacob Faibussowitsch   PetscCall(TSSolve(ts, u));
133c4762a1bSJed Brown 
134c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
135c4762a1bSJed Brown    Compute diagnostics of the solution
136c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1379566063dSJacob Faibussowitsch   PetscCall(VecNorm(u, NORM_1, &norm));
1389566063dSJacob Faibussowitsch   PetscCall(VecMax(u, NULL, &vmax));
1399566063dSJacob Faibussowitsch   PetscCall(VecMin(u, NULL, &vmin));
1409566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &nsteps));
1419566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &ftime));
14263a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "timestep %" PetscInt_FMT ": time %g, solution norm %g, max %g, min %g\n", nsteps, (double)ftime, (double)norm, (double)vmax, (double)vmin));
143c4762a1bSJed Brown 
144c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145c4762a1bSJed Brown      Free work space.
146c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1479566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
1489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&u));
1499566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
1509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&da));
1519566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
152b122ec5aSJacob Faibussowitsch   return 0;
153c4762a1bSJed Brown }
154c4762a1bSJed Brown /* ------------------------------------------------------------------- */
155*9371c9d4SSatish Balay static PetscErrorCode FormIFunction(TS ts, PetscReal ftime, Vec U, Vec Udot, Vec F, void *ptr) {
156c4762a1bSJed Brown   AppCtx      *user = (AppCtx *)ptr;
157c4762a1bSJed Brown   DM           da;
158c4762a1bSJed Brown   PetscInt     i, Mx, xs, xm;
159c4762a1bSJed Brown   PetscReal    hx, sx;
160c4762a1bSJed Brown   PetscScalar *u, *udot, *f;
161c4762a1bSJed Brown   Vec          localU;
162c4762a1bSJed Brown 
163c4762a1bSJed Brown   PetscFunctionBeginUser;
1649566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
1659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &localU));
1669566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &Mx, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
167c4762a1bSJed Brown 
168*9371c9d4SSatish Balay   hx = 1.0 / (PetscReal)(Mx - 1);
169*9371c9d4SSatish Balay   sx = 1.0 / (hx * hx);
170c4762a1bSJed Brown 
171c4762a1bSJed Brown   /*
172c4762a1bSJed Brown      Scatter ghost points to local vector,using the 2-step process
173c4762a1bSJed Brown         DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
174c4762a1bSJed Brown      By placing code between these two statements, computations can be
175c4762a1bSJed Brown      done while messages are in transition.
176c4762a1bSJed Brown   */
1779566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, U, INSERT_VALUES, localU));
1789566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, U, INSERT_VALUES, localU));
179c4762a1bSJed Brown 
180c4762a1bSJed Brown   /* Get pointers to vector data */
1819566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, localU, &u));
1829566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, Udot, &udot));
1839566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, F, &f));
184c4762a1bSJed Brown 
185c4762a1bSJed Brown   /* Get local grid boundaries */
1869566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, NULL, NULL, &xm, NULL, NULL));
187c4762a1bSJed Brown 
188c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
189c4762a1bSJed Brown   for (i = xs; i < xs + xm; i++) {
190c4762a1bSJed Brown     if (user->boundary == 0) {                /* Dirichlet BC */
191c4762a1bSJed Brown       if (i == 0 || i == Mx - 1) f[i] = u[i]; /* F = U */
192c4762a1bSJed Brown       else f[i] = udot[i] + (2. * u[i] - u[i - 1] - u[i + 1]) * sx;
193c4762a1bSJed Brown     } else { /* Neumann BC */
194c4762a1bSJed Brown       if (i == 0) f[i] = u[0] - u[1];
195c4762a1bSJed Brown       else if (i == Mx - 1) f[i] = u[i] - u[i - 1];
196c4762a1bSJed Brown       else f[i] = udot[i] + (2. * u[i] - u[i - 1] - u[i + 1]) * sx;
197c4762a1bSJed Brown     }
198c4762a1bSJed Brown   }
199c4762a1bSJed Brown 
200c4762a1bSJed Brown   /* Restore vectors */
2019566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, localU, &u));
2029566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, Udot, &udot));
2039566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, F, &f));
2049566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &localU));
205c4762a1bSJed Brown   PetscFunctionReturn(0);
206c4762a1bSJed Brown }
207c4762a1bSJed Brown 
208c4762a1bSJed Brown /* --------------------------------------------------------------------- */
209c4762a1bSJed Brown /*
210c4762a1bSJed Brown   IJacobian - Compute IJacobian = dF/dU + a dF/dUdot
211c4762a1bSJed Brown */
212*9371c9d4SSatish Balay PetscErrorCode FormIJacobian(TS ts, PetscReal t, Vec U, Vec Udot, PetscReal a, Mat J, Mat Jpre, void *ctx) {
213c4762a1bSJed Brown   PetscInt    i, rstart, rend, Mx;
214c4762a1bSJed Brown   PetscReal   hx, sx;
215c4762a1bSJed Brown   AppCtx     *user = (AppCtx *)ctx;
216c4762a1bSJed Brown   DM          da;
217c4762a1bSJed Brown   MatStencil  col[3], row;
218c4762a1bSJed Brown   PetscInt    nc;
219c4762a1bSJed Brown   PetscScalar vals[3];
220c4762a1bSJed Brown 
221c4762a1bSJed Brown   PetscFunctionBeginUser;
2229566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
2239566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Jpre, &rstart, &rend));
2249566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &Mx, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
225*9371c9d4SSatish Balay   hx = 1.0 / (PetscReal)(Mx - 1);
226*9371c9d4SSatish Balay   sx = 1.0 / (hx * hx);
227c4762a1bSJed Brown   for (i = rstart; i < rend; i++) {
228c4762a1bSJed Brown     nc    = 0;
229c4762a1bSJed Brown     row.i = i;
230c4762a1bSJed Brown     if (user->boundary == 0 && (i == 0 || i == Mx - 1)) {
231*9371c9d4SSatish Balay       col[nc].i  = i;
232*9371c9d4SSatish Balay       vals[nc++] = 1.0;
233c4762a1bSJed Brown     } else if (user->boundary > 0 && i == 0) { /* Left Neumann */
234*9371c9d4SSatish Balay       col[nc].i  = i;
235*9371c9d4SSatish Balay       vals[nc++] = 1.0;
236*9371c9d4SSatish Balay       col[nc].i  = i + 1;
237*9371c9d4SSatish Balay       vals[nc++] = -1.0;
238c4762a1bSJed Brown     } else if (user->boundary > 0 && i == Mx - 1) { /* Right Neumann */
239*9371c9d4SSatish Balay       col[nc].i  = i - 1;
240*9371c9d4SSatish Balay       vals[nc++] = -1.0;
241*9371c9d4SSatish Balay       col[nc].i  = i;
242*9371c9d4SSatish Balay       vals[nc++] = 1.0;
243c4762a1bSJed Brown     } else { /* Interior */
244*9371c9d4SSatish Balay       col[nc].i  = i - 1;
245*9371c9d4SSatish Balay       vals[nc++] = -1.0 * sx;
246*9371c9d4SSatish Balay       col[nc].i  = i;
247*9371c9d4SSatish Balay       vals[nc++] = 2.0 * sx + a;
248*9371c9d4SSatish Balay       col[nc].i  = i + 1;
249*9371c9d4SSatish Balay       vals[nc++] = -1.0 * sx;
250c4762a1bSJed Brown     }
2519566063dSJacob Faibussowitsch     PetscCall(MatSetValuesStencil(Jpre, 1, &row, nc, col, vals, INSERT_VALUES));
252c4762a1bSJed Brown   }
253c4762a1bSJed Brown 
2549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Jpre, MAT_FINAL_ASSEMBLY));
2559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Jpre, MAT_FINAL_ASSEMBLY));
256c4762a1bSJed Brown   if (J != Jpre) {
2579566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2589566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
259c4762a1bSJed Brown   }
260c4762a1bSJed Brown   if (user->viewJacobian) {
2619566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Jpre:\n"));
2629566063dSJacob Faibussowitsch     PetscCall(MatView(Jpre, PETSC_VIEWER_STDOUT_WORLD));
263c4762a1bSJed Brown   }
264c4762a1bSJed Brown   PetscFunctionReturn(0);
265c4762a1bSJed Brown }
266c4762a1bSJed Brown 
267c4762a1bSJed Brown /* ------------------------------------------------------------------- */
268*9371c9d4SSatish Balay PetscErrorCode FormInitialSolution(TS ts, Vec U, void *ptr) {
269c4762a1bSJed Brown   AppCtx      *user = (AppCtx *)ptr;
270c4762a1bSJed Brown   PetscReal    c    = user->c;
271c4762a1bSJed Brown   DM           da;
272c4762a1bSJed Brown   PetscInt     i, xs, xm, Mx;
273c4762a1bSJed Brown   PetscScalar *u;
274c4762a1bSJed Brown   PetscReal    hx, x, r;
275c4762a1bSJed Brown 
276c4762a1bSJed Brown   PetscFunctionBeginUser;
2779566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
2789566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &Mx, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
279c4762a1bSJed Brown 
280c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(Mx - 1);
281c4762a1bSJed Brown 
282c4762a1bSJed Brown   /* Get pointers to vector data */
2839566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, U, &u));
284c4762a1bSJed Brown 
285c4762a1bSJed Brown   /* Get local grid boundaries */
2869566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, NULL, NULL, &xm, NULL, NULL));
287c4762a1bSJed Brown 
288c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
289c4762a1bSJed Brown   for (i = xs; i < xs + xm; i++) {
290c4762a1bSJed Brown     x = i * hx;
291c4762a1bSJed Brown     r = PetscSqrtReal((x - .5) * (x - .5));
292c4762a1bSJed Brown     if (r < .125) u[i] = PetscExpReal(c * r * r * r);
293c4762a1bSJed Brown     else u[i] = 0.0;
294c4762a1bSJed Brown   }
295c4762a1bSJed Brown 
296c4762a1bSJed Brown   /* Restore vectors */
2979566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, U, &u));
298c4762a1bSJed Brown   PetscFunctionReturn(0);
299c4762a1bSJed Brown }
300c4762a1bSJed Brown 
301c4762a1bSJed Brown /*TEST
302c4762a1bSJed Brown 
303c4762a1bSJed Brown     test:
304c4762a1bSJed Brown       requires: !single
305c4762a1bSJed Brown       args: -da_grid_x 40 -ts_max_steps 2 -snes_monitor_short -ksp_monitor_short -ts_monitor
306c4762a1bSJed Brown 
307c4762a1bSJed Brown     test:
308c4762a1bSJed Brown       suffix: 2
309c4762a1bSJed Brown       requires: !single
310c4762a1bSJed Brown       args: -da_grid_x 100 -ts_type theta -ts_theta_theta 0.5
311c4762a1bSJed Brown 
312c4762a1bSJed Brown TEST*/
313