Actual source code: ex21.c
1: static char help[] = "Solves a time-dependent nonlinear PDE with lower and upper bounds on the interior grid points. Uses implicit\n\
2: timestepping. Runtime options include:\n\
3: -M <xg>, where <xg> = number of grid points\n\
4: -debug : Activate debugging printouts\n\
5: -nox : Deactivate x-window graphics\n\
6: -ul : lower bound\n\
7: -uh : upper bound\n\n";
9: /* ------------------------------------------------------------------------
11: This is a variation of ex2.c to solve the PDE
13: u * u_xx
14: u_t = ---------
15: 2*(t+1)^2
17: with box constraints on the interior grid points
18: ul <= u(t,x) <= uh with x != 0,1
19: on the domain 0 <= x <= 1, with boundary conditions
20: u(t,0) = t + 1, u(t,1) = 2*t + 2,
21: and initial condition
22: u(0,x) = 1 + x*x.
24: The exact solution is:
25: u(t,x) = (1 + x*x) * (1 + t)
27: We use by default the backward Euler method.
29: ------------------------------------------------------------------------- */
31: /*
32: Include "petscts.h" to use the PETSc timestepping routines. Note that
33: this file automatically includes "petscsys.h" and other lower-level
34: PETSc include files.
36: Include the "petscdmda.h" to allow us to use the distributed array data
37: structures to manage the parallel grid.
38: */
39: #include <petscts.h>
40: #include <petscdm.h>
41: #include <petscdmda.h>
42: #include <petscdraw.h>
44: /*
45: User-defined application context - contains data needed by the
46: application-provided callback routines.
47: */
48: typedef struct {
49: MPI_Comm comm; /* communicator */
50: DM da; /* distributed array data structure */
51: Vec localwork; /* local ghosted work vector */
52: Vec u_local; /* local ghosted approximate solution vector */
53: Vec solution; /* global exact solution vector */
54: PetscInt m; /* total number of grid points */
55: PetscReal h; /* mesh width: h = 1/(m-1) */
56: PetscBool debug; /* flag (1 indicates activation of debugging printouts) */
57: } AppCtx;
59: /*
60: User-defined routines, provided below.
61: */
62: extern PetscErrorCode InitialConditions(Vec, AppCtx *);
63: extern PetscErrorCode RHSFunction(TS, PetscReal, Vec, Vec, void *);
64: extern PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *);
65: extern PetscErrorCode Monitor(TS, PetscInt, PetscReal, Vec, void *);
66: extern PetscErrorCode ExactSolution(PetscReal, Vec, AppCtx *);
67: extern PetscErrorCode SetBounds(Vec, Vec, PetscScalar, PetscScalar, AppCtx *);
69: int main(int argc, char **argv)
70: {
71: AppCtx appctx; /* user-defined application context */
72: TS ts; /* timestepping context */
73: Mat A; /* Jacobian matrix data structure */
74: Vec u; /* approximate solution vector */
75: Vec r; /* residual vector */
76: PetscInt time_steps_max = 1000; /* default max timesteps */
77: PetscReal dt;
78: PetscReal time_total_max = 100.0; /* default max total time */
79: Vec xl, xu; /* Lower and upper bounds on variables */
80: PetscScalar ul = 0.0, uh = 3.0;
81: PetscBool mymonitor;
82: PetscReal bounds[] = {1.0, 3.3};
84: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85: Initialize program and set problem parameters
86: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
88: PetscFunctionBeginUser;
89: PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
90: PetscCall(PetscViewerDrawSetBounds(PETSC_VIEWER_DRAW_(PETSC_COMM_WORLD), 1, bounds));
92: appctx.comm = PETSC_COMM_WORLD;
93: appctx.m = 60;
94: PetscCall(PetscOptionsGetInt(NULL, NULL, "-M", &appctx.m, NULL));
95: PetscCall(PetscOptionsGetScalar(NULL, NULL, "-ul", &ul, NULL));
96: PetscCall(PetscOptionsGetScalar(NULL, NULL, "-uh", &uh, NULL));
97: PetscCall(PetscOptionsHasName(NULL, NULL, "-debug", &appctx.debug));
98: PetscCall(PetscOptionsHasName(NULL, NULL, "-mymonitor", &mymonitor));
99: appctx.h = 1.0 / (appctx.m - 1.0);
101: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102: Create vector data structures
103: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
105: /*
106: Create distributed array (DMDA) to manage parallel grid and vectors
107: and to set up the ghost point communication pattern. There are M
108: total grid values spread equally among all the processors.
109: */
110: PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, appctx.m, 1, 1, NULL, &appctx.da));
111: PetscCall(DMSetFromOptions(appctx.da));
112: PetscCall(DMSetUp(appctx.da));
114: /*
115: Extract global and local vectors from DMDA; we use these to store the
116: approximate solution. Then duplicate these for remaining vectors that
117: have the same types.
118: */
119: PetscCall(DMCreateGlobalVector(appctx.da, &u));
120: PetscCall(DMCreateLocalVector(appctx.da, &appctx.u_local));
122: /*
123: Create local work vector for use in evaluating right-hand-side function;
124: create global work vector for storing exact solution.
125: */
126: PetscCall(VecDuplicate(appctx.u_local, &appctx.localwork));
127: PetscCall(VecDuplicate(u, &appctx.solution));
129: /* Create residual vector */
130: PetscCall(VecDuplicate(u, &r));
131: /* Create lower and upper bound vectors */
132: PetscCall(VecDuplicate(u, &xl));
133: PetscCall(VecDuplicate(u, &xu));
134: PetscCall(SetBounds(xl, xu, ul, uh, &appctx));
136: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137: Create timestepping solver context; set callback routine for
138: right-hand-side function evaluation.
139: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
141: PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
142: PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
143: PetscCall(TSSetRHSFunction(ts, r, RHSFunction, &appctx));
145: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
146: Set optional user-defined monitoring routine
147: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
149: if (mymonitor) PetscCall(TSMonitorSet(ts, Monitor, &appctx, NULL));
151: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152: For nonlinear problems, the user can provide a Jacobian evaluation
153: routine (or use a finite differencing approximation).
155: Create matrix data structure; set Jacobian evaluation routine.
156: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
158: PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
159: PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, appctx.m, appctx.m));
160: PetscCall(MatSetFromOptions(A));
161: PetscCall(MatSetUp(A));
162: PetscCall(TSSetRHSJacobian(ts, A, A, RHSJacobian, &appctx));
164: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
165: Set solution vector and initial timestep
166: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
168: dt = appctx.h / 2.0;
169: PetscCall(TSSetTimeStep(ts, dt));
171: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172: Customize timestepping solver:
173: - Set the solution method to be the Backward Euler method.
174: - Set timestepping duration info
175: Then set runtime options, which can override these defaults.
176: For example,
177: -ts_max_steps <maxsteps> -ts_max_time <maxtime>
178: to override the defaults set by TSSetMaxSteps()/TSSetMaxTime().
179: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
181: PetscCall(TSSetType(ts, TSBEULER));
182: PetscCall(TSSetMaxSteps(ts, time_steps_max));
183: PetscCall(TSSetMaxTime(ts, time_total_max));
184: PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
185: /* Set lower and upper bound on the solution vector for each time step */
186: PetscCall(TSVISetVariableBounds(ts, xl, xu));
187: PetscCall(TSSetFromOptions(ts));
189: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
190: Solve the problem
191: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
193: /*
194: Evaluate initial conditions
195: */
196: PetscCall(InitialConditions(u, &appctx));
198: /*
199: Run the timestepping solver
200: */
201: PetscCall(TSSolve(ts, u));
203: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204: Free work space. All PETSc objects should be destroyed when they
205: are no longer needed.
206: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
208: PetscCall(VecDestroy(&r));
209: PetscCall(VecDestroy(&xl));
210: PetscCall(VecDestroy(&xu));
211: PetscCall(TSDestroy(&ts));
212: PetscCall(VecDestroy(&u));
213: PetscCall(MatDestroy(&A));
214: PetscCall(DMDestroy(&appctx.da));
215: PetscCall(VecDestroy(&appctx.localwork));
216: PetscCall(VecDestroy(&appctx.solution));
217: PetscCall(VecDestroy(&appctx.u_local));
219: /*
220: Always call PetscFinalize() before exiting a program. This routine
221: - finalizes the PETSc libraries as well as MPI
222: - provides summary and diagnostic information if certain runtime
223: options are chosen (e.g., -log_view).
224: */
225: PetscCall(PetscFinalize());
226: return 0;
227: }
228: /* --------------------------------------------------------------------- */
229: /*
230: InitialConditions - Computes the solution at the initial time.
232: Input Parameters:
233: u - uninitialized solution vector (global)
234: appctx - user-defined application context
236: Output Parameter:
237: u - vector with solution at initial time (global)
238: */
239: PetscErrorCode InitialConditions(Vec u, AppCtx *appctx)
240: {
241: PetscScalar *u_localptr, h = appctx->h, x;
242: PetscInt i, mybase, myend;
244: PetscFunctionBeginUser;
245: /*
246: Determine starting point of each processor's range of
247: grid values.
248: */
249: PetscCall(VecGetOwnershipRange(u, &mybase, &myend));
251: /*
252: Get a pointer to vector data.
253: - For default PETSc vectors, VecGetArray() returns a pointer to
254: the data array. Otherwise, the routine is implementation dependent.
255: - You MUST call VecRestoreArray() when you no longer need access to
256: the array.
257: - Note that the Fortran interface to VecGetArray() differs from the
258: C version. See the users manual for details.
259: */
260: PetscCall(VecGetArray(u, &u_localptr));
262: /*
263: We initialize the solution array by simply writing the solution
264: directly into the array locations. Alternatively, we could use
265: VecSetValues() or VecSetValuesLocal().
266: */
267: for (i = mybase; i < myend; i++) {
268: x = h * (PetscReal)i; /* current location in global grid */
269: u_localptr[i - mybase] = 1.0 + x * x;
270: }
272: /*
273: Restore vector
274: */
275: PetscCall(VecRestoreArray(u, &u_localptr));
277: /*
278: Print debugging information if desired
279: */
280: if (appctx->debug) {
281: PetscCall(PetscPrintf(appctx->comm, "initial guess vector\n"));
282: PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD));
283: }
285: PetscFunctionReturn(PETSC_SUCCESS);
286: }
288: /* --------------------------------------------------------------------- */
289: /*
290: SetBounds - Sets the lower and upper bounds on the interior points
292: Input parameters:
293: xl - vector of lower bounds
294: xu - vector of upper bounds
295: ul - constant lower bound for all variables
296: uh - constant upper bound for all variables
297: appctx - Application context
298: */
299: PetscErrorCode SetBounds(Vec xl, Vec xu, PetscScalar ul, PetscScalar uh, AppCtx *appctx)
300: {
301: PetscScalar *l, *u;
302: PetscMPIInt rank, size;
303: PetscInt localsize;
305: PetscFunctionBeginUser;
306: PetscCall(VecSet(xl, ul));
307: PetscCall(VecSet(xu, uh));
308: PetscCall(VecGetLocalSize(xl, &localsize));
309: PetscCall(VecGetArray(xl, &l));
310: PetscCall(VecGetArray(xu, &u));
312: PetscCallMPI(MPI_Comm_rank(appctx->comm, &rank));
313: PetscCallMPI(MPI_Comm_size(appctx->comm, &size));
314: if (rank == 0) {
315: l[0] = -PETSC_INFINITY;
316: u[0] = PETSC_INFINITY;
317: }
318: if (rank == size - 1) {
319: l[localsize - 1] = -PETSC_INFINITY;
320: u[localsize - 1] = PETSC_INFINITY;
321: }
322: PetscCall(VecRestoreArray(xl, &l));
323: PetscCall(VecRestoreArray(xu, &u));
324: PetscFunctionReturn(PETSC_SUCCESS);
325: }
327: /* --------------------------------------------------------------------- */
328: /*
329: ExactSolution - Computes the exact solution at a given time.
331: Input Parameters:
332: t - current time
333: solution - vector in which exact solution will be computed
334: appctx - user-defined application context
336: Output Parameter:
337: solution - vector with the newly computed exact solution
338: */
339: PetscErrorCode ExactSolution(PetscReal t, Vec solution, AppCtx *appctx)
340: {
341: PetscScalar *s_localptr, h = appctx->h, x;
342: PetscInt i, mybase, myend;
344: PetscFunctionBeginUser;
345: /*
346: Determine starting and ending points of each processor's
347: range of grid values
348: */
349: PetscCall(VecGetOwnershipRange(solution, &mybase, &myend));
351: /*
352: Get a pointer to vector data.
353: */
354: PetscCall(VecGetArray(solution, &s_localptr));
356: /*
357: Simply write the solution directly into the array locations.
358: Alternatively, we could use VecSetValues() or VecSetValuesLocal().
359: */
360: for (i = mybase; i < myend; i++) {
361: x = h * (PetscReal)i;
362: s_localptr[i - mybase] = (t + 1.0) * (1.0 + x * x);
363: }
365: /*
366: Restore vector
367: */
368: PetscCall(VecRestoreArray(solution, &s_localptr));
369: PetscFunctionReturn(PETSC_SUCCESS);
370: }
371: /* --------------------------------------------------------------------- */
372: /*
373: Monitor - User-provided routine to monitor the solution computed at
374: each timestep. This example plots the solution and computes the
375: error in two different norms.
377: Input Parameters:
378: ts - the timestep context
379: step - the count of the current step (with 0 meaning the
380: initial condition)
381: time - the current time
382: u - the solution at this timestep
383: ctx - the user-provided context for this monitoring routine.
384: In this case we use the application context which contains
385: information about the problem size, workspace and the exact
386: solution.
387: */
388: PetscErrorCode Monitor(TS ts, PetscInt step, PetscReal time, Vec u, void *ctx)
389: {
390: AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */
391: PetscReal en2, en2s, enmax;
392: PetscDraw draw;
394: PetscFunctionBeginUser;
395: /*
396: We use the default X windows viewer
397: PETSC_VIEWER_DRAW_(appctx->comm)
398: that is associated with the current communicator. This saves
399: the effort of calling PetscViewerDrawOpen() to create the window.
400: Note that if we wished to plot several items in separate windows we
401: would create each viewer with PetscViewerDrawOpen() and store them in
402: the application context, appctx.
404: PetscReal buffering makes graphics look better.
405: */
406: PetscCall(PetscViewerDrawGetDraw(PETSC_VIEWER_DRAW_(appctx->comm), 0, &draw));
407: PetscCall(PetscDrawSetDoubleBuffer(draw));
408: PetscCall(VecView(u, PETSC_VIEWER_DRAW_(appctx->comm)));
410: /*
411: Compute the exact solution at this timestep
412: */
413: PetscCall(ExactSolution(time, appctx->solution, appctx));
415: /*
416: Print debugging information if desired
417: */
418: if (appctx->debug) {
419: PetscCall(PetscPrintf(appctx->comm, "Computed solution vector\n"));
420: PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD));
421: PetscCall(PetscPrintf(appctx->comm, "Exact solution vector\n"));
422: PetscCall(VecView(appctx->solution, PETSC_VIEWER_STDOUT_WORLD));
423: }
425: /*
426: Compute the 2-norm and max-norm of the error
427: */
428: PetscCall(VecAXPY(appctx->solution, -1.0, u));
429: PetscCall(VecNorm(appctx->solution, NORM_2, &en2));
430: en2s = PetscSqrtReal(appctx->h) * en2; /* scale the 2-norm by the grid spacing */
431: PetscCall(VecNorm(appctx->solution, NORM_MAX, &enmax));
433: /*
434: PetscPrintf() causes only the first processor in this
435: communicator to print the timestep information.
436: */
437: PetscCall(PetscPrintf(appctx->comm, "Timestep %" PetscInt_FMT ": time = %g,2-norm error = %g, max norm error = %g\n", step, (double)time, (double)en2s, (double)enmax));
439: /*
440: Print debugging information if desired
441: */
442: /* if (appctx->debug) {
443: PetscCall(PetscPrintf(appctx->comm,"Error vector\n"));
444: PetscCall(VecView(appctx->solution,PETSC_VIEWER_STDOUT_WORLD));
445: } */
446: PetscFunctionReturn(PETSC_SUCCESS);
447: }
448: /* --------------------------------------------------------------------- */
449: /*
450: RHSFunction - User-provided routine that evalues the right-hand-side
451: function of the ODE. This routine is set in the main program by
452: calling TSSetRHSFunction(). We compute:
453: global_out = F(global_in)
455: Input Parameters:
456: ts - timesteping context
457: t - current time
458: global_in - vector containing the current iterate
459: ctx - (optional) user-provided context for function evaluation.
460: In this case we use the appctx defined above.
462: Output Parameter:
463: global_out - vector containing the newly evaluated function
464: */
465: PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec global_in, Vec global_out, void *ctx)
466: {
467: AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */
468: DM da = appctx->da; /* distributed array */
469: Vec local_in = appctx->u_local; /* local ghosted input vector */
470: Vec localwork = appctx->localwork; /* local ghosted work vector */
471: PetscInt i, localsize;
472: PetscMPIInt rank, size;
473: PetscScalar *copyptr, sc;
474: const PetscScalar *localptr;
476: PetscFunctionBeginUser;
477: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
478: Get ready for local function computations
479: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
480: /*
481: Scatter ghost points to local vector, using the 2-step process
482: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
483: By placing code between these two statements, computations can be
484: done while messages are in transition.
485: */
486: PetscCall(DMGlobalToLocalBegin(da, global_in, INSERT_VALUES, local_in));
487: PetscCall(DMGlobalToLocalEnd(da, global_in, INSERT_VALUES, local_in));
489: /*
490: Access directly the values in our local INPUT work array
491: */
492: PetscCall(VecGetArrayRead(local_in, &localptr));
494: /*
495: Access directly the values in our local OUTPUT work array
496: */
497: PetscCall(VecGetArray(localwork, ©ptr));
499: sc = 1.0 / (appctx->h * appctx->h * 2.0 * (1.0 + t) * (1.0 + t));
501: /*
502: Evaluate our function on the nodes owned by this processor
503: */
504: PetscCall(VecGetLocalSize(local_in, &localsize));
506: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
507: Compute entries for the locally owned part
508: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
510: /*
511: Handle boundary conditions: This is done by using the boundary condition
512: u(t,boundary) = g(t,boundary)
513: for some function g. Now take the derivative with respect to t to obtain
514: u_{t}(t,boundary) = g_{t}(t,boundary)
516: In our case, u(t,0) = t + 1, so that u_{t}(t,0) = 1
517: and u(t,1) = 2t+ 2, so that u_{t}(t,1) = 2
518: */
519: PetscCallMPI(MPI_Comm_rank(appctx->comm, &rank));
520: PetscCallMPI(MPI_Comm_size(appctx->comm, &size));
521: if (rank == 0) copyptr[0] = 1.0;
522: if (rank == size - 1) copyptr[localsize - 1] = (t < .5) ? 2.0 : 0.0;
524: /*
525: Handle the interior nodes where the PDE is replace by finite
526: difference operators.
527: */
528: for (i = 1; i < localsize - 1; i++) copyptr[i] = localptr[i] * sc * (localptr[i + 1] + localptr[i - 1] - 2.0 * localptr[i]);
530: /*
531: Restore vectors
532: */
533: PetscCall(VecRestoreArrayRead(local_in, &localptr));
534: PetscCall(VecRestoreArray(localwork, ©ptr));
536: /*
537: Insert values from the local OUTPUT vector into the global
538: output vector
539: */
540: PetscCall(DMLocalToGlobalBegin(da, localwork, INSERT_VALUES, global_out));
541: PetscCall(DMLocalToGlobalEnd(da, localwork, INSERT_VALUES, global_out));
543: /* Print debugging information if desired */
544: /* if (appctx->debug) {
545: PetscCall(PetscPrintf(appctx->comm,"RHS function vector\n"));
546: PetscCall(VecView(global_out,PETSC_VIEWER_STDOUT_WORLD));
547: } */
549: PetscFunctionReturn(PETSC_SUCCESS);
550: }
551: /* --------------------------------------------------------------------- */
552: /*
553: RHSJacobian - User-provided routine to compute the Jacobian of
554: the nonlinear right-hand-side function of the ODE.
556: Input Parameters:
557: ts - the TS context
558: t - current time
559: global_in - global input vector
560: dummy - optional user-defined context, as set by TSetRHSJacobian()
562: Output Parameters:
563: AA - Jacobian matrix
564: BB - optionally different preconditioning matrix
565: str - flag indicating matrix structure
567: Notes:
568: RHSJacobian computes entries for the locally owned part of the Jacobian.
569: - Currently, all PETSc parallel matrix formats are partitioned by
570: contiguous chunks of rows across the processors.
571: - Each processor needs to insert only elements that it owns
572: locally (but any non-local elements will be sent to the
573: appropriate processor during matrix assembly).
574: - Always specify global row and columns of matrix entries when
575: using MatSetValues().
576: - Here, we set all entries for a particular row at once.
577: - Note that MatSetValues() uses 0-based row and column numbers
578: in Fortran as well as in C.
579: */
580: PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec global_in, Mat AA, Mat B, void *ctx)
581: {
582: AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */
583: Vec local_in = appctx->u_local; /* local ghosted input vector */
584: DM da = appctx->da; /* distributed array */
585: PetscScalar v[3], sc;
586: const PetscScalar *localptr;
587: PetscInt i, mstart, mend, mstarts, mends, idx[3], is;
589: PetscFunctionBeginUser;
590: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
591: Get ready for local Jacobian computations
592: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
593: /*
594: Scatter ghost points to local vector, using the 2-step process
595: DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
596: By placing code between these two statements, computations can be
597: done while messages are in transition.
598: */
599: PetscCall(DMGlobalToLocalBegin(da, global_in, INSERT_VALUES, local_in));
600: PetscCall(DMGlobalToLocalEnd(da, global_in, INSERT_VALUES, local_in));
602: /*
603: Get pointer to vector data
604: */
605: PetscCall(VecGetArrayRead(local_in, &localptr));
607: /*
608: Get starting and ending locally owned rows of the matrix
609: */
610: PetscCall(MatGetOwnershipRange(B, &mstarts, &mends));
611: mstart = mstarts;
612: mend = mends;
614: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
615: Compute entries for the locally owned part of the Jacobian.
616: - Currently, all PETSc parallel matrix formats are partitioned by
617: contiguous chunks of rows across the processors.
618: - Each processor needs to insert only elements that it owns
619: locally (but any non-local elements will be sent to the
620: appropriate processor during matrix assembly).
621: - Here, we set all entries for a particular row at once.
622: - We can set matrix entries either using either
623: MatSetValuesLocal() or MatSetValues().
624: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
626: /*
627: Set matrix rows corresponding to boundary data
628: */
629: if (mstart == 0) {
630: v[0] = 0.0;
631: PetscCall(MatSetValues(B, 1, &mstart, 1, &mstart, v, INSERT_VALUES));
632: mstart++;
633: }
634: if (mend == appctx->m) {
635: mend--;
636: v[0] = 0.0;
637: PetscCall(MatSetValues(B, 1, &mend, 1, &mend, v, INSERT_VALUES));
638: }
640: /*
641: Set matrix rows corresponding to interior data. We construct the
642: matrix one row at a time.
643: */
644: sc = 1.0 / (appctx->h * appctx->h * 2.0 * (1.0 + t) * (1.0 + t));
645: for (i = mstart; i < mend; i++) {
646: idx[0] = i - 1;
647: idx[1] = i;
648: idx[2] = i + 1;
649: is = i - mstart + 1;
650: v[0] = sc * localptr[is];
651: v[1] = sc * (localptr[is + 1] + localptr[is - 1] - 4.0 * localptr[is]);
652: v[2] = sc * localptr[is];
653: PetscCall(MatSetValues(B, 1, &i, 3, idx, v, INSERT_VALUES));
654: }
656: /*
657: Restore vector
658: */
659: PetscCall(VecRestoreArrayRead(local_in, &localptr));
661: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
662: Complete the matrix assembly process and set some options
663: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
664: /*
665: Assemble matrix, using the 2-step process:
666: MatAssemblyBegin(), MatAssemblyEnd()
667: Computations can be done while messages are in transition
668: by placing code between these two statements.
669: */
670: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
671: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
673: /*
674: Set and option to indicate that we will never add a new nonzero location
675: to the matrix. If we do, it will generate an error.
676: */
677: PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
679: PetscFunctionReturn(PETSC_SUCCESS);
680: }
682: /*TEST
684: test:
685: args: -snes_type vinewtonrsls -ts_type glee -mymonitor -ts_max_steps 10 -nox
686: requires: !single
688: TEST*/