Actual source code: minsurf2.c
petsc-dev 2014-02-02
1: /* Program usage: mpirun -np <proc> minsurf2 [-help] [all TAO options] */
3: /*
4: Include "petsctao.h" so we can use TAO solvers.
5: petscdmda.h for distributed array
6: */
7: #include <petsctao.h>
8: #include <petscdmda.h>
10: static char help[] =
11: "This example demonstrates use of the TAO package to \n\
12: solve an unconstrained minimization problem. This example is based on a \n\
13: problem from the MINPACK-2 test suite. Given a rectangular 2-D domain and \n\
14: boundary values along the edges of the domain, the objective is to find the\n\
15: surface with the minimal area that satisfies the boundary conditions.\n\
16: The command line options are:\n\
17: -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\
18: -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\
19: -start <st>, where <st> =0 for zero vector, <st> >0 for random start, and <st> <0 \n\
20: for an average of the boundary conditions\n\n";
22: /*T
23: Concepts: TAO^Solving an unconstrained minimization problem
24: Routines: TaoCreate(); TaoSetType();
25: Routines: TaoSetInitialVector();
26: Routines: TaoSetObjectiveAndGradientRoutine();
27: Routines: TaoSetHessianRoutine(); TaoSetFromOptions();
28: Routines: TaoSetMonitor();
29: Routines: TaoSolve(); TaoView();
30: Routines: TaoGetTerminationReason(); TaoDestroy();
31: Processors: n
32: T*/
34: /*
35: User-defined application context - contains data needed by the
36: application-provided call-back routines, FormFunctionGradient()
37: and FormHessian().
38: */
39: typedef struct {
40: PetscInt mx, my; /* discretization in x, y directions */
41: PetscReal *bottom, *top, *left, *right; /* boundary values */
42: DM dm; /* distributed array data structure */
43: Mat H; /* Hessian */
44: } AppCtx;
47: /* -------- User-defined Routines --------- */
49: static PetscErrorCode MSA_BoundaryConditions(AppCtx*);
50: static PetscErrorCode MSA_InitialPoint(AppCtx*,Vec);
51: PetscErrorCode QuadraticH(AppCtx*,Vec,Mat);
52: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal *,Vec,void*);
53: PetscErrorCode FormGradient(Tao,Vec,Vec,void*);
54: PetscErrorCode FormHessian(Tao,Vec,Mat*,Mat*,MatStructure *,void*);
55: PetscErrorCode My_Monitor(Tao, void *);
59: int main( int argc, char **argv )
60: {
61: PetscErrorCode ierr; /* used to check for functions returning nonzeros */
62: PetscInt Nx, Ny; /* number of processors in x- and y- directions */
63: Vec x; /* solution, gradient vectors */
64: PetscBool flg, viewmat; /* flags */
65: PetscBool fddefault, fdcoloring; /* flags */
66: TaoTerminationReason reason;
67: Tao tao; /* TAO solver context */
68: AppCtx user; /* user-defined work context */
69: ISColoring iscoloring;
70: MatFDColoring matfdcoloring;
72: /* Initialize TAO */
73: PetscInitialize( &argc, &argv,(char *)0,help );
75: /* Specify dimension of the problem */
76: user.mx = 10; user.my = 10;
78: /* Check for any command line arguments that override defaults */
79: PetscOptionsGetInt(NULL,"-mx",&user.mx,&flg);
80: PetscOptionsGetInt(NULL,"-my",&user.my,&flg);
82: PetscPrintf(MPI_COMM_WORLD,"\n---- Minimum Surface Area Problem -----\n");
83: PetscPrintf(MPI_COMM_WORLD,"mx: %D my: %D \n\n",user.mx,user.my);
86: /* Let PETSc determine the vector distribution */
87: Nx = PETSC_DECIDE; Ny = PETSC_DECIDE;
89: /* Create distributed array (DM) to manage parallel grid and vectors */
90: DMDACreate2d(PETSC_COMM_WORLD,DMDA_BOUNDARY_NONE,DMDA_BOUNDARY_NONE,DMDA_STENCIL_BOX,user.mx, user.my,Nx,Ny,1,1,NULL,NULL,&user.dm);
93: /* Create TAO solver and set desired solution method.*/
94: TaoCreate(PETSC_COMM_WORLD,&tao);
95: TaoSetType(tao,"tao_cg");
97: /*
98: Extract global vector from DA for the vector of variables -- PETSC routine
99: Compute the initial solution -- application specific, see below
100: Set this vector for use by TAO -- TAO routine
101: */
102: DMCreateGlobalVector(user.dm,&x);
103: MSA_BoundaryConditions(&user);
104: MSA_InitialPoint(&user,x);
105: TaoSetInitialVector(tao,x);
107: /*
108: Initialize the Application context for use in function evaluations -- application specific, see below.
109: Set routines for function and gradient evaluation
110: */
111: TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);
113: /*
114: Given the command line arguments, calculate the hessian with either the user-
115: provided function FormHessian, or the default finite-difference driven Hessian
116: functions
117: */
118: PetscOptionsHasName(NULL,"-tao_fddefault",&fddefault);
119: PetscOptionsHasName(NULL,"-tao_fdcoloring",&fdcoloring);
122: /*
123: Create a matrix data structure to store the Hessian and set
124: the Hessian evalution routine.
125: Set the matrix structure to be used for Hessian evalutions
126: */
127: DMCreateMatrix(user.dm,&user.H);
128: MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE);
131: if (fdcoloring) {
132: DMCreateColoring(user.dm,IS_COLORING_GLOBAL,&iscoloring);
133:
135: MatFDColoringCreate(user.H,iscoloring,&matfdcoloring);
136:
138: ISColoringDestroy(&iscoloring);
139: MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))FormGradient,(void*)&user);
140: MatFDColoringSetFromOptions(matfdcoloring);
142: TaoSetHessianRoutine(tao,user.H,user.H,TaoDefaultComputeHessianColor,(void *)matfdcoloring);
144: } else if (fddefault){
145: TaoSetHessianRoutine(tao,user.H,user.H,TaoDefaultComputeHessian,(void *)NULL);
147: } else {
148: TaoSetHessianRoutine(tao,user.H,user.H,FormHessian,(void *)&user);
149: }
152: /*
153: If my_monitor option is in command line, then use the user-provided
154: monitoring function
155: */
156: PetscOptionsHasName(NULL,"-my_monitor",&viewmat);
157: if (viewmat){
158: TaoSetMonitor(tao,My_Monitor,NULL,NULL);
159: }
161: /* Check for any tao command line options */
162: TaoSetFromOptions(tao);
164: /* SOLVE THE APPLICATION */
165: TaoSolve(tao);
167: TaoView(tao,PETSC_VIEWER_STDOUT_WORLD);
169: /* Get information on termination */
170: TaoGetTerminationReason(tao,&reason);
171: if (reason <= 0 ){
172: PetscPrintf(MPI_COMM_WORLD,"Try a different TAO method \n");
173: }
176: /* Free TAO data structures */
177: TaoDestroy(&tao);
179: /* Free PETSc data structures */
180: VecDestroy(&x);
181: MatDestroy(&user.H);
182: if (fdcoloring) {
183: MatFDColoringDestroy(&matfdcoloring);
184: }
185: PetscFree(user.bottom);
186: PetscFree(user.top);
187: PetscFree(user.left);
188: PetscFree(user.right);
189: DMDestroy(&user.dm);
191: PetscFinalize();
192: return 0;
193: }
197: PetscErrorCode FormGradient(Tao tao, Vec X, Vec G,void *userCtx){
199: PetscReal fcn;
201: FormFunctionGradient(tao,X,&fcn,G,userCtx);
202: return(0);
203: }
205: /* -------------------------------------------------------------------- */
208: /* FormFunctionGradient - Evaluates the function and corresponding gradient.
210: Input Parameters:
211: . tao - the Tao context
212: . XX - input vector
213: . userCtx - optional user-defined context, as set by TaoSetObjectiveAndGradientRoutine()
215: Output Parameters:
216: . fcn - the newly evaluated function
217: . GG - vector containing the newly evaluated gradient
218: */
219: PetscErrorCode FormFunctionGradient(Tao tao, Vec X, PetscReal *fcn,Vec G,void *userCtx){
221: AppCtx *user = (AppCtx *) userCtx;
223: PetscInt i,j;
224: PetscInt mx=user->mx, my=user->my;
225: PetscInt xs,xm,gxs,gxm,ys,ym,gys,gym;
226: PetscReal ft=0.0;
227: PetscReal hx=1.0/(mx+1),hy=1.0/(my+1), hydhx=hy/hx, hxdhy=hx/hy, area=0.5*hx*hy;
228: PetscReal rhx=mx+1, rhy=my+1;
229: PetscReal f1,f2,f3,f4,f5,f6,d1,d2,d3,d4,d5,d6,d7,d8,xc,xl,xr,xt,xb,xlt,xrb;
230: PetscReal df1dxc,df2dxc,df3dxc,df4dxc,df5dxc,df6dxc;
231: PetscReal **g, **x;
232: Vec localX;
235: /* Get local mesh boundaries */
236: DMGetLocalVector(user->dm,&localX);
238: DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
239: DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);
241: /* Scatter ghost points to local vector */
242: DMGlobalToLocalBegin(user->dm,X,INSERT_VALUES,localX);
243: DMGlobalToLocalEnd(user->dm,X,INSERT_VALUES,localX);
245: /* Get pointers to vector data */
246: DMDAVecGetArray(user->dm,localX,(void**)&x);
247: DMDAVecGetArray(user->dm,G,(void**)&g);
249: /* Compute function and gradient over the locally owned part of the mesh */
250: for (j=ys; j<ys+ym; j++){
251: for (i=xs; i< xs+xm; i++){
253: xc = x[j][i];
254: xlt=xrb=xl=xr=xb=xt=xc;
256: if (i==0){ /* left side */
257: xl= user->left[j-ys+1];
258: xlt = user->left[j-ys+2];
259: } else {
260: xl = x[j][i-1];
261: }
263: if (j==0){ /* bottom side */
264: xb=user->bottom[i-xs+1];
265: xrb =user->bottom[i-xs+2];
266: } else {
267: xb = x[j-1][i];
268: }
270: if (i+1 == gxs+gxm){ /* right side */
271: xr=user->right[j-ys+1];
272: xrb = user->right[j-ys];
273: } else {
274: xr = x[j][i+1];
275: }
277: if (j+1==gys+gym){ /* top side */
278: xt=user->top[i-xs+1];
279: xlt = user->top[i-xs];
280: }else {
281: xt = x[j+1][i];
282: }
284: if (i>gxs && j+1<gys+gym){
285: xlt = x[j+1][i-1];
286: }
287: if (j>gys && i+1<gxs+gxm){
288: xrb = x[j-1][i+1];
289: }
291: d1 = (xc-xl);
292: d2 = (xc-xr);
293: d3 = (xc-xt);
294: d4 = (xc-xb);
295: d5 = (xr-xrb);
296: d6 = (xrb-xb);
297: d7 = (xlt-xl);
298: d8 = (xt-xlt);
300: df1dxc = d1*hydhx;
301: df2dxc = ( d1*hydhx + d4*hxdhy );
302: df3dxc = d3*hxdhy;
303: df4dxc = ( d2*hydhx + d3*hxdhy );
304: df5dxc = d2*hydhx;
305: df6dxc = d4*hxdhy;
307: d1 *= rhx;
308: d2 *= rhx;
309: d3 *= rhy;
310: d4 *= rhy;
311: d5 *= rhy;
312: d6 *= rhx;
313: d7 *= rhy;
314: d8 *= rhx;
316: f1 = PetscSqrtReal( 1.0 + d1*d1 + d7*d7);
317: f2 = PetscSqrtReal( 1.0 + d1*d1 + d4*d4);
318: f3 = PetscSqrtReal( 1.0 + d3*d3 + d8*d8);
319: f4 = PetscSqrtReal( 1.0 + d3*d3 + d2*d2);
320: f5 = PetscSqrtReal( 1.0 + d2*d2 + d5*d5);
321: f6 = PetscSqrtReal( 1.0 + d4*d4 + d6*d6);
323: f2 = PetscSqrtReal( 1.0 + d1*d1 + d4*d4);
324: f4 = PetscSqrtReal( 1.0 + d3*d3 + d2*d2);
326: ft = ft + (f2 + f4);
328: df1dxc /= f1;
329: df2dxc /= f2;
330: df3dxc /= f3;
331: df4dxc /= f4;
332: df5dxc /= f5;
333: df6dxc /= f6;
335: g[j][i] = (df1dxc+df2dxc+df3dxc+df4dxc+df5dxc+df6dxc ) * 0.5;
337: }
338: }
340: /* Compute triangular areas along the border of the domain. */
341: if (xs==0){ /* left side */
342: for (j=ys; j<ys+ym; j++){
343: d3=(user->left[j-ys+1] - user->left[j-ys+2])*rhy;
344: d2=(user->left[j-ys+1] - x[j][0]) *rhx;
345: ft = ft+PetscSqrtReal( 1.0 + d3*d3 + d2*d2);
346: }
347: }
348: if (ys==0){ /* bottom side */
349: for (i=xs; i<xs+xm; i++){
350: d2=(user->bottom[i+1-xs]-user->bottom[i-xs+2])*rhx;
351: d3=(user->bottom[i-xs+1]-x[0][i])*rhy;
352: ft = ft+PetscSqrtReal( 1.0 + d3*d3 + d2*d2);
353: }
354: }
356: if (xs+xm==mx){ /* right side */
357: for (j=ys; j< ys+ym; j++){
358: d1=(x[j][mx-1] - user->right[j-ys+1])*rhx;
359: d4=(user->right[j-ys]-user->right[j-ys+1])*rhy;
360: ft = ft+PetscSqrtReal( 1.0 + d1*d1 + d4*d4);
361: }
362: }
363: if (ys+ym==my){ /* top side */
364: for (i=xs; i<xs+xm; i++){
365: d1=(x[my-1][i] - user->top[i-xs+1])*rhy;
366: d4=(user->top[i-xs+1] - user->top[i-xs])*rhx;
367: ft = ft+PetscSqrtReal( 1.0 + d1*d1 + d4*d4);
368: }
369: }
371: if (ys==0 && xs==0){
372: d1=(user->left[0]-user->left[1])/hy;
373: d2=(user->bottom[0]-user->bottom[1])*rhx;
374: ft +=PetscSqrtReal( 1.0 + d1*d1 + d2*d2);
375: }
376: if (ys+ym == my && xs+xm == mx){
377: d1=(user->right[ym+1] - user->right[ym])*rhy;
378: d2=(user->top[xm+1] - user->top[xm])*rhx;
379: ft +=PetscSqrtReal( 1.0 + d1*d1 + d2*d2);
380: }
382: ft=ft*area;
383: MPI_Allreduce(&ft,fcn,1,MPIU_REAL,MPIU_SUM,MPI_COMM_WORLD);
385: /* Restore vectors */
386: DMDAVecRestoreArray(user->dm,localX,(void**)&x);
387: DMDAVecRestoreArray(user->dm,G,(void**)&g);
389: /* Scatter values to global vector */
390: DMRestoreLocalVector(user->dm,&localX);
392: PetscLogFlops(67*xm*ym);
394: return(0);
395: }
397: /* ------------------------------------------------------------------- */
400: /*
401: FormHessian - Evaluates Hessian matrix.
403: Input Parameters:
404: . tao - the Tao context
405: . x - input vector
406: . ptr - optional user-defined context, as set by TaoSetHessianRoutine()
408: Output Parameters:
409: . H - Hessian matrix
410: . Hpre - optionally different preconditioning matrix
411: . flg - flag indicating matrix structure
413: */
414: PetscErrorCode FormHessian(Tao tao,Vec X,Mat *H, Mat *Hpre, MatStructure *flg, void *ptr)
415: {
417: AppCtx *user = (AppCtx *) ptr;
420: /* Evaluate the Hessian entries*/
421: QuadraticH(user,X,*H);
424: /* Indicate that this matrix has the same sparsity pattern during
425: successive iterations; setting this flag can save significant work
426: in computing the preconditioner for some methods. */
427: *flg=SAME_NONZERO_PATTERN;
428: return(0);
429: }
431: /* ------------------------------------------------------------------- */
434: /*
435: QuadraticH - Evaluates Hessian matrix.
437: Input Parameters:
438: . user - user-defined context, as set by TaoSetHessian()
439: . X - input vector
441: Output Parameter:
442: . H - Hessian matrix
443: */
444: PetscErrorCode QuadraticH(AppCtx *user, Vec X, Mat Hessian)
445: {
446: PetscErrorCode ierr;
447: PetscInt i,j,k;
448: PetscInt mx=user->mx, my=user->my;
449: PetscInt xs,xm,gxs,gxm,ys,ym,gys,gym;
450: PetscReal hx=1.0/(mx+1), hy=1.0/(my+1), hydhx=hy/hx, hxdhy=hx/hy;
451: PetscReal f1,f2,f3,f4,f5,f6,d1,d2,d3,d4,d5,d6,d7,d8,xc,xl,xr,xt,xb,xlt,xrb;
452: PetscReal hl,hr,ht,hb,hc,htl,hbr;
453: PetscReal **x, v[7];
454: MatStencil col[7],row;
455: Vec localX;
456: PetscBool assembled;
459: /* Get local mesh boundaries */
460: DMGetLocalVector(user->dm,&localX);
462: DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
463: DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);
465: /* Scatter ghost points to local vector */
466: DMGlobalToLocalBegin(user->dm,X,INSERT_VALUES,localX);
467: DMGlobalToLocalEnd(user->dm,X,INSERT_VALUES,localX);
469: /* Get pointers to vector data */
470: DMDAVecGetArray(user->dm,localX,(void**)&x);
472: /* Initialize matrix entries to zero */
473: MatAssembled(Hessian,&assembled);
474: if (assembled){MatZeroEntries(Hessian); }
477: /* Set various matrix options */
478: MatSetOption(Hessian,MAT_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE);
480: /* Compute Hessian over the locally owned part of the mesh */
482: for (j=ys; j<ys+ym; j++){
484: for (i=xs; i< xs+xm; i++){
486: xc = x[j][i];
487: xlt=xrb=xl=xr=xb=xt=xc;
489: /* Left side */
490: if (i==0){
491: xl = user->left[j-ys+1];
492: xlt = user->left[j-ys+2];
493: } else {
494: xl = x[j][i-1];
495: }
497: if (j==0){
498: xb = user->bottom[i-xs+1];
499: xrb = user->bottom[i-xs+2];
500: } else {
501: xb = x[j-1][i];
502: }
504: if (i+1 == mx){
505: xr = user->right[j-ys+1];
506: xrb = user->right[j-ys];
507: } else {
508: xr = x[j][i+1];
509: }
511: if (j+1==my){
512: xt = user->top[i-xs+1];
513: xlt = user->top[i-xs];
514: }else {
515: xt = x[j+1][i];
516: }
518: if (i>0 && j+1<my){
519: xlt = x[j+1][i-1];
520: }
521: if (j>0 && i+1<mx){
522: xrb = x[j-1][i+1];
523: }
526: d1 = (xc-xl)/hx;
527: d2 = (xc-xr)/hx;
528: d3 = (xc-xt)/hy;
529: d4 = (xc-xb)/hy;
530: d5 = (xrb-xr)/hy;
531: d6 = (xrb-xb)/hx;
532: d7 = (xlt-xl)/hy;
533: d8 = (xlt-xt)/hx;
535: f1 = PetscSqrtReal( 1.0 + d1*d1 + d7*d7);
536: f2 = PetscSqrtReal( 1.0 + d1*d1 + d4*d4);
537: f3 = PetscSqrtReal( 1.0 + d3*d3 + d8*d8);
538: f4 = PetscSqrtReal( 1.0 + d3*d3 + d2*d2);
539: f5 = PetscSqrtReal( 1.0 + d2*d2 + d5*d5);
540: f6 = PetscSqrtReal( 1.0 + d4*d4 + d6*d6);
543: hl = (-hydhx*(1.0+d7*d7)+d1*d7)/(f1*f1*f1)+
544: (-hydhx*(1.0+d4*d4)+d1*d4)/(f2*f2*f2);
545: hr = (-hydhx*(1.0+d5*d5)+d2*d5)/(f5*f5*f5)+
546: (-hydhx*(1.0+d3*d3)+d2*d3)/(f4*f4*f4);
547: ht = (-hxdhy*(1.0+d8*d8)+d3*d8)/(f3*f3*f3)+
548: (-hxdhy*(1.0+d2*d2)+d2*d3)/(f4*f4*f4);
549: hb = (-hxdhy*(1.0+d6*d6)+d4*d6)/(f6*f6*f6)+
550: (-hxdhy*(1.0+d1*d1)+d1*d4)/(f2*f2*f2);
552: hbr = -d2*d5/(f5*f5*f5) - d4*d6/(f6*f6*f6);
553: htl = -d1*d7/(f1*f1*f1) - d3*d8/(f3*f3*f3);
555: hc = hydhx*(1.0+d7*d7)/(f1*f1*f1) + hxdhy*(1.0+d8*d8)/(f3*f3*f3) +
556: hydhx*(1.0+d5*d5)/(f5*f5*f5) + hxdhy*(1.0+d6*d6)/(f6*f6*f6) +
557: (hxdhy*(1.0+d1*d1)+hydhx*(1.0+d4*d4)-2*d1*d4)/(f2*f2*f2) +
558: (hxdhy*(1.0+d2*d2)+hydhx*(1.0+d3*d3)-2*d2*d3)/(f4*f4*f4);
560: hl/=2.0; hr/=2.0; ht/=2.0; hb/=2.0; hbr/=2.0; htl/=2.0; hc/=2.0;
562: row.j = j; row.i = i;
563: k=0;
564: if (j>0){
565: v[k]=hb;
566: col[k].j = j - 1; col[k].i = i;
567: k++;
568: }
570: if (j>0 && i < mx -1){
571: v[k]=hbr;
572: col[k].j = j - 1; col[k].i = i+1;
573: k++;
574: }
576: if (i>0){
577: v[k]= hl;
578: col[k].j = j; col[k].i = i-1;
579: k++;
580: }
582: v[k]= hc;
583: col[k].j = j; col[k].i = i;
584: k++;
586: if (i < mx-1 ){
587: v[k]= hr;
588: col[k].j = j; col[k].i = i+1;
589: k++;
590: }
592: if (i>0 && j < my-1 ){
593: v[k]= htl;
594: col[k].j = j+1; col[k].i = i-1;
595: k++;
596: }
598: if (j < my-1 ){
599: v[k]= ht;
600: col[k].j = j+1; col[k].i = i;
601: k++;
602: }
604: /*
605: Set matrix values using local numbering, which was defined
606: earlier, in the main routine.
607: */
608: MatSetValuesStencil(Hessian,1,&row,k,col,v,INSERT_VALUES);
609:
611: }
612: }
614: /* Restore vectors */
615: DMDAVecRestoreArray(user->dm,localX,(void**)&x);
617: DMRestoreLocalVector(user->dm,&localX);
619: /* Assemble the matrix */
620: MatAssemblyBegin(Hessian,MAT_FINAL_ASSEMBLY);
621: MatAssemblyEnd(Hessian,MAT_FINAL_ASSEMBLY);
623: PetscLogFlops(199*xm*ym);
624: return(0);
625: }
627: /* ------------------------------------------------------------------- */
630: /*
631: MSA_BoundaryConditions - Calculates the boundary conditions for
632: the region.
634: Input Parameter:
635: . user - user-defined application context
637: Output Parameter:
638: . user - user-defined application context
639: */
640: static PetscErrorCode MSA_BoundaryConditions(AppCtx * user)
641: {
642: PetscErrorCode ierr;
643: PetscInt i,j,k,limit=0,maxits=5;
644: PetscInt xs,ys,xm,ym,gxs,gys,gxm,gym;
645: PetscInt mx=user->mx,my=user->my;
646: PetscInt bsize=0, lsize=0, tsize=0, rsize=0;
647: PetscReal one=1.0, two=2.0, three=3.0, tol=1e-10;
648: PetscReal fnorm,det,hx,hy,xt=0,yt=0;
649: PetscReal u1,u2,nf1,nf2,njac11,njac12,njac21,njac22;
650: PetscReal b=-0.5, t=0.5, l=-0.5, r=0.5;
651: PetscReal *boundary;
652: PetscBool flg;
655: /* Get local mesh boundaries */
656: DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
657: DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);
659: bsize=xm+2;
660: lsize=ym+2;
661: rsize=ym+2;
662: tsize=xm+2;
664: PetscMalloc1(bsize,&user->bottom);
665: PetscMalloc1(tsize,&user->top);
666: PetscMalloc1(lsize,&user->left);
667: PetscMalloc1(rsize,&user->right);
669: hx= (r-l)/(mx+1); hy=(t-b)/(my+1);
671: for (j=0; j<4; j++){
672: if (j==0){
673: yt=b;
674: xt=l+hx*xs;
675: limit=bsize;
676: boundary=user->bottom;
677: } else if (j==1){
678: yt=t;
679: xt=l+hx*xs;
680: limit=tsize;
681: boundary=user->top;
682: } else if (j==2){
683: yt=b+hy*ys;
684: xt=l;
685: limit=lsize;
686: boundary=user->left;
687: } else { /* if (j==3) */
688: yt=b+hy*ys;
689: xt=r;
690: limit=rsize;
691: boundary=user->right;
692: }
694: for (i=0; i<limit; i++){
695: u1=xt;
696: u2=-yt;
697: for (k=0; k<maxits; k++){
698: nf1=u1 + u1*u2*u2 - u1*u1*u1/three-xt;
699: nf2=-u2 - u1*u1*u2 + u2*u2*u2/three-yt;
700: fnorm=PetscSqrtReal(nf1*nf1+nf2*nf2);
701: if (fnorm <= tol) break;
702: njac11=one+u2*u2-u1*u1;
703: njac12=two*u1*u2;
704: njac21=-two*u1*u2;
705: njac22=-one - u1*u1 + u2*u2;
706: det = njac11*njac22-njac21*njac12;
707: u1 = u1-(njac22*nf1-njac12*nf2)/det;
708: u2 = u2-(njac11*nf2-njac21*nf1)/det;
709: }
711: boundary[i]=u1*u1-u2*u2;
712: if (j==0 || j==1) {
713: xt=xt+hx;
714: } else { /* if (j==2 || j==3) */
715: yt=yt+hy;
716: }
718: }
720: }
722: /* Scale the boundary if desired */
723: if (1==1){
724: PetscReal scl = 1.0;
726: PetscOptionsGetReal(NULL,"-bottom",&scl,&flg);
727:
728: if (flg){
729: for (i=0;i<bsize;i++) user->bottom[i]*=scl;
730: }
732: PetscOptionsGetReal(NULL,"-top",&scl,&flg);
733:
734: if (flg){
735: for (i=0;i<tsize;i++) user->top[i]*=scl;
736: }
738: PetscOptionsGetReal(NULL,"-right",&scl,&flg);
739:
740: if (flg){
741: for (i=0;i<rsize;i++) user->right[i]*=scl;
742: }
744: PetscOptionsGetReal(NULL,"-left",&scl,&flg);
745:
746: if (flg){
747: for (i=0;i<lsize;i++) user->left[i]*=scl;
748: }
749: }
751: return(0);
752: }
754: /* ------------------------------------------------------------------- */
757: /*
758: MSA_InitialPoint - Calculates the initial guess in one of three ways.
760: Input Parameters:
761: . user - user-defined application context
762: . X - vector for initial guess
764: Output Parameters:
765: . X - newly computed initial guess
766: */
767: static PetscErrorCode MSA_InitialPoint(AppCtx * user, Vec X)
768: {
769: PetscErrorCode ierr;
770: PetscInt start2=-1,i,j;
771: PetscReal start1=0;
772: PetscBool flg1,flg2;
775: PetscOptionsGetReal(NULL,"-start",&start1,&flg1);
776: PetscOptionsGetInt(NULL,"-random",&start2,&flg2);
778: if (flg1){ /* The zero vector is reasonable */
780: VecSet(X, start1);
782: } else if (flg2 && start2>0){ /* Try a random start between -0.5 and 0.5 */
784: PetscRandom rctx; PetscReal np5=-0.5;
786: PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
787: PetscRandomSetType(rctx,PETSCRAND);
788:
789: for (i=0; i<start2; i++){
790: VecSetRandom(X, rctx);
791: }
792: PetscRandomDestroy(&rctx);
793: VecShift(X, np5);
795: } else { /* Take an average of the boundary conditions */
797: PetscInt xs,xm,ys,ym;
798: PetscInt mx=user->mx,my=user->my;
799: PetscReal **x;
801: /* Get local mesh boundaries */
802: DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
804: /* Get pointers to vector data */
805: DMDAVecGetArray(user->dm,X,(void**)&x);
807: /* Perform local computations */
808: for (j=ys; j<ys+ym; j++){
809: for (i=xs; i< xs+xm; i++){
810: x[j][i] = ( ((j+1)*user->bottom[i-xs+1]+(my-j+1)*user->top[i-xs+1])/(my+2)+
811: ((i+1)*user->left[j-ys+1]+(mx-i+1)*user->right[j-ys+1])/(mx+2))/2.0;
812: }
813: }
815: /* Restore vectors */
816: DMDAVecRestoreArray(user->dm,X,(void**)&x);
818: PetscLogFlops(9*xm*ym);
820: }
821: return(0);
822: }
824: /*-----------------------------------------------------------------------*/
827: PetscErrorCode My_Monitor(Tao tao, void *ctx){
829: Vec X;
831: TaoGetSolutionVector(tao,&X);
832: VecView(X,PETSC_VIEWER_STDOUT_WORLD);
833: return(0);
834: }