Actual source code: ex5.c
1: /*$Id: ex5.c,v 1.142 2001/08/07 21:31:17 bsmith Exp $*/
3: /* Program usage: mpirun -np <procs> ex5 [-help] [all PETSc options] */
5: static char help[] = "Bratu nonlinear PDE in 2d.n
6: We solve the Bratu (SFI - solid fuel ignition) problem in a 2D rectangularn
7: domain, using distributed arrays (DAs) to partition the parallel grid.n
8: The command line options include:n
9: -par <parameter>, where <parameter> indicates the problem's nonlinearityn
10: problem SFI: <parameter> = Bratu parameter (0 <= par <= 6.81)nn";
12: /*T
13: Concepts: SNES^parallel Bratu example
14: Concepts: DA^using distributed arrays;
15: Processors: n
16: T*/
18: /* ------------------------------------------------------------------------
20: Solid Fuel Ignition (SFI) problem. This problem is modeled by
21: the partial differential equation
22:
23: -Laplacian u - lambda*exp(u) = 0, 0 < x,y < 1,
24:
25: with boundary conditions
26:
27: u = 0 for x = 0, x = 1, y = 0, y = 1.
28:
29: A finite difference approximation with the usual 5-point stencil
30: is used to discretize the boundary value problem to obtain a nonlinear
31: system of equations.
34: ------------------------------------------------------------------------- */
36: /*
37: Include "petscda.h" so that we can use distributed arrays (DAs).
38: Include "petscsnes.h" so that we can use SNES solvers. Note that this
39: file automatically includes:
40: petsc.h - base PETSc routines petscvec.h - vectors
41: petscsys.h - system routines petscmat.h - matrices
42: petscis.h - index sets petscksp.h - Krylov subspace methods
43: petscviewer.h - viewers petscpc.h - preconditioners
44: petscsles.h - linear solvers
45: */
46: #include petscda.h
47: #include petscsnes.h
49: /*
50: User-defined application context - contains data needed by the
51: application-provided call-back routines, FormJacobian() and
52: FormFunction().
53: */
54: typedef struct {
55: DA da; /* distributed array data structure */
56: PassiveReal param; /* test problem parameter */
57: } AppCtx;
59: /*
60: User-defined routines
61: */
62: extern int FormFunction(SNES,Vec,Vec,void*),FormInitialGuess(AppCtx*,Vec),FormFunctionMatlab(SNES,Vec,Vec,void*);
63: extern int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
64: extern int FormFunctionLocal(DALocalInfo*,PetscScalar**,PetscScalar**,AppCtx*);
65: extern int FormJacobianLocal(DALocalInfo*,PetscScalar**,Mat,AppCtx*);
67: int main(int argc,char **argv)
68: {
69: SNES snes; /* nonlinear solver */
70: Vec x,r; /* solution, residual vectors */
71: Mat A,J; /* Jacobian matrix */
72: AppCtx user; /* user-defined work context */
73: int its; /* iterations for convergence */
74: PetscTruth local_function = PETSC_TRUE,global_function = PETSC_FALSE,matlab_function = PETSC_FALSE;
75: PetscTruth fd_jacobian = PETSC_FALSE,global_jacobian=PETSC_FALSE,local_jacobian=PETSC_TRUE,adic_jacobian=PETSC_FALSE;
76: PetscTruth adicmf_jacobian = PETSC_FALSE;
77: int ierr;
78: PetscReal bratu_lambda_max = 6.81,bratu_lambda_min = 0.,fnorm;
79: MatFDColoring matfdcoloring = 0;
80: ISColoring iscoloring;
83:
84: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85: Initialize program
86: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
88: PetscInitialize(&argc,&argv,(char *)0,help);
90: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
91: Initialize problem parameters
92: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
93: user.param = 6.0;
94: PetscOptionsGetReal(PETSC_NULL,"-par",&user.param,PETSC_NULL);
95: if (user.param >= bratu_lambda_max || user.param <= bratu_lambda_min) {
96: SETERRQ(1,"Lambda is out of range");
97: }
99: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100: Create nonlinear solver context
101: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102: SNESCreate(PETSC_COMM_WORLD,&snes);
104: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
105: Create distributed array (DA) to manage parallel grid and vectors
106: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
107: DACreate2d(PETSC_COMM_WORLD,DA_NONPERIODIC,DA_STENCIL_STAR,-4,-4,PETSC_DECIDE,PETSC_DECIDE,
108: 1,1,PETSC_NULL,PETSC_NULL,&user.da);
110: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111: Extract global vectors from DA; then duplicate for remaining
112: vectors that are the same types
113: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
114: DACreateGlobalVector(user.da,&x);
115: VecDuplicate(x,&r);
117: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118: Set local function evaluation routine
119: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
120: DASetLocalFunction(user.da,(DALocalFunction1)FormFunctionLocal);
121: DASetLocalJacobian(user.da,(DALocalFunction1)FormJacobianLocal);
122: DASetLocalAdicFunction(user.da,ad_FormFunctionLocal);
124: /* Decide which FormFunction to use */
125: PetscOptionsGetLogical(PETSC_NULL,"-matlab_function",&matlab_function,0);
126: PetscOptionsGetLogical(PETSC_NULL,"-global_function",&global_function,0);
127: PetscOptionsGetLogical(PETSC_NULL,"-local_function",&local_function,0);
129: if (global_function) {
130: SNESSetFunction(snes,r,FormFunction,&user);
131: #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
132: } else if (matlab_function) {
133: SNESSetFunction(snes,r,FormFunctionMatlab,&user);
134: #endif
135: } else if (local_function) {
136: SNESSetFunction(snes,r,SNESDAFormFunction,&user);
137: }
139: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
140: Create matrix data structure; set Jacobian evaluation routine
142: Set Jacobian matrix data structure and default Jacobian evaluation
143: routine. User can override with:
144: -snes_mf : matrix-free Newton-Krylov method with no preconditioning
145: (unless user explicitly sets preconditioner)
146: -snes_mf_operator : form preconditioning matrix as set by the user,
147: but use matrix-free approx for Jacobian-vector
148: products within Newton-Krylov method
150: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
151: DAGetMatrix(user.da,MATMPIAIJ,&J);
152: A = J;
154: PetscOptionsGetLogical(PETSC_NULL,"-fd_jacobian",&fd_jacobian,0);
155: PetscOptionsGetLogical(PETSC_NULL,"-adic_jacobian",&adic_jacobian,0);
156: PetscOptionsGetLogical(PETSC_NULL,"-global_jacobian",&global_jacobian,0);
157: PetscOptionsGetLogical(PETSC_NULL,"-local_jacobian",&local_jacobian,0);
159: PetscOptionsGetLogical(PETSC_NULL,"-adicmf_jacobian",&adicmf_jacobian,0);
160: #if defined(PETSC_HAVE_ADIC) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
161: if (adicmf_jacobian) {
162: DASetLocalAdicMFFunction(user.da,admf_FormFunctionLocal);
163: MatRegisterDAAD();
164: MatCreateDAAD(user.da,&A);
165: MatDAADSetSNES(A,snes);
166: MatDAADSetCtx(A,&user);
167: }
168: #endif
170: if (fd_jacobian) {
171: DAGetColoring(user.da,IS_COLORING_LOCAL,&iscoloring);
172: MatFDColoringCreate(J,iscoloring,&matfdcoloring);
173: ISColoringDestroy(iscoloring);
174: MatFDColoringSetFunction(matfdcoloring,(int (*)(void))FormFunction,&user);
175: MatFDColoringSetFromOptions(matfdcoloring);
176: SNESSetJacobian(snes,A,J,SNESDefaultComputeJacobianColor,matfdcoloring);
177: #if defined(PETSC_HAVE_ADIC) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
178: } else if (adic_jacobian) {
179: DAGetColoring(user.da,IS_COLORING_GHOSTED,&iscoloring);
180: MatSetColoring(J,iscoloring);
181: ISColoringDestroy(iscoloring);
182: SNESSetJacobian(snes,A,J,SNESDAComputeJacobianWithAdic,&user);
183: #endif
184: } else if (global_jacobian){
185: SNESSetJacobian(snes,A,J,FormJacobian,&user);
186: } else if (local_jacobian){
187: SNESSetJacobian(snes,A,J,SNESDAComputeJacobian,&user);
188: }
190: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191: Customize nonlinear solver; set runtime options
192: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
193: SNESSetFromOptions(snes);
195: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196: Evaluate initial guess
197: Note: The user should initialize the vector, x, with the initial guess
198: for the nonlinear solver prior to calling SNESSolve(). In particular,
199: to employ an initial guess of zero, the user should explicitly set
200: this vector to zero by calling VecSet().
201: */
202: FormInitialGuess(&user,x);
204: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
205: Solve nonlinear system
206: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
207: SNESSolve(snes,x,&its);
209: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210: Explicitly check norm of the residual of the solution
211: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
212: FormFunction(snes,x,r,(void *)&user);
213: VecNorm(r,NORM_2,&fnorm);
214: PetscPrintf(PETSC_COMM_WORLD,"Number of Newton iterations = %d fnorm %gn",its,fnorm);
216: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217: Free work space. All PETSc objects should be destroyed when they
218: are no longer needed.
219: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
221: if (A != J) {
222: MatDestroy(A);
223: }
224: MatDestroy(J);
225: if (matfdcoloring) {
226: MatFDColoringDestroy(matfdcoloring);
227: }
228: VecDestroy(x);
229: VecDestroy(r);
230: SNESDestroy(snes);
231: DADestroy(user.da);
232: PetscFinalize();
234: return(0);
235: }
236: /* ------------------------------------------------------------------- */
237: /*
238: FormInitialGuess - Forms initial approximation.
240: Input Parameters:
241: user - user-defined application context
242: X - vector
244: Output Parameter:
245: X - vector
246: */
247: int FormInitialGuess(AppCtx *user,Vec X)
248: {
249: int i,j,Mx,My,ierr,xs,ys,xm,ym;
250: PetscReal lambda,temp1,temp,hx,hy;
251: PetscScalar **x;
254: DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
255: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
257: lambda = user->param;
258: hx = 1.0/(PetscReal)(Mx-1);
259: hy = 1.0/(PetscReal)(My-1);
260: temp1 = lambda/(lambda + 1.0);
262: /*
263: Get a pointer to vector data.
264: - For default PETSc vectors, VecGetArray() returns a pointer to
265: the data array. Otherwise, the routine is implementation dependent.
266: - You MUST call VecRestoreArray() when you no longer need access to
267: the array.
268: */
269: DAVecGetArray(user->da,X,(void**)&x);
271: /*
272: Get local grid boundaries (for 2-dimensional DA):
273: xs, ys - starting grid indices (no ghost points)
274: xm, ym - widths of local grid (no ghost points)
276: */
277: DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);
279: /*
280: Compute initial guess over the locally owned part of the grid
281: */
282: for (j=ys; j<ys+ym; j++) {
283: temp = (PetscReal)(PetscMin(j,My-j-1))*hy;
284: for (i=xs; i<xs+xm; i++) {
286: if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
287: /* boundary conditions are all zero Dirichlet */
288: x[j][i] = 0.0;
289: } else {
290: x[j][i] = temp1*sqrt(PetscMin((PetscReal)(PetscMin(i,Mx-i-1))*hx,temp));
291: }
292: }
293: }
295: /*
296: Restore vector
297: */
298: DAVecRestoreArray(user->da,X,(void**)&x);
300: return(0);
301: }
302: /* ------------------------------------------------------------------- */
303: /*
304: FormFunction - Evaluates nonlinear function, F(x).
306: Input Parameters:
307: . snes - the SNES context
308: . X - input vector
309: . ptr - optional user-defined context, as set by SNESSetFunction()
311: Output Parameter:
312: . F - function vector
313: */
314: int FormFunction(SNES snes,Vec X,Vec F,void *ptr)
315: {
316: AppCtx *user = (AppCtx*)ptr;
317: int ierr,i,j,Mx,My,xs,ys,xm,ym;
318: PetscReal two = 2.0,lambda,hx,hy,hxdhy,hydhx,sc;
319: PetscScalar u,uxx,uyy,**x,**f;
320: Vec localX;
323: DAGetLocalVector(user->da,&localX);
324: DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
325: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
327: lambda = user->param;
328: hx = 1.0/(PetscReal)(Mx-1);
329: hy = 1.0/(PetscReal)(My-1);
330: sc = hx*hy*lambda;
331: hxdhy = hx/hy;
332: hydhx = hy/hx;
334: /*
335: Scatter ghost points to local vector,using the 2-step process
336: DAGlobalToLocalBegin(),DAGlobalToLocalEnd().
337: By placing code between these two statements, computations can be
338: done while messages are in transition.
339: */
340: DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
341: DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);
343: /*
344: Get pointers to vector data
345: */
346: DAVecGetArray(user->da,localX,(void**)&x);
347: DAVecGetArray(user->da,F,(void**)&f);
349: /*
350: Get local grid boundaries
351: */
352: DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);
354: /*
355: Compute function over the locally owned part of the grid
356: */
357: for (j=ys; j<ys+ym; j++) {
358: for (i=xs; i<xs+xm; i++) {
359: if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
360: f[j][i] = x[j][i];
361: } else {
362: u = x[j][i];
363: uxx = (two*u - x[j][i-1] - x[j][i+1])*hydhx;
364: uyy = (two*u - x[j-1][i] - x[j+1][i])*hxdhy;
365: f[j][i] = uxx + uyy - sc*PetscExpScalar(u);
366: }
367: }
368: }
370: /*
371: Restore vectors
372: */
373: DAVecRestoreArray(user->da,localX,(void**)&x);
374: DAVecRestoreArray(user->da,F,(void**)&f);
375: DARestoreLocalVector(user->da,&localX);
376: PetscLogFlops(11*ym*xm);
377: return(0);
378: }
379: /* ------------------------------------------------------------------- */
380: /*
381: FormFunctionLocal - Evaluates nonlinear function, F(x).
383: Process adiC: FormFunctionLocal
385: */
386: int FormFunctionLocal(DALocalInfo *info,PetscScalar **x,PetscScalar **f,AppCtx *user)
387: {
388: int ierr,i,j;
389: PetscReal two = 2.0,lambda,hx,hy,hxdhy,hydhx,sc;
390: PetscScalar u,uxx,uyy;
394: lambda = user->param;
395: hx = 1.0/(PetscReal)(info->mx-1);
396: hy = 1.0/(PetscReal)(info->my-1);
397: sc = hx*hy*lambda;
398: hxdhy = hx/hy;
399: hydhx = hy/hx;
400: /*
401: Compute function over the locally owned part of the grid
402: */
403: for (j=info->ys; j<info->ys+info->ym; j++) {
404: for (i=info->xs; i<info->xs+info->xm; i++) {
405: if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) {
406: f[j][i] = x[j][i];
407: } else {
408: u = x[j][i];
409: uxx = (two*u - x[j][i-1] - x[j][i+1])*hydhx;
410: uyy = (two*u - x[j-1][i] - x[j+1][i])*hxdhy;
411: f[j][i] = uxx + uyy - sc*PetscExpScalar(u);
412: }
413: }
414: }
416: PetscLogFlops(11*info->ym*info->xm);
417: return(0);
418: }
419: /* ------------------------------------------------------------------- */
420: /*
421: FormJacobian - Evaluates Jacobian matrix.
423: Input Parameters:
424: . snes - the SNES context
425: . x - input vector
426: . ptr - optional user-defined context, as set by SNESSetJacobian()
428: Output Parameters:
429: . A - Jacobian matrix
430: . B - optionally different preconditioning matrix
431: . flag - flag indicating matrix structure
433: */
434: int FormJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
435: {
436: AppCtx *user = (AppCtx*)ptr; /* user-defined application context */
437: Mat jac = *B; /* Jacobian matrix */
438: Vec localX;
439: int ierr,i,j;
440: MatStencil col[5],row;
441: int xs,ys,xm,ym,Mx,My;
442: PetscScalar lambda,v[5],hx,hy,hxdhy,hydhx,sc,**x;
445: DAGetLocalVector(user->da,&localX);
446: DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
447: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
449: lambda = user->param;
450: hx = 1.0/(PetscReal)(Mx-1);
451: hy = 1.0/(PetscReal)(My-1);
452: sc = hx*hy*lambda;
453: hxdhy = hx/hy;
454: hydhx = hy/hx;
457: /*
458: Scatter ghost points to local vector, using the 2-step process
459: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
460: By placing code between these two statements, computations can be
461: done while messages are in transition.
462: */
463: DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
464: DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);
466: /*
467: Get pointer to vector data
468: */
469: DAVecGetArray(user->da,localX,(void**)&x);
471: /*
472: Get local grid boundaries
473: */
474: DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);
476: /*
477: Compute entries for the locally owned part of the Jacobian.
478: - Currently, all PETSc parallel matrix formats are partitioned by
479: contiguous chunks of rows across the processors.
480: - Each processor needs to insert only elements that it owns
481: locally (but any non-local elements will be sent to the
482: appropriate processor during matrix assembly).
483: - Here, we set all entries for a particular row at once.
484: - We can set matrix entries either using either
485: MatSetValuesLocal() or MatSetValues(), as discussed above.
486: */
487: for (j=ys; j<ys+ym; j++) {
488: for (i=xs; i<xs+xm; i++) {
489: row.j = j; row.i = i;
490: /* boundary points */
491: if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
492: v[0] = 1.0;
493: MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
494: } else {
495: /* interior grid points */
496: v[0] = -hxdhy; col[0].j = j - 1; col[0].i = i;
497: v[1] = -hydhx; col[1].j = j; col[1].i = i-1;
498: v[2] = 2.0*(hydhx + hxdhy) - sc*PetscExpScalar(x[j][i]); col[2].j = row.j; col[2].i = row.i;
499: v[3] = -hydhx; col[3].j = j; col[3].i = i+1;
500:
501: v[4] = -hxdhy; col[4].j = j + 1; col[4].i = i;
502: MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);
503: }
504: }
505: }
506: DAVecRestoreArray(user->da,localX,(void**)&x);
507: DARestoreLocalVector(user->da,&localX);
509: /*
510: Assemble matrix, using the 2-step process:
511: MatAssemblyBegin(), MatAssemblyEnd().
512: */
513: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
514: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
516: /*
517: Normally since the matrix has already been assembled above; this
518: would do nothing. But in the matrix free mode -snes_mf_operator
519: this tells the "matrix-free" matrix that a new linear system solve
520: is about to be done.
521: */
523: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
524: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
526: /*
527: Set flag to indicate that the Jacobian matrix retains an identical
528: nonzero structure throughout all nonlinear iterations (although the
529: values of the entries change). Thus, we can save some work in setting
530: up the preconditioner (e.g., no need to redo symbolic factorization for
531: ILU/ICC preconditioners).
532: - If the nonzero structure of the matrix is different during
533: successive linear solves, then the flag DIFFERENT_NONZERO_PATTERN
534: must be used instead. If you are unsure whether the matrix
535: structure has changed or not, use the flag DIFFERENT_NONZERO_PATTERN.
536: - Caution: If you specify SAME_NONZERO_PATTERN, PETSc
537: believes your assertion and does not check the structure
538: of the matrix. If you erroneously claim that the structure
539: is the same when it actually is not, the new preconditioner
540: will not function correctly. Thus, use this optimization
541: feature with caution!
542: */
543: *flag = SAME_NONZERO_PATTERN;
546: /*
547: Tell the matrix we will never add a new nonzero location to the
548: matrix. If we do, it will generate an error.
549: */
550: MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR);
551: return(0);
552: }
554: /*
555: FormJacobianLocal - Evaluates Jacobian matrix.
558: */
559: int FormJacobianLocal(DALocalInfo *info,PetscScalar **x,Mat jac,AppCtx *user)
560: {
561: int ierr,i,j;
562: MatStencil col[5],row;
563: PetscScalar lambda,v[5],hx,hy,hxdhy,hydhx,sc;
566: lambda = user->param;
567: hx = 1.0/(PetscReal)(info->mx-1);
568: hy = 1.0/(PetscReal)(info->my-1);
569: sc = hx*hy*lambda;
570: hxdhy = hx/hy;
571: hydhx = hy/hx;
574: /*
575: Compute entries for the locally owned part of the Jacobian.
576: - Currently, all PETSc parallel matrix formats are partitioned by
577: contiguous chunks of rows across the processors.
578: - Each processor needs to insert only elements that it owns
579: locally (but any non-local elements will be sent to the
580: appropriate processor during matrix assembly).
581: - Here, we set all entries for a particular row at once.
582: - We can set matrix entries either using either
583: MatSetValuesLocal() or MatSetValues(), as discussed above.
584: */
585: for (j=info->ys; j<info->ys+info->ym; j++) {
586: for (i=info->xs; i<info->xs+info->xm; i++) {
587: row.j = j; row.i = i;
588: /* boundary points */
589: if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) {
590: v[0] = 1.0;
591: MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
592: } else {
593: /* interior grid points */
594: v[0] = -hxdhy; col[0].j = j - 1; col[0].i = i;
595: v[1] = -hydhx; col[1].j = j; col[1].i = i-1;
596: v[2] = 2.0*(hydhx + hxdhy) - sc*PetscExpScalar(x[j][i]); col[2].j = row.j; col[2].i = row.i;
597: v[3] = -hydhx; col[3].j = j; col[3].i = i+1;
598: v[4] = -hxdhy; col[4].j = j + 1; col[4].i = i;
599: MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);
600: }
601: }
602: }
604: /*
605: Assemble matrix, using the 2-step process:
606: MatAssemblyBegin(), MatAssemblyEnd().
607: */
608: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
609: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
610: /*
611: Tell the matrix we will never add a new nonzero location to the
612: matrix. If we do, it will generate an error.
613: */
614: MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR);
615: return(0);
616: }
618: /*
619: Variant of FormFunction() that computes the function in Matlab
620: */
621: #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
622: int FormFunctionMatlab(SNES snes,Vec X,Vec F,void *ptr)
623: {
624: AppCtx *user = (AppCtx*)ptr;
625: int ierr,Mx,My;
626: PetscReal lambda,hx,hy;
627: Vec localX,localF;
628: MPI_Comm comm;
631: DAGetLocalVector(user->da,&localX);
632: DAGetLocalVector(user->da,&localF);
633: PetscObjectSetName((PetscObject)localX,"localX");
634: PetscObjectSetName((PetscObject)localF,"localF");
635: DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
636: PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
638: lambda = user->param;
639: hx = 1.0/(PetscReal)(Mx-1);
640: hy = 1.0/(PetscReal)(My-1);
642: PetscObjectGetComm((PetscObject)snes,&comm);
643: /*
644: Scatter ghost points to local vector,using the 2-step process
645: DAGlobalToLocalBegin(),DAGlobalToLocalEnd().
646: By placing code between these two statements, computations can be
647: done while messages are in transition.
648: */
649: DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
650: DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);
651: PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(comm),(PetscObject)localX);
652: PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(comm),"localF=ex5m(localX,%18.16e,%18.16e,%18.16e)",hx,hy,lambda);
653: PetscMatlabEngineGet(PETSC_MATLAB_ENGINE_(comm),(PetscObject)localF);
655: /*
656: Insert values into global vector
657: */
658: DALocalToGlobal(user->da,localF,INSERT_VALUES,F);
659: DARestoreLocalVector(user->da,&localX);
660: DARestoreLocalVector(user->da,&localF);
661: return(0);
662: }
663: #endif