Actual source code: biharmonic.c
petsc-dev 2014-02-02
2: static char help[] = "Solves biharmonic equation in 1d.\n";
4: /*
5: Solves the equation
7: u_t = - kappa \Delta \Delta u
8: Periodic boundary conditions
10: Evolve the biharmonic heat equation:
11: ---------------
12: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 5 -mymonitor
14: Evolve with the restriction that -1 <= u <= 1; i.e. as a variational inequality
15: ---------------
16: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 5 -vi -mymonitor
18: u_t = kappa \Delta \Delta u + 6.*u*(u_x)^2 + (3*u^2 - 12) \Delta u
19: -1 <= u <= 1
20: Periodic boundary conditions
22: Evolve the Cahn-Hillard equations: double well Initial hump shrinks then grows
23: ---------------
24: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 6 -vi -kappa .00001 -ts_dt 5.96046e-06 -cahn-hillard -ts_monitor_draw_solution --mymonitor
26: Initial hump neither shrinks nor grows when degenerate (otherwise similar solution)
28: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 6 -vi -kappa .00001 -ts_dt 5.96046e-06 -cahn-hillard -degenerate -ts_monitor_draw_solution --mymonitor
30: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 6 -vi -kappa .00001 -ts_dt 5.96046e-06 -cahn-hillard -snes_vi_ignore_function_sign -ts_monitor_draw_solution --mymonitor
32: Evolve the Cahn-Hillard equations: double obstacle
33: ---------------
34: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu -draw_pause .1 -snes_converged_reason -wait -ts_type cn -da_refine 5 -vi -kappa .00001 -ts_dt 5.96046e-06 -cahn-hillard -energy 2 -snes_linesearch_monitor -vi -ts_monitor_draw_solution --mymonitor
36: Evolve the Cahn-Hillard equations: logarithmic + double well (never shrinks and then grows)
37: ---------------
38: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu --snes_converged_reason -wait -ts_type cn -da_refine 5 -vi -kappa .0001 -ts_dt 5.96046e-06 -cahn-hillard -energy 3 -snes_linesearch_monitor -theta .00000001 -vi -ts_monitor_draw_solution --ts_final_time 1. -mymonitor
40: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu --snes_converged_reason -wait -ts_type cn -da_refine 5 -vi -kappa .0001 -ts_dt 5.96046e-06 -cahn-hillard -energy 3 -snes_linesearch_monitor -theta .00000001 -vi -ts_monitor_draw_solution --ts_final_time 1. -degenerate -mymonitor
43: Evolve the Cahn-Hillard equations: logarithmic + double obstacle (never shrinks, never grows)
44: ---------------
45: ./biharmonic -ts_monitor -snes_vi_monitor -pc_type lu --snes_converged_reason -wait -ts_type cn -da_refine 5 -vi -kappa .00001 -ts_dt 5.96046e-06 -cahn-hillard -energy 4 -snes_linesearch_monitor -theta .00000001 -vi -ts_monitor_draw_solution --mymonitor
50: */
51: #include <petscdmda.h>
52: #include <petscts.h>
53: #include <petscdraw.h>
55: extern PetscErrorCode FormFunction(TS,PetscReal,Vec,Vec,void*),FormInitialSolution(DM,Vec),MyMonitor(TS,PetscInt,PetscReal,Vec,void*),MyDestroy(void**),FormJacobian(TS,PetscReal,Vec,Mat*,Mat*,MatStructure*,void*);
56: typedef struct {PetscBool cahnhillard;PetscBool degenerate;PetscReal kappa;PetscInt energy;PetscReal tol;PetscReal theta,theta_c;PetscInt truncation;PetscBool netforce; PetscDrawViewPorts *ports;} UserCtx;
60: int main(int argc,char **argv)
61: {
62: TS ts; /* nonlinear solver */
63: Vec x,r; /* solution, residual vectors */
64: Mat J; /* Jacobian matrix */
65: PetscInt steps,Mx,maxsteps = 10000000;
67: DM da;
68: PetscReal dt;
69: PetscReal vbounds[] = {-1.1,1.1};
70: PetscBool wait,vi = PETSC_FALSE,mymonitor;
71: Vec ul,uh;
72: UserCtx ctx;
74: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75: Initialize program
76: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
77: PetscInitialize(&argc,&argv,(char*)0,help);
78: ctx.kappa = 1.0;
79: PetscOptionsGetReal(NULL,"-kappa",&ctx.kappa,NULL);
80: ctx.degenerate = PETSC_FALSE;
81: PetscOptionsGetBool(NULL,"-degenerate",&ctx.degenerate,NULL);
82: ctx.cahnhillard = PETSC_FALSE;
83: PetscOptionsGetBool(NULL,"-cahn-hillard",&ctx.cahnhillard,NULL);
84: PetscOptionsGetBool(NULL,"-vi",&vi,NULL);
85: ctx.netforce = PETSC_FALSE;
86: PetscOptionsGetBool(NULL,"-netforce",&ctx.netforce,NULL);
87: ctx.energy = 1;
88: PetscOptionsInt("-energy","type of energy (1=double well, 2=double obstacle, 3=logarithmic+double well, 4=logarithmic+double obstacle)","",ctx.energy,&ctx.energy,NULL);
89: ctx.tol = 1.0e-8;
90: PetscOptionsGetReal(NULL,"-tol",&ctx.tol,NULL);
91: ctx.theta = .001;
92: ctx.theta_c = 1.0;
93: PetscOptionsGetReal(NULL,"-theta",&ctx.theta,NULL);
94: PetscOptionsGetReal(NULL,"-theta_c",&ctx.theta_c,NULL);
95: ctx.truncation = 1;
96: PetscOptionsInt("-truncation","order of log truncation (1=cubic, 2=quadratic)","",ctx.truncation,&ctx.truncation,NULL);
97: PetscOptionsHasName(NULL,"-mymonitor",&mymonitor);
98: PetscViewerDrawSetBounds(PETSC_VIEWER_DRAW_(PETSC_COMM_WORLD),1,vbounds);
99: PetscViewerDrawResize(PETSC_VIEWER_DRAW_(PETSC_COMM_WORLD),800,600);
101: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102: Create distributed array (DMDA) to manage parallel grid and vectors
103: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
104: DMDACreate1d(PETSC_COMM_WORLD, DMDA_BOUNDARY_PERIODIC, -10,1,2,NULL,&da);
105: DMDASetFieldName(da,0,"Biharmonic heat equation: u");
106: DMDAGetInfo(da,0,&Mx,0,0,0,0,0,0,0,0,0,0,0);
107: dt = 1.0/(10.*ctx.kappa*Mx*Mx*Mx*Mx);
109: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110: Extract global vectors from DMDA; then duplicate for remaining
111: vectors that are the same types
112: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
113: DMCreateGlobalVector(da,&x);
114: VecDuplicate(x,&r);
116: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
117: Create timestepping solver context
118: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
119: TSCreate(PETSC_COMM_WORLD,&ts);
120: TSSetDM(ts,da);
121: TSSetProblemType(ts,TS_NONLINEAR);
122: TSSetRHSFunction(ts,NULL,FormFunction,&ctx);
123: DMSetMatType(da,MATAIJ);
124: DMCreateMatrix(da,&J);
125: TSSetRHSJacobian(ts,J,J,FormJacobian,&ctx);
126: TSSetDuration(ts,maxsteps,.02);
127: TSSetExactFinalTime(ts,TS_EXACTFINALTIME_INTERPOLATE);
129: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
130: Create matrix data structure; set Jacobian evaluation routine
132: Set Jacobian matrix data structure and default Jacobian evaluation
133: routine. User can override with:
134: -snes_mf : matrix-free Newton-Krylov method with no preconditioning
135: (unless user explicitly sets preconditioner)
136: -snes_mf_operator : form preconditioning matrix as set by the user,
137: but use matrix-free approx for Jacobian-vector
138: products within Newton-Krylov method
140: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
141: #if defined(f00)
142: {
143: SNES snes;
144: DMCreateColoring(da,IS_COLORING_GLOBAL,&iscoloring);
145: MatFDColoringCreate(J,iscoloring,&matfdcoloring);
146: ISColoringDestroy(&iscoloring);
147: MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))SNESTSFormFunction,ts);
148: MatFDColoringSetFromOptions(matfdcoloring);
149: MatFDColoringSetUp(J,iscoloring,matfdcoloring);
150: TSGetSNES(ts,&snes);
151: SNESSetJacobian(snes,J,J,SNESComputeJacobianDefaultColor,matfdcoloring);
152: }
153: #endif
155: if (vi) {
156: VecDuplicate(x,&ul);
157: VecDuplicate(x,&uh);
158: VecSet(ul,-1.0);
159: VecSet(uh,1.0);
160: TSVISetVariableBounds(ts,ul,uh);
161: }
163: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164: Customize nonlinear solver
165: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
166: TSSetType(ts,TSCN);
168: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
169: Set initial conditions
170: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
171: FormInitialSolution(da,x);
172: TSSetInitialTimeStep(ts,0.0,dt);
173: TSSetSolution(ts,x);
175: if (mymonitor) {
176: ctx.ports = NULL;
177: TSMonitorSet(ts,MyMonitor,&ctx,MyDestroy);
178: }
180: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
181: Set runtime options
182: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
183: TSSetFromOptions(ts);
185: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
186: Solve nonlinear system
187: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
188: TSSolve(ts,x);
189: wait = PETSC_FALSE;
190: PetscOptionsGetBool(NULL,"-wait",&wait,NULL);
191: if (wait) {
192: PetscSleep(-1);
193: }
194: TSGetTimeStepNumber(ts,&steps);
195: VecView(x,PETSC_VIEWER_BINARY_WORLD);
197: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
198: Free work space. All PETSc objects should be destroyed when they
199: are no longer needed.
200: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
201: if (vi) {
202: VecDestroy(&ul);
203: VecDestroy(&uh);
204: }
205: MatDestroy(&J);
206: #if defined(f00)
207: MatFDColoringDestroy(&matfdcoloring);
208: #endif
209: VecDestroy(&x);
210: VecDestroy(&r);
211: TSDestroy(&ts);
212: DMDestroy(&da);
214: PetscFinalize();
215: return(0);
216: }
217: /* ------------------------------------------------------------------- */
220: /*
221: FormFunction - Evaluates nonlinear function, F(x).
223: Input Parameters:
224: . ts - the TS context
225: . X - input vector
226: . ptr - optional user-defined context, as set by SNESSetFunction()
228: Output Parameter:
229: . F - function vector
230: */
231: PetscErrorCode FormFunction(TS ts,PetscReal ftime,Vec X,Vec F,void *ptr)
232: {
233: DM da;
235: PetscInt i,Mx,xs,xm;
236: PetscReal hx,sx;
237: PetscScalar *x,*f,c,r,l;
238: Vec localX;
239: UserCtx *ctx = (UserCtx*)ptr;
240: PetscReal tol = ctx->tol, theta=ctx->theta,theta_c=ctx->theta_c,a,b; /* a and b are used in the cubic truncation of the log function */
243: TSGetDM(ts,&da);
244: DMGetLocalVector(da,&localX);
245: DMDAGetInfo(da,PETSC_IGNORE,&Mx,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
246: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
248: hx = 1.0/(PetscReal)Mx; sx = 1.0/(hx*hx);
250: /*
251: Scatter ghost points to local vector,using the 2-step process
252: DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
253: By placing code between these two statements, computations can be
254: done while messages are in transition.
255: */
256: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
257: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
259: /*
260: Get pointers to vector data
261: */
262: DMDAVecGetArray(da,localX,&x);
263: DMDAVecGetArray(da,F,&f);
265: /*
266: Get local grid boundaries
267: */
268: DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);
270: /*
271: Compute function over the locally owned part of the grid
272: */
273: for (i=xs; i<xs+xm; i++) {
274: if (ctx->degenerate) {
275: c = (1. - x[i]*x[i])*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
276: r = (1. - x[i+1]*x[i+1])*(x[i] + x[i+2] - 2.0*x[i+1])*sx;
277: l = (1. - x[i-1]*x[i-1])*(x[i-2] + x[i] - 2.0*x[i-1])*sx;
278: } else {
279: c = (x[i-1] + x[i+1] - 2.0*x[i])*sx;
280: r = (x[i] + x[i+2] - 2.0*x[i+1])*sx;
281: l = (x[i-2] + x[i] - 2.0*x[i-1])*sx;
282: }
283: f[i] = -ctx->kappa*(l + r - 2.0*c)*sx;
284: if (ctx->cahnhillard) {
285: switch (ctx->energy) {
286: case 1: /* double well */
287: f[i] += 6.*.25*x[i]*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (3.*x[i]*x[i] - 1.)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
288: break;
289: case 2: /* double obstacle */
290: f[i] += -(x[i-1] + x[i+1] - 2.0*x[i])*sx;
291: break;
292: case 3: /* logarithmic + double well */
293: f[i] += 6.*.25*x[i]*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (3.*x[i]*x[i] - 1.)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
294: if (ctx->truncation==2) { /* log function with approximated with a quadratic polynomial outside -1.0+2*tol, 1.0-2*tol */
295: if (PetscRealPart(x[i]) < -1.0 + 2.0*tol) f[i] += (.25*theta/(tol-tol*tol))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
296: else if (PetscRealPart(x[i]) > 1.0 - 2.0*tol) f[i] += (.25*theta/(tol-tol*tol))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
297: else f[i] += 2.0*theta*x[i]/((1.0-x[i]*x[i])*(1.0-x[i]*x[i]))*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (theta/(1.0-x[i]*x[i]))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
298: } else { /* log function is approximated with a cubic polynomial outside -1.0+2*tol, 1.0-2*tol */
299: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
300: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
301: if (PetscRealPart(x[i]) < -1.0 + 2.0*tol) f[i] += -1.0*a*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (-1.0*a*x[i] + b)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
302: else if (PetscRealPart(x[i]) > 1.0 - 2.0*tol) f[i] += 1.0*a*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + ( a*x[i] + b)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
303: else f[i] += 2.0*theta*x[i]/((1.0-x[i]*x[i])*(1.0-x[i]*x[i]))*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (theta/(1.0-x[i]*x[i]))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
304: }
305: break;
306: case 4: /* logarithmic + double obstacle */
307: f[i] += -theta_c*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
308: if (ctx->truncation==2) { /* quadratic */
309: if (PetscRealPart(x[i]) < -1.0 + 2.0*tol) f[i] += (.25*theta/(tol-tol*tol))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
310: else if (PetscRealPart(x[i]) > 1.0 - 2.0*tol) f[i] += (.25*theta/(tol-tol*tol))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
311: else f[i] += 2.0*theta*x[i]/((1.0-x[i]*x[i])*(1.0-x[i]*x[i]))*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (theta/(1.0-x[i]*x[i]))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
312: } else { /* cubic */
313: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
314: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
315: if (PetscRealPart(x[i]) < -1.0 + 2.0*tol) f[i] += -1.0*a*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (-1.0*a*x[i] + b)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
316: else if (PetscRealPart(x[i]) > 1.0 - 2.0*tol) f[i] += 1.0*a*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + ( a*x[i] + b)*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
317: else f[i] += 2.0*theta*x[i]/((1.0-x[i]*x[i])*(1.0-x[i]*x[i]))*.25*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (theta/(1.0-x[i]*x[i]))*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
318: }
319: break;
320: }
321: }
323: }
325: /*
326: Restore vectors
327: */
328: DMDAVecRestoreArray(da,localX,&x);
329: DMDAVecRestoreArray(da,F,&f);
330: DMRestoreLocalVector(da,&localX);
331: return(0);
332: }
334: /* ------------------------------------------------------------------- */
337: /*
338: FormJacobian - Evaluates nonlinear function's Jacobian
340: */
341: PetscErrorCode FormJacobian(TS ts,PetscReal ftime,Vec X,Mat *A,Mat *B,MatStructure *str,void *ptr)
342: {
343: DM da;
345: PetscInt i,Mx,xs,xm;
346: MatStencil row,cols[5];
347: PetscReal hx,sx;
348: PetscScalar *x,vals[5];
349: Vec localX;
350: UserCtx *ctx = (UserCtx*)ptr;
353: TSGetDM(ts,&da);
354: DMGetLocalVector(da,&localX);
355: DMDAGetInfo(da,PETSC_IGNORE,&Mx,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
356: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
358: hx = 1.0/(PetscReal)Mx; sx = 1.0/(hx*hx);
360: /*
361: Scatter ghost points to local vector,using the 2-step process
362: DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
363: By placing code between these two statements, computations can be
364: done while messages are in transition.
365: */
366: DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);
367: DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);
369: /*
370: Get pointers to vector data
371: */
372: DMDAVecGetArray(da,localX,&x);
374: /*
375: Get local grid boundaries
376: */
377: DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);
379: /*
380: Compute function over the locally owned part of the grid
381: */
382: for (i=xs; i<xs+xm; i++) {
383: row.i = i;
384: if (ctx->degenerate) {
385: /*PetscScalar c,r,l;
386: c = (1. - x[i]*x[i])*(x[i-1] + x[i+1] - 2.0*x[i])*sx;
387: r = (1. - x[i+1]*x[i+1])*(x[i] + x[i+2] - 2.0*x[i+1])*sx;
388: l = (1. - x[i-1]*x[i-1])*(x[i-2] + x[i] - 2.0*x[i-1])*sx; */
389: } else {
390: cols[0].i = i - 2; vals[0] = -ctx->kappa*sx*sx;
391: cols[1].i = i - 1; vals[1] = 4.0*ctx->kappa*sx*sx;
392: cols[2].i = i ; vals[2] = -6.0*ctx->kappa*sx*sx;
393: cols[3].i = i + 1; vals[3] = 4.0*ctx->kappa*sx*sx;
394: cols[4].i = i + 2; vals[4] = -ctx->kappa*sx*sx;
395: }
396: MatSetValuesStencil(*B,1,&row,5,cols,vals,INSERT_VALUES);
398: if (ctx->cahnhillard) {
399: switch (ctx->energy) {
400: case 1: /* double well */
401: /* f[i] += 6.*.25*x[i]*(x[i+1] - x[i-1])*(x[i+1] - x[i-1])*sx + (3.*x[i]*x[i] - 1.)*(x[i-1] + x[i+1] - 2.0*x[i])*sx; */
402: break;
403: case 2: /* double obstacle */
404: /* f[i] += -(x[i-1] + x[i+1] - 2.0*x[i])*sx; */
405: break;
406: case 3: /* logarithmic + double well */
407: break;
408: case 4: /* logarithmic + double obstacle */
409: break;
410: }
411: }
413: }
415: /*
416: Restore vectors
417: */
418: DMDAVecRestoreArray(da,localX,&x);
419: DMRestoreLocalVector(da,&localX);
420: MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
421: MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
422: if (*A != *B) {
423: MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);
424: MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);
425: }
426: return(0);
427: }
428: /* ------------------------------------------------------------------- */
431: PetscErrorCode FormInitialSolution(DM da,Vec U)
432: {
433: PetscErrorCode ierr;
434: PetscInt i,xs,xm,Mx,N,scale;
435: PetscScalar *u;
436: PetscReal r,hx,x;
437: const PetscScalar *f;
438: Vec finesolution;
439: PetscViewer viewer;
442: DMDAGetInfo(da,PETSC_IGNORE,&Mx,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
443: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
445: hx = 1.0/(PetscReal)Mx;
447: /*
448: Get pointers to vector data
449: */
450: DMDAVecGetArray(da,U,&u);
452: /*
453: Get local grid boundaries
454: */
455: DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);
457: /* InitialSolution.biharmonic is obtained by running
458: ./heat -square_initial -ts_monitor -snes_monitor -pc_type lu -snes_converged_reason -ts_type cn -da_refine 9 -ts_final_time 1.e-4 -ts_dt .125e-6 -snes_atol 1.e-25 -snes_rtol 1.e-25 -ts_max_steps 30
459: After changing the initial grid spacing to 10 and the stencil width to 2 in the DMDA create.
460: */
461: PetscViewerBinaryOpen(PETSC_COMM_WORLD,"InitialSolution.biharmonic",FILE_MODE_READ,&viewer);
462: VecCreate(PETSC_COMM_WORLD,&finesolution);
463: VecLoad(finesolution,viewer);
464: PetscViewerDestroy(&viewer);
465: VecGetSize(finesolution,&N);
466: scale = N/Mx;
467: VecGetArrayRead(finesolution,&f);
469: /*
470: Compute function over the locally owned part of the grid
471: */
472: for (i=xs; i<xs+xm; i++) {
473: x = i*hx;
474: r = PetscSqrtReal((x-.5)*(x-.5));
475: if (r < .125) u[i] = 1.0;
476: else u[i] = -.5;
478: /* With the initial condition above the method is first order in space */
479: /* this is a smooth initial condition so the method becomes second order in space */
480: /*u[i] = PetscSinScalar(2*PETSC_PI*x); */
481: u[i] = f[scale*i];
482: }
483: VecRestoreArrayRead(finesolution,&f);
484: VecDestroy(&finesolution);
486: /*
487: Restore vectors
488: */
489: DMDAVecRestoreArray(da,U,&u);
490: return(0);
491: }
495: /*
496: This routine is not parallel
497: */
498: PetscErrorCode MyMonitor(TS ts,PetscInt step,PetscReal time,Vec U,void *ptr)
499: {
500: UserCtx *ctx = (UserCtx*)ptr;
501: PetscDrawLG lg;
503: PetscScalar *u,l,r,c;
504: PetscInt Mx,i,xs,xm,cnt;
505: PetscReal x,y,hx,pause,sx,len,max,xx[4],yy[4],xx_netforce,yy_netforce,yup,ydown,y2,len2;
506: PetscDraw draw;
507: Vec localU;
508: DM da;
509: int colors[] = {PETSC_DRAW_YELLOW,PETSC_DRAW_RED,PETSC_DRAW_BLUE,PETSC_DRAW_PLUM,PETSC_DRAW_BLACK};
510: /*
511: const char *const legend[3][3] = {{"-kappa (\\grad u,\\grad u)","(1 - u^2)^2"},{"-kappa (\\grad u,\\grad u)","(1 - u^2)"},{"-kappa (\\grad u,\\grad u)","logarithmic"}};
512: */
513: PetscDrawAxis axis;
514: PetscDrawViewPorts *ports;
515: PetscReal tol = ctx->tol, theta=ctx->theta,theta_c=ctx->theta_c,a,b; /* a and b are used in the cubic truncation of the log function */
519: TSGetDM(ts,&da);
520: DMGetLocalVector(da,&localU);
521: DMDAGetInfo(da,PETSC_IGNORE,&Mx,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
522: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
523: DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);
524: hx = 1.0/(PetscReal)Mx; sx = 1.0/(hx*hx);
525: DMGlobalToLocalBegin(da,U,INSERT_VALUES,localU);
526: DMGlobalToLocalEnd(da,U,INSERT_VALUES,localU);
527: DMDAVecGetArray(da,localU,&u);
529: PetscViewerDrawGetDrawLG(PETSC_VIEWER_DRAW_(PETSC_COMM_WORLD),1,&lg);
530: PetscDrawLGGetDraw(lg,&draw);
531: PetscDrawCheckResizedWindow(draw);
532: if (!ctx->ports) {
533: PetscDrawViewPortsCreateRect(draw,1,3,&ctx->ports);
534: }
535: ports = ctx->ports;
536: PetscDrawLGGetAxis(lg,&axis);
537: PetscDrawLGReset(lg);
539: xx[0] = 0.0; xx[1] = 1.0; cnt = 2;
540: PetscOptionsGetRealArray(NULL,"-zoom",xx,&cnt,NULL);
541: xs = xx[0]/hx; xm = (xx[1] - xx[0])/hx;
543: /*
544: Plot the energies
545: */
546: PetscDrawLGSetDimension(lg,1 + (ctx->cahnhillard ? 1 : 0) + (ctx->energy == 3));
547: PetscDrawLGSetColors(lg,colors+1);
548: PetscDrawViewPortsSet(ports,2);
549: x = hx*xs;
550: for (i=xs; i<xs+xm; i++) {
551: xx[0] = xx[1] = xx[2] = x;
552: if (ctx->degenerate) yy[0] = PetscRealPart(.25*(1. - u[i]*u[i])*ctx->kappa*(u[i-1] - u[i+1])*(u[i-1] - u[i+1])*sx);
553: else yy[0] = PetscRealPart(.25*ctx->kappa*(u[i-1] - u[i+1])*(u[i-1] - u[i+1])*sx);
555: if (ctx->cahnhillard) {
556: switch (ctx->energy) {
557: case 1: /* double well */
558: yy[1] = .25*PetscRealPart((1. - u[i]*u[i])*(1. - u[i]*u[i]));
559: break;
560: case 2: /* double obstacle */
561: yy[1] = .5*PetscRealPart(1. - u[i]*u[i]);
562: break;
563: case 3: /* logarithm + double well */
564: yy[1] = .25*PetscRealPart((1. - u[i]*u[i])*(1. - u[i]*u[i]));
565: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = .5*theta*(2.0*tol*PetscLogReal(tol) + PetscRealPart(1.0-u[i])*PetscLogReal(PetscRealPart(1.-u[i])/2.0));
566: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = .5*theta*(PetscRealPart(1.0+u[i])*PetscLogReal(PetscRealPart(1.0+u[i])/2.0) + 2.0*tol*PetscLogReal(tol));
567: else yy[2] = .5*theta*(PetscRealPart(1.0+u[i])*PetscLogReal(PetscRealPart(1.0+u[i])/2.0) + PetscRealPart(1.0-u[i])*PetscLogReal(PetscRealPart(1.0-u[i])/2.0));
568: break;
569: case 4: /* logarithm + double obstacle */
570: yy[1] = .5*theta_c*PetscRealPart(1.0-u[i]*u[i]);
571: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = .5*theta*(2.0*tol*PetscLogReal(tol) + PetscRealPart(1.0-u[i])*PetscLogReal(PetscRealPart(1.-u[i])/2.0));
572: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = .5*theta*(PetscRealPart(1.0+u[i])*PetscLogReal(PetscRealPart(1.0+u[i])/2.0) + 2.0*tol*PetscLogReal(tol));
573: else yy[2] = .5*theta*(PetscRealPart(1.0+u[i])*PetscLogReal(PetscRealPart(1.0+u[i])/2.0) + PetscRealPart(1.0-u[i])*PetscLogReal(PetscRealPart(1.0-u[i])/2.0));
574: break;
575: }
576: }
577: PetscDrawLGAddPoint(lg,xx,yy);
578: x += hx;
579: }
580: PetscDrawGetPause(draw,&pause);
581: PetscDrawSetPause(draw,0.0);
582: PetscDrawAxisSetLabels(axis,"Energy","","");
583: /* PetscDrawLGSetLegend(lg,legend[ctx->energy-1]); */
584: PetscDrawLGDraw(lg);
586: /*
587: Plot the forces
588: */
589: PetscDrawLGSetDimension(lg,0 + (ctx->cahnhillard ? 2 : 0) + (ctx->energy == 3));
590: PetscDrawLGSetColors(lg,colors+1);
591: PetscDrawViewPortsSet(ports,1);
592: PetscDrawLGReset(lg);
593: x = xs*hx;
594: max = 0.;
595: for (i=xs; i<xs+xm; i++) {
596: xx[0] = xx[1] = xx[2] = xx[3] = x;
597: xx_netforce = x;
598: if (ctx->degenerate) {
599: c = (1. - u[i]*u[i])*(u[i-1] + u[i+1] - 2.0*u[i])*sx;
600: r = (1. - u[i+1]*u[i+1])*(u[i] + u[i+2] - 2.0*u[i+1])*sx;
601: l = (1. - u[i-1]*u[i-1])*(u[i-2] + u[i] - 2.0*u[i-1])*sx;
602: } else {
603: c = (u[i-1] + u[i+1] - 2.0*u[i])*sx;
604: r = (u[i] + u[i+2] - 2.0*u[i+1])*sx;
605: l = (u[i-2] + u[i] - 2.0*u[i-1])*sx;
606: }
607: yy[0] = PetscRealPart(-ctx->kappa*(l + r - 2.0*c)*sx);
608: yy_netforce = yy[0];
609: max = PetscMax(max,PetscAbs(yy[0]));
610: if (ctx->cahnhillard) {
611: switch (ctx->energy) {
612: case 1: /* double well */
613: yy[1] = PetscRealPart(6.*.25*u[i]*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (3.*u[i]*u[i] - 1.)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
614: break;
615: case 2: /* double obstacle */
616: yy[1] = -PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx;
617: break;
618: case 3: /* logarithmic + double well */
619: yy[1] = PetscRealPart(6.*.25*u[i]*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (3.*u[i]*u[i] - 1.)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
620: if (ctx->truncation==2) { /* quadratic */
621: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = (.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx;
622: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = (.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx;
623: else yy[2] = PetscRealPart(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
624: } else { /* cubic */
625: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
626: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
627: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = PetscRealPart(-1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (-1.0*a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
628: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = PetscRealPart(1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + ( a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
629: else yy[2] = PetscRealPart(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
630: }
631: break;
632: case 4: /* logarithmic + double obstacle */
633: yy[1] = theta_c*PetscRealPart(-(u[i-1] + u[i+1] - 2.0*u[i]))*sx;
634: if (ctx->truncation==2) {
635: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = (.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx;
636: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = (.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx;
637: else yy[2] = PetscRealPart(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
638: }
639: else {
640: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
641: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
642: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) yy[2] = PetscRealPart(-1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (-1.0*a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
643: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) yy[2] = PetscRealPart(1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + ( a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
644: else yy[2] = PetscRealPart(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx);
645: }
646: break;
647: }
648: if (ctx->energy < 3) {
649: max = PetscMax(max,PetscAbs(yy[1]));
650: yy[2] = yy[0]+yy[1];
651: yy_netforce = yy[2];
652: } else {
653: max = PetscMax(max,PetscAbs(yy[1]+yy[2]));
654: yy[3] = yy[0]+yy[1]+yy[2];
655: yy_netforce = yy[3];
656: }
657: }
658: if (ctx->netforce) {
659: PetscDrawLGAddPoint(lg,&xx_netforce,&yy_netforce);
660: } else {
661: PetscDrawLGAddPoint(lg,xx,yy);
662: }
663: x += hx;
664: /*if (max > 7200150000.0) */
665: /* printf("max very big when i = %d\n",i); */
666: }
667: PetscDrawAxisSetLabels(axis,"Right hand side","","");
668: PetscDrawLGSetLegend(lg,NULL);
669: PetscDrawLGDraw(lg);
671: /*
672: Plot the solution
673: */
674: PetscDrawLGSetDimension(lg,1);
675: PetscDrawViewPortsSet(ports,0);
676: PetscDrawLGReset(lg);
677: x = hx*xs;
678: PetscDrawLGSetLimits(lg,x,x+(xm-1)*hx,-1.1,1.1);
679: PetscDrawLGSetColors(lg,colors);
680: for (i=xs; i<xs+xm; i++) {
681: xx[0] = x;
682: yy[0] = PetscRealPart(u[i]);
683: PetscDrawLGAddPoint(lg,xx,yy);
684: x += hx;
685: }
686: PetscDrawAxisSetLabels(axis,"Solution","","");
687: PetscDrawLGDraw(lg);
689: /*
690: Print the forces as arrows on the solution
691: */
692: x = hx*xs;
693: cnt = xm/60;
694: cnt = (!cnt) ? 1 : cnt;
696: for (i=xs; i<xs+xm; i += cnt) {
697: y = yup = ydown = PetscRealPart(u[i]);
698: c = (u[i-1] + u[i+1] - 2.0*u[i])*sx;
699: r = (u[i] + u[i+2] - 2.0*u[i+1])*sx;
700: l = (u[i-2] + u[i] - 2.0*u[i-1])*sx;
701: len = -.5*PetscRealPart(ctx->kappa*(l + r - 2.0*c)*sx)/max;
702: PetscDrawArrow(draw,x,y,x,y+len,PETSC_DRAW_RED);
703: if (ctx->cahnhillard) {
704: if (len < 0.) ydown += len;
705: else yup += len;
707: switch (ctx->energy) {
708: case 1: /* double well */
709: len = .5*PetscRealPart(6.*.25*u[i]*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (3.*u[i]*u[i] - 1.)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max;
710: break;
711: case 2: /* double obstacle */
712: len = -.5*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx/max;
713: break;
714: case 3: /* logarithmic + double well */
715: len = .5*PetscRealPart(6.*.25*u[i]*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (3.*u[i]*u[i] - 1.)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max;
716: if (len < 0.) ydown += len;
717: else yup += len;
719: if (ctx->truncation==2) { /* quadratic */
720: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) len2 = .5*(.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx/max;
721: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) len2 = .5*(.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx/max;
722: else len2 = PetscRealPart(.5*(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max);
723: } else { /* cubic */
724: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
725: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
726: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) len2 = PetscRealPart(.5*(-1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (-1.0*a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max);
727: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) len2 = PetscRealPart(.5*(a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + ( a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max);
728: else len2 = PetscRealPart(.5*(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max);
729: }
730: y2 = len < 0 ? ydown : yup;
731: PetscDrawArrow(draw,x,y2,x,y2+len2,PETSC_DRAW_PLUM);
732: break;
733: case 4: /* logarithmic + double obstacle */
734: len = -.5*theta_c*PetscRealPart(-(u[i-1] + u[i+1] - 2.0*u[i])*sx/max);
735: if (len < 0.) ydown += len;
736: else yup += len;
738: if (ctx->truncation==2) { /* quadratic */
739: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) len2 = .5*(.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx/max;
740: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) len2 = .5*(.25*theta/(tol-tol*tol))*PetscRealPart(u[i-1] + u[i+1] - 2.0*u[i])*sx/max;
741: else len2 = PetscRealPart(.5*(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max);
742: } else { /* cubic */
743: a = 2.0*theta*(1.0-2.0*tol)/(16.0*tol*tol*(1.0-tol)*(1.0-tol));
744: b = theta/(4.0*tol*(1.0-tol)) - a*(1.0-2.0*tol);
745: if (PetscRealPart(u[i]) < -1.0 + 2.0*tol) len2 = .5*PetscRealPart(-1.0*a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (-1.0*a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max;
746: else if (PetscRealPart(u[i]) > 1.0 - 2.0*tol) len2 = .5*PetscRealPart(a*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + ( a*u[i] + b)*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max;
747: else len2 = .5*PetscRealPart(2.0*theta*u[i]/((1.0-u[i]*u[i])*(1.0-u[i]*u[i]))*.25*(u[i+1] - u[i-1])*(u[i+1] - u[i-1])*sx + (theta/(1.0-u[i]*u[i]))*(u[i-1] + u[i+1] - 2.0*u[i])*sx)/max;
748: }
749: y2 = len < 0 ? ydown : yup;
750: PetscDrawArrow(draw,x,y2,x,y2+len2,PETSC_DRAW_PLUM);
751: break;
752: }
753: PetscDrawArrow(draw,x,y,x,y+len,PETSC_DRAW_BLUE);
754: }
755: x += cnt*hx;
756: }
757: DMDAVecRestoreArray(da,localU,&x);
758: DMRestoreLocalVector(da,&localU);
759: PetscDrawStringSetSize(draw,.2,.2);
760: PetscDrawFlush(draw);
761: PetscDrawSetPause(draw,pause);
762: PetscDrawPause(draw);
763: return(0);
764: }
768: PetscErrorCode MyDestroy(void **ptr)
769: {
770: UserCtx *ctx = *(UserCtx**)ptr;
774: PetscDrawViewPortsDestroy(ctx->ports);
775: return(0);
776: }