Actual source code: nash.c

  1: #define PETSCKSP_DLL

 3:  #include private/kspimpl.h
 4:  #include ../src/ksp/ksp/impls/cg/nash/nashimpl.h

  6: #define NASH_PRECONDITIONED_DIRECTION   0
  7: #define NASH_UNPRECONDITIONED_DIRECTION 1
  8: #define NASH_DIRECTION_TYPES            2

 10: static const char *DType_Table[64] = {  "preconditioned", "unpreconditioned"};

 14: /*@
 15:     KSPNASHSetRadius - Sets the radius of the trust region.

 17:     Collective on KSP

 19:     Input Parameters:
 20: +   ksp    - the iterative context
 21: -   radius - the trust region radius (Infinity is the default)

 23:     Options Database Key:
 24: .   -ksp_nash_radius <r>

 26:     Level: advanced

 28: .keywords: KSP, NASH, set, trust region radius
 29: @*/
 30: PetscErrorCode  KSPNASHSetRadius(KSP ksp, PetscReal radius)
 31: {
 32:   PetscErrorCode ierr, (*f)(KSP, PetscReal);

 36:   if (radius < 0.0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Radius negative");
 37:   PetscObjectQueryFunction((PetscObject)ksp, "KSPNASHSetRadius_C", (void (**)(void))&f);
 38:   if (f) {
 39:     (*f)(ksp, radius);
 40:   }
 41:   return(0);
 42: }

 46: /*@
 47:     KSPNASHGetNormD - Got norm of the direction.

 49:     Collective on KSP

 51:     Input Parameters:
 52: +   ksp    - the iterative context
 53: -   norm_d - the norm of the direction

 55:     Level: advanced

 57: .keywords: KSP, NASH, get, norm direction
 58: @*/
 59: PetscErrorCode  KSPNASHGetNormD(KSP ksp, PetscReal *norm_d)
 60: {
 61:   PetscErrorCode ierr, (*f)(KSP, PetscReal *);

 65:   PetscObjectQueryFunction((PetscObject)ksp, "KSPNASHGetNormD_C", (void (**)(void))&f);
 66:   if (f) {
 67:     (*f)(ksp, norm_d);
 68:   }
 69:   return(0);
 70: }

 74: /*@
 75:     KSPNASHGetObjFcn - Get objective function value.

 77:     Collective on KSP

 79:     Input Parameters:
 80: +   ksp   - the iterative context
 81: -   o_fcn - the objective function value

 83:     Level: advanced

 85: .keywords: KSP, NASH, get, objective function
 86: @*/
 87: PetscErrorCode  KSPNASHGetObjFcn(KSP ksp, PetscReal *o_fcn)
 88: {
 89:   PetscErrorCode ierr, (*f)(KSP, PetscReal *);

 93:   PetscObjectQueryFunction((PetscObject)ksp, "KSPNASHGetObjFcn_C", (void (**)(void))&f);
 94:   if (f) {
 95:     (*f)(ksp, o_fcn);
 96:   }
 97:   return(0);
 98: }


103: PetscErrorCode KSPSolve_NASH(KSP ksp)
104: {
105: #ifdef PETSC_USE_COMPLEX
106:   SETERRQ(PETSC_ERR_SUP, "NASH is not available for complex systems");
107: #else
108:   KSP_NASH       *cg = (KSP_NASH *)ksp->data;
110:   MatStructure   pflag;
111:   Mat            Qmat, Mmat;
112:   Vec            r, z, p, d;
113:   PC             pc;

115:   PetscReal      norm_r, norm_d, norm_dp1, norm_p, dMp;
116:   PetscReal      alpha, beta, kappa, rz, rzm1;
117:   PetscReal      rr, r2, step;

119:   PetscInt       max_cg_its;

121:   PetscTruth     diagonalscale;

124:   /***************************************************************************/
125:   /* Check the arguments and parameters.                                     */
126:   /***************************************************************************/

128:   PCDiagonalScale(ksp->pc, &diagonalscale);
129:   if (diagonalscale) {
130:     SETERRQ1(PETSC_ERR_SUP, "Krylov method %s does not support diagonal scaling", ((PetscObject)ksp)->type_name);
131:   }

133:   if (cg->radius < 0.0) {
134:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Input error: radius < 0");
135:   }

137:   /***************************************************************************/
138:   /* Get the workspace vectors and initialize variables                      */
139:   /***************************************************************************/

141:   r2 = cg->radius * cg->radius;
142:   r  = ksp->work[0];
143:   z  = ksp->work[1];
144:   p  = ksp->work[2];
145:   d  = ksp->vec_sol;
146:   pc = ksp->pc;

148:   PCGetOperators(pc, &Qmat, &Mmat, &pflag);

150:   VecGetSize(d, &max_cg_its);
151:   max_cg_its = PetscMin(max_cg_its, ksp->max_it);
152:   ksp->its = 0;

154:   /***************************************************************************/
155:   /* Initialize objective function and direction.                            */
156:   /***************************************************************************/

158:   cg->o_fcn = 0.0;

160:   VecSet(d, 0.0);                        /* d = 0             */
161:   cg->norm_d = 0.0;

163:   /***************************************************************************/
164:   /* Begin the conjugate gradient method.  Check the right-hand side for     */
165:   /* numerical problems.  The check for not-a-number and infinite values     */
166:   /* need be performed only once.                                            */
167:   /***************************************************************************/

169:   VecCopy(ksp->vec_rhs, r);        /* r = -grad         */
170:   VecDot(r, r, &rr);                /* rr = r^T r        */
171:   if (PetscIsInfOrNanScalar(rr)) {
172:     /*************************************************************************/
173:     /* The right-hand side contains not-a-number or an infinite value.       */
174:     /* The gradient step does not work; return a zero value for the step.    */
175:     /*************************************************************************/

177:     ksp->reason = KSP_DIVERGED_NAN;
178:     PetscInfo1(ksp, "KSPSolve_NASH: bad right-hand side: rr=%g\n", rr);
179:     return(0);
180:   }

182:   /***************************************************************************/
183:   /* Check the preconditioner for numerical problems and for positive        */
184:   /* definiteness.  The check for not-a-number and infinite values need be   */
185:   /* performed only once.                                                    */
186:   /***************************************************************************/

188:   KSP_PCApply(ksp, r, z);                /* z = inv(M) r      */
189:   VecDot(r, z, &rz);                /* rz = r^T inv(M) r */
190:   if (PetscIsInfOrNanScalar(rz)) {
191:     /*************************************************************************/
192:     /* The preconditioner contains not-a-number or an infinite value.        */
193:     /* Return the gradient direction intersected with the trust region.      */
194:     /*************************************************************************/

196:     ksp->reason = KSP_DIVERGED_NAN;
197:     PetscInfo1(ksp, "KSPSolve_NASH: bad preconditioner: rz=%g\n", rz);

199:     if (cg->radius) {
200:       if (r2 >= rr) {
201:         alpha = 1.0;
202:         cg->norm_d = sqrt(rr);
203:       }
204:       else {
205:         alpha = sqrt(r2 / rr);
206:         cg->norm_d = cg->radius;
207:       }

209:       VecAXPY(d, alpha, r);        /* d = d + alpha r   */

211:       /***********************************************************************/
212:       /* Compute objective function.                                         */
213:       /***********************************************************************/

215:       KSP_MatMult(ksp, Qmat, d, z);CHKERRQ(ierr)
216:       VecAYPX(z, -0.5, ksp->vec_rhs);
217:       VecDot(d, z, &cg->o_fcn);
218:       cg->o_fcn = -cg->o_fcn;
219:       ++ksp->its;
220:     }
221:     return(0);
222:   }

224:   if (rz < 0.0) {
225:     /*************************************************************************/
226:     /* The preconditioner is indefinite.  Because this is the first          */
227:     /* and we do not have a direction yet, we use the gradient step.  Note   */
228:     /* that we cannot use the preconditioned norm when computing the step    */
229:     /* because the matrix is indefinite.                                     */
230:     /*************************************************************************/

232:     ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
233:     PetscInfo1(ksp, "KSPSolve_NASH: indefinite preconditioner: rz=%g\n", rz);

235:     if (cg->radius) {
236:       if (r2 >= rr) {
237:         alpha = 1.0;
238:         cg->norm_d = sqrt(rr);
239:       }
240:       else {
241:         alpha = sqrt(r2 / rr);
242:         cg->norm_d = cg->radius;
243:       }

245:       VecAXPY(d, alpha, r);        /* d = d + alpha r   */

247:       /***********************************************************************/
248:       /* Compute objective function.                                         */
249:       /***********************************************************************/

251:       KSP_MatMult(ksp, Qmat, d, z);CHKERRQ(ierr)
252:       VecAYPX(z, -0.5, ksp->vec_rhs);
253:       VecDot(d, z, &cg->o_fcn);
254:       cg->o_fcn = -cg->o_fcn;
255:       ++ksp->its;
256:     }
257:     return(0);
258:   }

260:   /***************************************************************************/
261:   /* As far as we know, the preconditioner is positive semidefinite.         */
262:   /* Compute and log the residual.  Check convergence because this           */
263:   /* initializes things, but do not terminate until at least one conjugate   */
264:   /* gradient iteration has been performed.                                  */
265:   /***************************************************************************/

267:   switch(ksp->normtype) {
268:   case KSP_NORM_PRECONDITIONED:
269:     VecNorm(z, NORM_2, &norm_r);        /* norm_r = |z|      */
270:     break;

272:   case KSP_NORM_UNPRECONDITIONED:
273:     norm_r = sqrt(rr);                                        /* norm_r = |r|      */
274:     break;

276:   case KSP_NORM_NATURAL:
277:     norm_r = sqrt(rz);                                        /* norm_r = |r|_M    */
278:     break;

280:   default:
281:     norm_r = 0.0;
282:     break;
283:   }

285:   KSPLogResidualHistory(ksp, norm_r);
286:   KSPMonitor(ksp, ksp->its, norm_r);
287:   ksp->rnorm = norm_r;

289:   (*ksp->converged)(ksp, ksp->its, norm_r, &ksp->reason, ksp->cnvP);

291:   /***************************************************************************/
292:   /* Compute the first direction and update the iteration.                   */
293:   /***************************************************************************/

295:   VecCopy(z, p);                        /* p = z             */
296:   KSP_MatMult(ksp, Qmat, p, z);        /* z = Q * p         */
297:   ++ksp->its;

299:   /***************************************************************************/
300:   /* Check the matrix for numerical problems.                                */
301:   /***************************************************************************/

303:   VecDot(p, z, &kappa);                /* kappa = p^T Q p   */
304:   if (PetscIsInfOrNanScalar(kappa)) {
305:     /*************************************************************************/
306:     /* The matrix produced not-a-number or an infinite value.  In this case, */
307:     /* we must stop and use the gradient direction.  This condition need     */
308:     /* only be checked once.                                                 */
309:     /*************************************************************************/

311:     ksp->reason = KSP_DIVERGED_NAN;
312:     PetscInfo1(ksp, "KSPSolve_NASH: bad matrix: kappa=%g\n", kappa);

314:     if (cg->radius) {
315:       if (r2 >= rr) {
316:         alpha = 1.0;
317:         cg->norm_d = sqrt(rr);
318:       }
319:       else {
320:         alpha = sqrt(r2 / rr);
321:         cg->norm_d = cg->radius;
322:       }

324:       VecAXPY(d, alpha, r);        /* d = d + alpha r   */

326:       /***********************************************************************/
327:       /* Compute objective function.                                         */
328:       /***********************************************************************/

330:       KSP_MatMult(ksp, Qmat, d, z);CHKERRQ(ierr)
331:       VecAYPX(z, -0.5, ksp->vec_rhs);
332:       VecDot(d, z, &cg->o_fcn);
333:       cg->o_fcn = -cg->o_fcn;
334:       ++ksp->its;
335:     }
336:     return(0);
337:   }

339:   /***************************************************************************/
340:   /* Initialize variables for calculating the norm of the direction.         */
341:   /***************************************************************************/

343:   dMp = 0.0;
344:   norm_d = 0.0;
345:   switch(cg->dtype) {
346:   case NASH_PRECONDITIONED_DIRECTION:
347:     norm_p = rz;
348:     break;

350:   default:
351:     VecDot(p, p, &norm_p);
352:     break;
353:   }

355:   /***************************************************************************/
356:   /* Check for negative curvature.                                           */
357:   /***************************************************************************/

359:   if (kappa <= 0.0) {
360:     /*************************************************************************/
361:     /* In this case, the matrix is indefinite and we have encountered a      */
362:     /* direction of negative curvature.  Because negative curvature occurs   */
363:     /* during the first step, we must follow a direction.                    */
364:     /*************************************************************************/

366:     ksp->reason = KSP_CONVERGED_CG_NEG_CURVE;
367:     PetscInfo1(ksp, "KSPSolve_NASH: negative curvature: kappa=%g\n", kappa);

369:     if (cg->radius && norm_p > 0.0) {
370:       /***********************************************************************/
371:       /* Follow direction of negative curvature to the boundary of the       */
372:       /* trust region.                                                       */
373:       /***********************************************************************/

375:       step = sqrt(r2 / norm_p);
376:       cg->norm_d = cg->radius;

378:       VecAXPY(d, step, p);        /* d = d + step p    */

380:       /***********************************************************************/
381:       /* Update objective function.                                          */
382:       /***********************************************************************/

384:       cg->o_fcn += step * (0.5 * step * kappa - rz);
385:     }
386:     else if (cg->radius) {
387:       /***********************************************************************/
388:       /* The norm of the preconditioned direction is zero; use the gradient  */
389:       /* step.                                                               */
390:       /***********************************************************************/

392:       if (r2 >= rr) {
393:         alpha = 1.0;
394:         cg->norm_d = sqrt(rr);
395:       }
396:       else {
397:         alpha = sqrt(r2 / rr);
398:         cg->norm_d = cg->radius;
399:       }

401:       VecAXPY(d, alpha, r);        /* d = d + alpha r   */

403:       /***********************************************************************/
404:       /* Compute objective function.                                         */
405:       /***********************************************************************/

407:       KSP_MatMult(ksp, Qmat, d, z);CHKERRQ(ierr)
408:       VecAYPX(z, -0.5, ksp->vec_rhs);
409:       VecDot(d, z, &cg->o_fcn);
410:       cg->o_fcn = -cg->o_fcn;
411:       ++ksp->its;
412:     }
413:     return(0);
414:   }

416:   /***************************************************************************/
417:   /* Run the conjugate gradient method until either the problem is solved,   */
418:   /* we encounter the boundary of the trust region, or the conjugate         */
419:   /* gradient method breaks down.                                            */
420:   /***************************************************************************/

422:   while(1) {
423:     /*************************************************************************/
424:     /* Know that kappa is nonzero, because we have not broken down, so we    */
425:     /* can compute the steplength.                                           */
426:     /*************************************************************************/

428:     alpha = rz / kappa;

430:     /*************************************************************************/
431:     /* Compute the steplength and check for intersection with the trust      */
432:     /* region.                                                               */
433:     /*************************************************************************/

435:     norm_dp1 = norm_d + alpha*(2.0*dMp + alpha*norm_p);
436:     if (cg->radius && norm_dp1 >= r2) {
437:       /***********************************************************************/
438:       /* In this case, the matrix is positive definite as far as we know.    */
439:       /* However, the full step goes beyond the trust region.                */
440:       /***********************************************************************/

442:       ksp->reason = KSP_CONVERGED_CG_CONSTRAINED;
443:       PetscInfo1(ksp, "KSPSolve_NASH: constrained step: radius=%g\n", cg->radius);

445:       if (norm_p > 0.0) {
446:         /*********************************************************************/
447:         /* Follow the direction to the boundary of the trust region.         */
448:         /*********************************************************************/

450:         step = (sqrt(dMp*dMp+norm_p*(r2-norm_d))-dMp)/norm_p;
451:         cg->norm_d = cg->radius;

453:         VecAXPY(d, step, p);        /* d = d + step p    */

455:         /*********************************************************************/
456:         /* Update objective function.                                        */
457:         /*********************************************************************/

459:         cg->o_fcn += step * (0.5 * step * kappa - rz);
460:       }
461:       else {
462:         /*********************************************************************/
463:         /* The norm of the direction is zero; there is nothing to follow.    */
464:         /*********************************************************************/
465:       }
466:       break;
467:     }

469:     /*************************************************************************/
470:     /* Now we can update the direction and residual.                         */
471:     /*************************************************************************/

473:     VecAXPY(d, alpha, p);                /* d = d + alpha p   */
474:     VecAXPY(r, -alpha, z);                        /* r = r - alpha Q p */
475:     KSP_PCApply(ksp, r, z);        /* z = inv(M) r      */

477:     switch(cg->dtype) {
478:     case NASH_PRECONDITIONED_DIRECTION:
479:       norm_d = norm_dp1;
480:       break;

482:     default:
483:       VecDot(d, d, &norm_d);
484:       break;
485:     }
486:     cg->norm_d = sqrt(norm_d);

488:     /*************************************************************************/
489:     /* Update objective function.                                            */
490:     /*************************************************************************/

492:     cg->o_fcn -= 0.5 * alpha * rz;

494:     /*************************************************************************/
495:     /* Check that the preconditioner appears positive semidefinite.          */
496:     /*************************************************************************/

498:     rzm1 = rz;
499:     VecDot(r, z, &rz);                /* rz = r^T z        */
500:     if (rz < 0.0) {
501:       /***********************************************************************/
502:       /* The preconditioner is indefinite.                                   */
503:       /***********************************************************************/

505:       ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
506:       PetscInfo1(ksp, "KSPSolve_NASH: cg indefinite preconditioner: rz=%g\n", rz);
507:       break;
508:     }

510:     /*************************************************************************/
511:     /* As far as we know, the preconditioner is positive semidefinite.       */
512:     /* Compute the residual and check for convergence.                       */
513:     /*************************************************************************/

515:     switch(ksp->normtype) {
516:     case KSP_NORM_PRECONDITIONED:
517:       VecNorm(z, NORM_2, &norm_r);/* norm_r = |z|      */
518:       break;

520:     case KSP_NORM_UNPRECONDITIONED:
521:       VecNorm(r, NORM_2, &norm_r);/* norm_r = |r|      */
522:       break;

524:     case KSP_NORM_NATURAL:
525:       norm_r = sqrt(rz);                                /* norm_r = |r|_M    */
526:       break;

528:     default:
529:       norm_r = 0.;
530:       break;
531:     }

533:     KSPLogResidualHistory(ksp, norm_r);
534:     KSPMonitor(ksp, ksp->its, norm_r);
535:     ksp->rnorm = norm_r;
536: 
537:     (*ksp->converged)(ksp, ksp->its, norm_r, &ksp->reason, ksp->cnvP);
538:     if (ksp->reason) {
539:       /***********************************************************************/
540:       /* The method has converged.                                           */
541:       /***********************************************************************/

543:       PetscInfo2(ksp, "KSPSolve_NASH: truncated step: rnorm=%g, radius=%g\n", norm_r, cg->radius);
544:       break;
545:     }

547:     /*************************************************************************/
548:     /* We have not converged yet.  Check for breakdown.                      */
549:     /*************************************************************************/

551:     beta = rz / rzm1;
552:     if (fabs(beta) <= 0.0) {
553:       /***********************************************************************/
554:       /* Conjugate gradients has broken down.                                */
555:       /***********************************************************************/

557:       ksp->reason = KSP_DIVERGED_BREAKDOWN;
558:       PetscInfo1(ksp, "KSPSolve_NASH: breakdown: beta=%g\n", beta);
559:       break;
560:     }

562:     /*************************************************************************/
563:     /* Check iteration limit.                                                */
564:     /*************************************************************************/

566:     if (ksp->its >= max_cg_its) {
567:       ksp->reason = KSP_DIVERGED_ITS;
568:       PetscInfo1(ksp, "KSPSolve_NASH: iterlim: its=%d\n", ksp->its);
569:       break;
570:     }

572:     /*************************************************************************/
573:     /* Update p and the norms.                                               */
574:     /*************************************************************************/

576:     VecAYPX(p, beta, z);          /* p = z + beta p    */

578:     switch(cg->dtype) {
579:     case NASH_PRECONDITIONED_DIRECTION:
580:       dMp = beta*(dMp + alpha*norm_p);
581:       norm_p = beta*(rzm1 + beta*norm_p);
582:       break;

584:     default:
585:       VecDot(d, p, &dMp);
586:       VecDot(p, p, &norm_p);
587:       break;
588:     }

590:     /*************************************************************************/
591:     /* Compute the new direction and update the iteration.                   */
592:     /*************************************************************************/

594:     KSP_MatMult(ksp, Qmat, p, z);        /* z = Q * p         */
595:     VecDot(p, z, &kappa);                /* kappa = p^T Q p   */
596:     ++ksp->its;

598:     /*************************************************************************/
599:     /* Check for negative curvature.                                         */
600:     /*************************************************************************/

602:     if (kappa <= 0.0) {
603:       /***********************************************************************/
604:       /* In this case, the matrix is indefinite and we have encountered      */
605:       /* a direction of negative curvature.  Stop at the base.               */
606:       /***********************************************************************/

608:       ksp->reason = KSP_CONVERGED_CG_NEG_CURVE;
609:       PetscInfo1(ksp, "KSPSolve_NASH: negative curvature: kappa=%g\n", kappa);
610:       break;
611:     }
612:   }

614:   return(0);
615: #endif
616: }

620: PetscErrorCode KSPSetUp_NASH(KSP ksp)
621: {

625:   /***************************************************************************/
626:   /* This implementation of CG only handles left preconditioning so generate */
627:   /* an error otherwise.                                                     */
628:   /***************************************************************************/

630:   if (ksp->pc_side == PC_RIGHT) {
631:     SETERRQ(PETSC_ERR_SUP, "No right preconditioning for KSPNASH");
632:   } else if (ksp->pc_side == PC_SYMMETRIC) {
633:     SETERRQ(PETSC_ERR_SUP, "No symmetric preconditioning for KSPNASH");
634:   }

636:   /***************************************************************************/
637:   /* Set work vectors needed by conjugate gradient method and allocate       */
638:   /***************************************************************************/

640:   KSPDefaultGetWork(ksp, 3);
641:   return(0);
642: }

646: PetscErrorCode KSPDestroy_NASH(KSP ksp)
647: {

651:  /***************************************************************************/
652:   /* Clear composed functions                                                */
653:   /***************************************************************************/

655:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPNASHSetRadius_C","",PETSC_NULL);
656:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPNASHGetNormD_C","",PETSC_NULL);
657:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPNASHGetObjFcn_C","",PETSC_NULL);

659:   /***************************************************************************/
660:   /* Destroy KSP object.                                                     */
661:   /***************************************************************************/

663:   KSPDefaultDestroy(ksp);
664:   return(0);
665: }

670: PetscErrorCode  KSPNASHSetRadius_NASH(KSP ksp, PetscReal radius)
671: {
672:   KSP_NASH *cg = (KSP_NASH *)ksp->data;

675:   cg->radius = radius;
676:   return(0);
677: }

681: PetscErrorCode  KSPNASHGetNormD_NASH(KSP ksp, PetscReal *norm_d)
682: {
683:   KSP_NASH *cg = (KSP_NASH *)ksp->data;

686:   *norm_d = cg->norm_d;
687:   return(0);
688: }

692: PetscErrorCode  KSPNASHGetObjFcn_NASH(KSP ksp, PetscReal *o_fcn){
693:   KSP_NASH *cg = (KSP_NASH *)ksp->data;

696:   *o_fcn = cg->o_fcn;
697:   return(0);
698: }

703: PetscErrorCode KSPSetFromOptions_NASH(KSP ksp)
704: {
706:   KSP_NASH       *cg = (KSP_NASH *)ksp->data;

709:   PetscOptionsHead("KSP NASH options");

711:   PetscOptionsReal("-ksp_nash_radius", "Trust Region Radius", "KSPNASHSetRadius", cg->radius, &cg->radius, PETSC_NULL);

713:   PetscOptionsEList("-ksp_nash_dtype", "Norm used for direction", "", DType_Table, NASH_DIRECTION_TYPES, DType_Table[cg->dtype], &cg->dtype, PETSC_NULL);

715:   PetscOptionsTail();
716:   return(0);
717: }

719: /*MC
720:      KSPNASH -   Code to run conjugate gradient method subject to a constraint
721:          on the solution norm. This is used in Trust Region methods for
722:          nonlinear equations, SNESTR

724:    Options Database Keys:
725: .      -ksp_nash_radius <r> - Trust Region Radius

727:    Notes: This is rarely used directly

729:    Level: developer

731:   Use preconditioned conjugate gradient to compute
732:   an approximate minimizer of the quadratic function

734:             q(s) = g^T * s + 0.5 * s^T * H * s

736:    subject to the trust region constraint

738:             || s || <= delta,

740:    where

742:      delta is the trust region radius,
743:      g is the gradient vector, 
744:      H is the Hessian approximation, and
745:      M is the positive definite preconditioner matrix.

747:    KSPConvergedReason may be
748: $  KSP_CONVERGED_CG_NEG_CURVE if convergence is reached along a negative curvature direction,
749: $  KSP_CONVERGED_CG_CONSTRAINED if convergence is reached along a constrained step,
750: $  other KSP converged/diverged reasons

752:   Notes:
753:   The preconditioner supplied should be symmetric and positive definite.

755: .seealso:  KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP, KSPNASHSetRadius(), KSPNASHGetNormD(), KSPNASHGetObjFcn()
756: M*/

761: PetscErrorCode  KSPCreate_NASH(KSP ksp)
762: {
764:   KSP_NASH       *cg;

767:   PetscNewLog(ksp,KSP_NASH, &cg);
768:   cg->radius = 0.0;
769:   cg->dtype = NASH_UNPRECONDITIONED_DIRECTION;

771:   ksp->data = (void *) cg;
772:   ksp->pc_side = PC_LEFT;
773:   ksp->normtype = KSP_NORM_UNPRECONDITIONED;

775:   /***************************************************************************/
776:   /* Sets the functions that are associated with this data structure         */
777:   /* (in C++ this is the same as defining virtual functions).                */
778:   /***************************************************************************/

780:   ksp->ops->setup                = KSPSetUp_NASH;
781:   ksp->ops->solve                = KSPSolve_NASH;
782:   ksp->ops->destroy              = KSPDestroy_NASH;
783:   ksp->ops->setfromoptions       = KSPSetFromOptions_NASH;
784:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
785:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;
786:   ksp->ops->view                 = 0;

788:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,
789:                                            "KSPNASHSetRadius_C",
790:                                            "KSPNASHSetRadius_NASH",
791:                                             KSPNASHSetRadius_NASH);
792:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,
793:                                            "KSPNASHGetNormD_C",
794:                                            "KSPNASHGetNormD_NASH",
795:                                             KSPNASHGetNormD_NASH);
796:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,
797:                                            "KSPNASHGetObjFcn_C",
798:                                            "KSPNASHGetObjFcn_NASH",
799:                                             KSPNASHGetObjFcn_NASH);
800:   return(0);
801: }