Actual source code: ex3.c
petsc-3.6.4 2016-04-12
2: static char help[] ="Model Equations for Advection-Diffusion\n";
4: /*
5: Page 9, Section 1.2 Model Equations for Advection-Diffusion
7: u_t = a u_x + d u_xx
9: The initial conditions used here different then in the book.
11: */
13: /*
14: Helpful runtime linear solver options:
15: -pc_type mg -da_refine 2 -snes_monitor -ksp_monitor -ts_view (geometric multigrid with three levels)
17: */
19: /*
20: Include "petscts.h" so that we can use TS solvers. Note that this file
21: automatically includes:
22: petscsys.h - base PETSc routines petscvec.h - vectors
23: petscmat.h - matrices
24: petscis.h - index sets petscksp.h - Krylov subspace methods
25: petscviewer.h - viewers petscpc.h - preconditioners
26: petscksp.h - linear solvers petscsnes.h - nonlinear solvers
27: */
29: #include <petscts.h>
30: #include <petscdm.h>
31: #include <petscdmda.h>
33: /*
34: User-defined application context - contains data needed by the
35: application-provided call-back routines.
36: */
37: typedef struct {
38: PetscScalar a,d; /* advection and diffusion strength */
39: PetscBool upwind;
40: } AppCtx;
42: /*
43: User-defined routines
44: */
45: extern PetscErrorCode InitialConditions(TS,Vec,AppCtx*);
46: extern PetscErrorCode RHSMatrixHeat(TS,PetscReal,Vec,Mat,Mat,void*);
47: extern PetscErrorCode Solution(TS,PetscReal,Vec,AppCtx*);
51: int main(int argc,char **argv)
52: {
53: AppCtx appctx; /* user-defined application context */
54: TS ts; /* timestepping context */
55: Vec U; /* approximate solution vector */
57: PetscReal dt;
58: DM da;
59: PetscInt M;
61: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62: Initialize program and set problem parameters
63: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
65: PetscInitialize(&argc,&argv,(char*)0,help);
66: appctx.a = 1.0;
67: appctx.d = 0.0;
68: PetscOptionsGetScalar(NULL,"-a",&appctx.a,NULL);
69: PetscOptionsGetScalar(NULL,"-d",&appctx.d,NULL);
70: appctx.upwind = PETSC_TRUE;
71: PetscOptionsGetBool(NULL,"-upwind",&appctx.upwind,NULL);
73: DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC, -60, 1, 1,NULL,&da);
74: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75: Create vector data structures
76: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
78: /*
79: Create vector data structures for approximate and exact solutions
80: */
81: DMCreateGlobalVector(da,&U);
83: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84: Create timestepping solver context
85: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
87: TSCreate(PETSC_COMM_WORLD,&ts);
88: TSSetDM(ts,da);
90: /*
91: For linear problems with a time-dependent f(U,t) in the equation
92: u_t = f(u,t), the user provides the discretized right-hand-side
93: as a time-dependent matrix.
94: */
95: TSSetRHSFunction(ts,NULL,TSComputeRHSFunctionLinear,&appctx);
96: TSSetRHSJacobian(ts,NULL,NULL,RHSMatrixHeat,&appctx);
97: TSSetSolutionFunction(ts,(PetscErrorCode (*)(TS,PetscReal,Vec,void*))Solution,&appctx);
99: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100: Customize timestepping solver:
101: - Set timestepping duration info
102: Then set runtime options, which can override these defaults.
103: For example,
104: -ts_max_steps <maxsteps> -ts_final_time <maxtime>
105: to override the defaults set by TSSetDuration().
106: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
108: DMDAGetInfo(da,PETSC_IGNORE,&M,0,0,0,0,0,0,0,0,0,0,0);
109: dt = .48/(M*M);
110: TSSetInitialTimeStep(ts,0.0,dt);
111: TSSetDuration(ts,1000,100.0);
112: TSSetType(ts,TSARKIMEX);
113: TSSetFromOptions(ts);
115: /*
116: Evaluate initial conditions
117: */
118: InitialConditions(ts,U,&appctx);
120: /*
121: Run the timestepping solver
122: */
123: TSSolve(ts,U);
126: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127: Free work space. All PETSc objects should be destroyed when they
128: are no longer needed.
129: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
131: TSDestroy(&ts);
132: VecDestroy(&U);
133: DMDestroy(&da);
135: /*
136: Always call PetscFinalize() before exiting a program. This routine
137: - finalizes the PETSc libraries as well as MPI
138: - provides summary and diagnostic information if certain runtime
139: options are chosen (e.g., -log_summary).
140: */
141: PetscFinalize();
142: return 0;
143: }
144: /* --------------------------------------------------------------------- */
147: /*
148: InitialConditions - Computes the solution at the initial time.
150: Input Parameter:
151: u - uninitialized solution vector (global)
152: appctx - user-defined application context
154: Output Parameter:
155: u - vector with solution at initial time (global)
156: */
157: PetscErrorCode InitialConditions(TS ts,Vec U,AppCtx *appctx)
158: {
159: PetscScalar *u,h;
161: PetscInt i,mstart,mend,xm,M;
162: DM da;
164: TSGetDM(ts,&da);
165: DMDAGetCorners(da,&mstart,0,0,&xm,0,0);
166: DMDAGetInfo(da,PETSC_IGNORE,&M,0,0,0,0,0,0,0,0,0,0,0);
167: h = 1.0/M;
168: mend = mstart + xm;
169: /*
170: Get a pointer to vector data.
171: - For default PETSc vectors, VecGetArray() returns a pointer to
172: the data array. Otherwise, the routine is implementation dependent.
173: - You MUST call VecRestoreArray() when you no longer need access to
174: the array.
175: - Note that the Fortran interface to VecGetArray() differs from the
176: C version. See the users manual for details.
177: */
178: DMDAVecGetArray(da,U,&u);
180: /*
181: We initialize the solution array by simply writing the solution
182: directly into the array locations. Alternatively, we could use
183: VecSetValues() or VecSetValuesLocal().
184: */
185: for (i=mstart; i<mend; i++) u[i] = PetscSinScalar(PETSC_PI*i*6.*h) + 3.*PetscSinScalar(PETSC_PI*i*2.*h);
187: /*
188: Restore vector
189: */
190: DMDAVecRestoreArray(da,U,&u);
191: return 0;
192: }
193: /* --------------------------------------------------------------------- */
196: /*
197: Solution - Computes the exact solution at a given time.
199: Input Parameters:
200: t - current time
201: solution - vector in which exact solution will be computed
202: appctx - user-defined application context
204: Output Parameter:
205: solution - vector with the newly computed exact solution
206: */
207: PetscErrorCode Solution(TS ts,PetscReal t,Vec U,AppCtx *appctx)
208: {
209: PetscScalar *u,ex1,ex2,sc1,sc2,h;
211: PetscInt i,mstart,mend,xm,M;
212: DM da;
214: TSGetDM(ts,&da);
215: DMDAGetCorners(da,&mstart,0,0,&xm,0,0);
216: DMDAGetInfo(da,PETSC_IGNORE,&M,0,0,0,0,0,0,0,0,0,0,0);
217: h = 1.0/M;
218: mend = mstart + xm;
219: /*
220: Get a pointer to vector data.
221: */
222: DMDAVecGetArray(da,U,&u);
224: /*
225: Simply write the solution directly into the array locations.
226: Alternatively, we culd use VecSetValues() or VecSetValuesLocal().
227: */
228: ex1 = PetscExpScalar(-36.*PETSC_PI*PETSC_PI*appctx->d*t);
229: ex2 = PetscExpScalar(-4.*PETSC_PI*PETSC_PI*appctx->d*t);
230: sc1 = PETSC_PI*6.*h; sc2 = PETSC_PI*2.*h;
231: for (i=mstart; i<mend; i++) u[i] = PetscSinScalar(sc1*(PetscReal)i + appctx->a*PETSC_PI*6.*t)*ex1 + 3.*PetscSinScalar(sc2*(PetscReal)i + appctx->a*PETSC_PI*2.*t)*ex2;
233: /*
234: Restore vector
235: */
236: DMDAVecRestoreArray(da,U,&u);
237: return 0;
238: }
240: /* --------------------------------------------------------------------- */
243: /*
244: RHSMatrixHeat - User-provided routine to compute the right-hand-side
245: matrix for the heat equation.
247: Input Parameters:
248: ts - the TS context
249: t - current time
250: global_in - global input vector
251: dummy - optional user-defined context, as set by TSetRHSJacobian()
253: Output Parameters:
254: AA - Jacobian matrix
255: BB - optionally different preconditioning matrix
256: str - flag indicating matrix structure
258: Notes:
259: Recall that MatSetValues() uses 0-based row and column numbers
260: in Fortran as well as in C.
261: */
262: PetscErrorCode RHSMatrixHeat(TS ts,PetscReal t,Vec U,Mat AA,Mat BB,void *ctx)
263: {
264: Mat A = AA; /* Jacobian matrix */
265: AppCtx *appctx = (AppCtx*)ctx; /* user-defined application context */
266: PetscInt mstart, mend;
268: PetscInt i,idx[3],M,xm;
269: PetscScalar v[3],h;
270: DM da;
272: TSGetDM(ts,&da);
273: DMDAGetInfo(da,0,&M,0,0,0,0,0,0,0,0,0,0,0);
274: DMDAGetCorners(da,&mstart,0,0,&xm,0,0);
275: h = 1.0/M;
276: mend = mstart + xm;
277: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
278: Compute entries for the locally owned part of the matrix
279: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
280: /*
281: Set matrix rows corresponding to boundary data
282: */
284: /* diffusion */
285: v[0] = appctx->d/(h*h);
286: v[1] = -2.0*appctx->d/(h*h);
287: v[2] = appctx->d/(h*h);
288: if (!mstart) {
289: idx[0] = M-1; idx[1] = 0; idx[2] = 1;
290: MatSetValues(A,1,&mstart,3,idx,v,INSERT_VALUES);
291: mstart++;
292: }
294: if (mend == M) {
295: mend--;
296: idx[0] = M-2; idx[1] = M-1; idx[2] = 0;
297: MatSetValues(A,1,&mend,3,idx,v,INSERT_VALUES);
298: }
300: /*
301: Set matrix rows corresponding to interior data. We construct the
302: matrix one row at a time.
303: */
304: for (i=mstart; i<mend; i++) {
305: idx[0] = i-1; idx[1] = i; idx[2] = i+1;
306: MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);
307: }
308: MatAssemblyBegin(A,MAT_FLUSH_ASSEMBLY);
309: MatAssemblyEnd(A,MAT_FLUSH_ASSEMBLY);
311: DMDAGetCorners(da,&mstart,0,0,&xm,0,0);
312: mend = mstart + xm;
313: if (!appctx->upwind) {
314: /* advection -- centered differencing */
315: v[0] = -.5*appctx->a/(h);
316: v[1] = .5*appctx->a/(h);
317: if (!mstart) {
318: idx[0] = M-1; idx[1] = 1;
319: MatSetValues(A,1,&mstart,2,idx,v,ADD_VALUES);
320: mstart++;
321: }
323: if (mend == M) {
324: mend--;
325: idx[0] = M-2; idx[1] = 0;
326: MatSetValues(A,1,&mend,2,idx,v,ADD_VALUES);
327: }
329: for (i=mstart; i<mend; i++) {
330: idx[0] = i-1; idx[1] = i+1;
331: MatSetValues(A,1,&i,2,idx,v,ADD_VALUES);
332: }
333: } else {
334: /* advection -- upwinding */
335: v[0] = -appctx->a/(h);
336: v[1] = appctx->a/(h);
337: if (!mstart) {
338: idx[0] = 0; idx[1] = 1;
339: MatSetValues(A,1,&mstart,2,idx,v,ADD_VALUES);
340: mstart++;
341: }
343: if (mend == M) {
344: mend--;
345: idx[0] = M-1; idx[1] = 0;
346: MatSetValues(A,1,&mend,2,idx,v,ADD_VALUES);
347: }
349: for (i=mstart; i<mend; i++) {
350: idx[0] = i; idx[1] = i+1;
351: MatSetValues(A,1,&i,2,idx,v,ADD_VALUES);
352: }
353: }
356: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
357: Complete the matrix assembly process and set some options
358: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
359: /*
360: Assemble matrix, using the 2-step process:
361: MatAssemblyBegin(), MatAssemblyEnd()
362: Computations can be done while messages are in transition
363: by placing code between these two statements.
364: */
365: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
366: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
368: /*
369: Set and option to indicate that we will never add a new nonzero location
370: to the matrix. If we do, it will generate an error.
371: */
372: MatSetOption(A,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
373: return 0;
374: }