Actual source code: minsurf2.c

petsc-dev 2014-02-02
Report Typos and Errors
  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: }