xref: /petsc/src/ts/tests/ex25.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
1c4762a1bSJed Brown static const char help[] = "Call PetscInitialize multiple times.\n";
2c4762a1bSJed Brown /*
3c4762a1bSJed Brown    This example is based on the Brusselator tutorial of the same name, but tests multiple calls to PetscInitialize().
4c4762a1bSJed Brown    This is a bad "convergence study" because it only compares min and max values of the solution rather than comparing
5c4762a1bSJed Brown    norms of the errors.  For convergence studies, we recommend invoking PetscInitialize() only once and comparing norms
6c4762a1bSJed Brown    of errors (perhaps estimated using an accurate reference solution).
7c4762a1bSJed Brown 
8c4762a1bSJed Brown    Time-dependent Brusselator reaction-diffusion PDE in 1d. Demonstrates IMEX methods and multiple solves.
9c4762a1bSJed Brown 
10c4762a1bSJed Brown    u_t - alpha u_xx = A + u^2 v - (B+1) u
11c4762a1bSJed Brown    v_t - alpha v_xx = B u - u^2 v
12c4762a1bSJed Brown    0 < x < 1;
13c4762a1bSJed Brown    A = 1, B = 3, alpha = 1/10
14c4762a1bSJed Brown 
15c4762a1bSJed Brown    Initial conditions:
16c4762a1bSJed Brown    u(x,0) = 1 + sin(2 pi x)
17c4762a1bSJed Brown    v(x,0) = 3
18c4762a1bSJed Brown 
19c4762a1bSJed Brown    Boundary conditions:
20c4762a1bSJed Brown    u(0,t) = u(1,t) = 1
21c4762a1bSJed Brown    v(0,t) = v(1,t) = 3
22c4762a1bSJed Brown */
23c4762a1bSJed Brown 
24c4762a1bSJed Brown #include <petscdm.h>
25c4762a1bSJed Brown #include <petscdmda.h>
26c4762a1bSJed Brown #include <petscts.h>
27c4762a1bSJed Brown 
28c4762a1bSJed Brown typedef struct {
29c4762a1bSJed Brown   PetscScalar u, v;
30c4762a1bSJed Brown } Field;
31c4762a1bSJed Brown 
32c4762a1bSJed Brown typedef struct _User *User;
33c4762a1bSJed Brown struct _User {
34c4762a1bSJed Brown   PetscReal A, B;          /* Reaction coefficients */
35c4762a1bSJed Brown   PetscReal alpha;         /* Diffusion coefficient */
36c4762a1bSJed Brown   PetscReal uleft, uright; /* Dirichlet boundary conditions */
37c4762a1bSJed Brown   PetscReal vleft, vright; /* Dirichlet boundary conditions */
38c4762a1bSJed Brown };
39c4762a1bSJed Brown 
40c4762a1bSJed Brown static PetscErrorCode FormRHSFunction(TS, PetscReal, Vec, Vec, void *);
41c4762a1bSJed Brown static PetscErrorCode FormIFunction(TS, PetscReal, Vec, Vec, Vec, void *);
42c4762a1bSJed Brown static PetscErrorCode FormIJacobian(TS, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *);
43c4762a1bSJed Brown static PetscErrorCode FormInitialSolution(TS, Vec, void *);
443ba16761SJacob Faibussowitsch static PetscErrorCode Brusselator(int, char **, PetscInt);
45c4762a1bSJed Brown 
main(int argc,char ** argv)46d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
47d71ae5a4SJacob Faibussowitsch {
483ba16761SJacob Faibussowitsch   int ierr = MPI_Init(&argc, &argv);
499371c9d4SSatish Balay   if (ierr) return ierr;
503ba16761SJacob Faibussowitsch   for (PetscInt cycle = 0; cycle < 4; cycle++) {
513ba16761SJacob Faibussowitsch     if (Brusselator(argc, argv, cycle)) return 1;
52c4762a1bSJed Brown   }
533ba16761SJacob Faibussowitsch   return MPI_Finalize();
54c4762a1bSJed Brown }
55c4762a1bSJed Brown 
Brusselator(int argc,char ** argv,PetscInt cycle)56d71ae5a4SJacob Faibussowitsch PetscErrorCode Brusselator(int argc, char **argv, PetscInt cycle)
57d71ae5a4SJacob Faibussowitsch {
58c4762a1bSJed Brown   TS                ts; /* nonlinear solver */
59c4762a1bSJed Brown   Vec               X;  /* solution, residual vectors */
60c4762a1bSJed Brown   Mat               J;  /* Jacobian matrix */
61c4762a1bSJed Brown   PetscInt          steps, mx;
62c4762a1bSJed Brown   DM                da;
63c4762a1bSJed Brown   PetscReal         ftime, hx, dt, xmax, xmin;
64c4762a1bSJed Brown   struct _User      user; /* user-defined work context */
65c4762a1bSJed Brown   TSConvergedReason reason;
66c4762a1bSJed Brown 
67327415f7SBarry Smith   PetscFunctionBeginUser;
68c8025a54SPierre Jolivet   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
69c4762a1bSJed Brown 
70c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71c4762a1bSJed Brown      Create distributed array (DMDA) to manage parallel grid and vectors
72c4762a1bSJed Brown   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
739566063dSJacob Faibussowitsch   PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, 11, 2, 2, NULL, &da));
749566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(da));
759566063dSJacob Faibussowitsch   PetscCall(DMSetUp(da));
76c4762a1bSJed Brown 
77c4762a1bSJed Brown   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78c4762a1bSJed Brown      Extract global vectors from DMDA;
79c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
809566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(da, &X));
81c4762a1bSJed Brown 
82c4762a1bSJed Brown   /* Initialize user application context */
83d0609cedSBarry Smith   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "Advection-reaction options", "");
84c4762a1bSJed Brown   {
85c4762a1bSJed Brown     user.A      = 1;
86c4762a1bSJed Brown     user.B      = 3;
87c4762a1bSJed Brown     user.alpha  = 0.1;
88c4762a1bSJed Brown     user.uleft  = 1;
89c4762a1bSJed Brown     user.uright = 1;
90c4762a1bSJed Brown     user.vleft  = 3;
91c4762a1bSJed Brown     user.vright = 3;
929566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-A", "Reaction rate", "", user.A, &user.A, NULL));
939566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-B", "Reaction rate", "", user.B, &user.B, NULL));
949566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-alpha", "Diffusion coefficient", "", user.alpha, &user.alpha, NULL));
959566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-uleft", "Dirichlet boundary condition", "", user.uleft, &user.uleft, NULL));
969566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-uright", "Dirichlet boundary condition", "", user.uright, &user.uright, NULL));
979566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-vleft", "Dirichlet boundary condition", "", user.vleft, &user.vleft, NULL));
989566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-vright", "Dirichlet boundary condition", "", user.vright, &user.vright, NULL));
99c4762a1bSJed Brown   }
100d0609cedSBarry Smith   PetscOptionsEnd();
101c4762a1bSJed Brown 
102c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103c4762a1bSJed Brown      Create timestepping solver context
104c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1059566063dSJacob Faibussowitsch   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
1069566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, da));
1079566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSARKIMEX));
1089566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts, NULL, FormRHSFunction, &user));
1099566063dSJacob Faibussowitsch   PetscCall(TSSetIFunction(ts, NULL, FormIFunction, &user));
1109566063dSJacob Faibussowitsch   PetscCall(DMSetMatType(da, MATAIJ));
1119566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(da, &J));
1129566063dSJacob Faibussowitsch   PetscCall(TSSetIJacobian(ts, J, J, FormIJacobian, &user));
113c4762a1bSJed Brown 
114c4762a1bSJed Brown   ftime = 1.0;
1159566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, ftime));
1169566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
117c4762a1bSJed Brown 
118c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
119c4762a1bSJed Brown      Set initial conditions
120c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1219566063dSJacob Faibussowitsch   PetscCall(FormInitialSolution(ts, X, &user));
1229566063dSJacob Faibussowitsch   PetscCall(TSSetSolution(ts, X));
1239566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &mx));
124c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(mx / 2 - 1);
125c4762a1bSJed Brown   dt = 0.4 * PetscSqr(hx) / user.alpha; /* Diffusive stability limit */
126c4762a1bSJed Brown   dt *= PetscPowRealInt(0.2, cycle);    /* Shrink the time step in convergence study. */
1279566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, dt));
1289566063dSJacob Faibussowitsch   PetscCall(TSSetTolerances(ts, 1e-3 * PetscPowRealInt(0.5, cycle), NULL, 1e-3 * PetscPowRealInt(0.5, cycle), NULL));
129c4762a1bSJed Brown 
130c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131c4762a1bSJed Brown      Set runtime options
132c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1339566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts));
134c4762a1bSJed Brown 
135c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
136c4762a1bSJed Brown      Solve nonlinear system
137c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1389566063dSJacob Faibussowitsch   PetscCall(TSSolve(ts, X));
1399566063dSJacob Faibussowitsch   PetscCall(TSGetSolveTime(ts, &ftime));
1409566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &steps));
1419566063dSJacob Faibussowitsch   PetscCall(TSGetConvergedReason(ts, &reason));
1429566063dSJacob Faibussowitsch   PetscCall(VecMin(X, NULL, &xmin));
1439566063dSJacob Faibussowitsch   PetscCall(VecMax(X, NULL, &xmax));
14463a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s at time %g after % 3" PetscInt_FMT " steps. Range [%6.4f,%6.4f]\n", TSConvergedReasons[reason], (double)ftime, steps, (double)xmin, (double)xmax));
145c4762a1bSJed Brown 
146c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147c4762a1bSJed Brown      Free work space.
148c4762a1bSJed Brown    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
1509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
1519566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
1529566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&da));
1539566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
1543ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
155c4762a1bSJed Brown }
156c4762a1bSJed Brown 
FormIFunction(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void * ptr)157d71ae5a4SJacob Faibussowitsch static PetscErrorCode FormIFunction(TS ts, PetscReal t, Vec X, Vec Xdot, Vec F, void *ptr)
158d71ae5a4SJacob Faibussowitsch {
159c4762a1bSJed Brown   User          user = (User)ptr;
160c4762a1bSJed Brown   DM            da;
161c4762a1bSJed Brown   DMDALocalInfo info;
162c4762a1bSJed Brown   PetscInt      i;
163c4762a1bSJed Brown   Field        *x, *xdot, *f;
164c4762a1bSJed Brown   PetscReal     hx;
165c4762a1bSJed Brown   Vec           Xloc;
166c4762a1bSJed Brown 
167c4762a1bSJed Brown   PetscFunctionBeginUser;
1689566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
1699566063dSJacob Faibussowitsch   PetscCall(DMDAGetLocalInfo(da, &info));
170c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(info.mx - 1);
171c4762a1bSJed Brown 
172c4762a1bSJed Brown   /*
173c4762a1bSJed Brown      Scatter ghost points to local vector,using the 2-step process
174c4762a1bSJed Brown         DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
175c4762a1bSJed Brown      By placing code between these two statements, computations can be
176c4762a1bSJed Brown      done while messages are in transition.
177c4762a1bSJed Brown   */
1789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
1799566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
1809566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
181c4762a1bSJed Brown 
182c4762a1bSJed Brown   /* Get pointers to vector data */
1839566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, Xloc, &x));
1849566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, Xdot, &xdot));
1859566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, F, &f));
186c4762a1bSJed Brown 
187c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
188c4762a1bSJed Brown   for (i = info.xs; i < info.xs + info.xm; i++) {
189c4762a1bSJed Brown     if (i == 0) {
190c4762a1bSJed Brown       f[i].u = hx * (x[i].u - user->uleft);
191c4762a1bSJed Brown       f[i].v = hx * (x[i].v - user->vleft);
192c4762a1bSJed Brown     } else if (i == info.mx - 1) {
193c4762a1bSJed Brown       f[i].u = hx * (x[i].u - user->uright);
194c4762a1bSJed Brown       f[i].v = hx * (x[i].v - user->vright);
195c4762a1bSJed Brown     } else {
196c4762a1bSJed Brown       f[i].u = hx * xdot[i].u - user->alpha * (x[i - 1].u - 2. * x[i].u + x[i + 1].u) / hx;
197c4762a1bSJed Brown       f[i].v = hx * xdot[i].v - user->alpha * (x[i - 1].v - 2. * x[i].v + x[i + 1].v) / hx;
198c4762a1bSJed Brown     }
199c4762a1bSJed Brown   }
200c4762a1bSJed Brown 
201c4762a1bSJed Brown   /* Restore vectors */
2029566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, Xloc, &x));
2039566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, Xdot, &xdot));
2049566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, F, &f));
2059566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
2063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207c4762a1bSJed Brown }
208c4762a1bSJed Brown 
FormRHSFunction(TS ts,PetscReal t,Vec X,Vec F,void * ptr)209d71ae5a4SJacob Faibussowitsch static PetscErrorCode FormRHSFunction(TS ts, PetscReal t, Vec X, Vec F, void *ptr)
210d71ae5a4SJacob Faibussowitsch {
211c4762a1bSJed Brown   User          user = (User)ptr;
212c4762a1bSJed Brown   DM            da;
213c4762a1bSJed Brown   DMDALocalInfo info;
214c4762a1bSJed Brown   PetscInt      i;
215c4762a1bSJed Brown   PetscReal     hx;
216c4762a1bSJed Brown   Field        *x, *f;
217c4762a1bSJed Brown 
218c4762a1bSJed Brown   PetscFunctionBeginUser;
2199566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
2209566063dSJacob Faibussowitsch   PetscCall(DMDAGetLocalInfo(da, &info));
221c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(info.mx - 1);
222c4762a1bSJed Brown 
223c4762a1bSJed Brown   /* Get pointers to vector data */
2249566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, X, &x));
2259566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, F, &f));
226c4762a1bSJed Brown 
227c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
228c4762a1bSJed Brown   for (i = info.xs; i < info.xs + info.xm; i++) {
229c4762a1bSJed Brown     PetscScalar u = x[i].u, v = x[i].v;
230c4762a1bSJed Brown     f[i].u = hx * (user->A + u * u * v - (user->B + 1) * u);
231c4762a1bSJed Brown     f[i].v = hx * (user->B * u - u * u * v);
232c4762a1bSJed Brown   }
233c4762a1bSJed Brown 
234c4762a1bSJed Brown   /* Restore vectors */
2359566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, X, &x));
2369566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, F, &f));
2373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
238c4762a1bSJed Brown }
239c4762a1bSJed Brown 
240c4762a1bSJed Brown /* --------------------------------------------------------------------- */
241c4762a1bSJed Brown /*
242c4762a1bSJed Brown   IJacobian - Compute IJacobian = dF/dU + a dF/dUdot
243c4762a1bSJed Brown */
FormIJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat J,Mat Jpre,void * ptr)244d71ae5a4SJacob Faibussowitsch PetscErrorCode FormIJacobian(TS ts, PetscReal t, Vec X, Vec Xdot, PetscReal a, Mat J, Mat Jpre, void *ptr)
245d71ae5a4SJacob Faibussowitsch {
246c4762a1bSJed Brown   User          user = (User)ptr;
247c4762a1bSJed Brown   DMDALocalInfo info;
248c4762a1bSJed Brown   PetscInt      i;
249c4762a1bSJed Brown   PetscReal     hx;
250c4762a1bSJed Brown   DM            da;
251c4762a1bSJed Brown   Field        *x, *xdot;
252c4762a1bSJed Brown 
253c4762a1bSJed Brown   PetscFunctionBeginUser;
2549566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
2559566063dSJacob Faibussowitsch   PetscCall(DMDAGetLocalInfo(da, &info));
256c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(info.mx - 1);
257c4762a1bSJed Brown 
258c4762a1bSJed Brown   /* Get pointers to vector data */
2599566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, X, &x));
2609566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, Xdot, &xdot));
261c4762a1bSJed Brown 
262c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
263c4762a1bSJed Brown   for (i = info.xs; i < info.xs + info.xm; i++) {
264c4762a1bSJed Brown     if (i == 0 || i == info.mx - 1) {
265c4762a1bSJed Brown       const PetscInt    row = i, col = i;
2669371c9d4SSatish Balay       const PetscScalar vals[2][2] = {
2679371c9d4SSatish Balay         {hx, 0 },
2689371c9d4SSatish Balay         {0,  hx}
2699371c9d4SSatish Balay       };
2709566063dSJacob Faibussowitsch       PetscCall(MatSetValuesBlocked(Jpre, 1, &row, 1, &col, &vals[0][0], INSERT_VALUES));
271c4762a1bSJed Brown     } else {
272c4762a1bSJed Brown       const PetscInt    row = i, col[] = {i - 1, i, i + 1};
273c4762a1bSJed Brown       const PetscScalar dxxL = -user->alpha / hx, dxx0 = 2. * user->alpha / hx, dxxR = -user->alpha / hx;
2749371c9d4SSatish Balay       const PetscScalar vals[2][3][2] = {
2759371c9d4SSatish Balay         {{dxxL, 0}, {a * hx + dxx0, 0}, {dxxR, 0}},
2769371c9d4SSatish Balay         {{0, dxxL}, {0, a * hx + dxx0}, {0, dxxR}}
2779371c9d4SSatish Balay       };
2789566063dSJacob Faibussowitsch       PetscCall(MatSetValuesBlocked(Jpre, 1, &row, 3, col, &vals[0][0][0], INSERT_VALUES));
279c4762a1bSJed Brown     }
280c4762a1bSJed Brown   }
281c4762a1bSJed Brown 
282c4762a1bSJed Brown   /* Restore vectors */
2839566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, X, &x));
2849566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, Xdot, &xdot));
285c4762a1bSJed Brown 
2869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Jpre, MAT_FINAL_ASSEMBLY));
2879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Jpre, MAT_FINAL_ASSEMBLY));
288c4762a1bSJed Brown   if (J != Jpre) {
2899566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2909566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
291c4762a1bSJed Brown   }
2923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
293c4762a1bSJed Brown }
294c4762a1bSJed Brown 
FormInitialSolution(TS ts,Vec X,PetscCtx ctx)295*2a8381b2SBarry Smith PetscErrorCode FormInitialSolution(TS ts, Vec X, PetscCtx ctx)
296d71ae5a4SJacob Faibussowitsch {
297c4762a1bSJed Brown   User          user = (User)ctx;
298c4762a1bSJed Brown   DM            da;
299c4762a1bSJed Brown   PetscInt      i;
300c4762a1bSJed Brown   DMDALocalInfo info;
301c4762a1bSJed Brown   Field        *x;
302c4762a1bSJed Brown   PetscReal     hx;
303c4762a1bSJed Brown 
304c4762a1bSJed Brown   PetscFunctionBeginUser;
3059566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
3069566063dSJacob Faibussowitsch   PetscCall(DMDAGetLocalInfo(da, &info));
307c4762a1bSJed Brown   hx = 1.0 / (PetscReal)(info.mx - 1);
308c4762a1bSJed Brown 
309c4762a1bSJed Brown   /* Get pointers to vector data */
3109566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, X, &x));
311c4762a1bSJed Brown 
312c4762a1bSJed Brown   /* Compute function over the locally owned part of the grid */
313c4762a1bSJed Brown   for (i = info.xs; i < info.xs + info.xm; i++) {
314c4762a1bSJed Brown     PetscReal xi = i * hx;
315c4762a1bSJed Brown     x[i].u       = user->uleft * (1. - xi) + user->uright * xi + PetscSinReal(2. * PETSC_PI * xi);
316c4762a1bSJed Brown     x[i].v       = user->vleft * (1. - xi) + user->vright * xi;
317c4762a1bSJed Brown   }
3189566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, X, &x));
3193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
320c4762a1bSJed Brown }
321c4762a1bSJed Brown 
322c4762a1bSJed Brown /*TEST
323c4762a1bSJed Brown 
324c4762a1bSJed Brown     test:
325c4762a1bSJed Brown       args: -ts_exact_final_time INTERPOLATE -snes_rtol 1.e-3
326c4762a1bSJed Brown 
327c4762a1bSJed Brown     test:
328c4762a1bSJed Brown       suffix: 2
329c4762a1bSJed Brown       args: -ts_exact_final_time INTERPOLATE -snes_rtol 1.e-3
330c4762a1bSJed Brown 
331c4762a1bSJed Brown TEST*/
332