14800dd8cSBarry Smith #ifndef lint 2*ddbbdb52SLois Curfman McInnes static char vcid[] = "$Id: tr.c,v 1.14 1995/07/14 18:35:58 curfman Exp curfman $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 7a935fc98SLois Curfman McInnes #include "pviewer.h" 84800dd8cSBarry Smith 9fbe28522SBarry Smith /* 10df60cc22SBarry Smith This convergence test determines if the two norm of the 11df60cc22SBarry Smith solution lies outside the trust region, if so it halts. 12df60cc22SBarry Smith */ 13df60cc22SBarry Smith int TRConverged_Private(KSP ksp,int n, double rnorm, void *ctx) 14df60cc22SBarry Smith { 15df60cc22SBarry Smith SNES snes = (SNES) ctx; 16df60cc22SBarry Smith SNES_TR *neP = (SNES_TR*)snes->data; 17df60cc22SBarry Smith double rtol,atol,dtol,norm; 18df60cc22SBarry Smith Vec x; 19df60cc22SBarry Smith int ierr; 20df60cc22SBarry Smith 21df60cc22SBarry Smith KSPGetTolerances(ksp,&rtol,&atol,&dtol); 22df60cc22SBarry Smith 23df60cc22SBarry Smith if ( n == 0 ) { 24df60cc22SBarry Smith neP->ttol = MAX(rtol*rnorm,atol); 25df60cc22SBarry Smith neP->rnorm0 = rnorm; 26df60cc22SBarry Smith } 27df60cc22SBarry Smith if ( rnorm <= neP->ttol ) return 1; 28df60cc22SBarry Smith if ( rnorm >= dtol*neP->rnorm0 || rnorm != rnorm) return -1; 29df60cc22SBarry Smith 30a935fc98SLois Curfman McInnes /* Determine norm of solution */ 3178b31e54SBarry Smith ierr = KSPBuildSolution(ksp,0,&x); CHKERRQ(ierr); 3278b31e54SBarry Smith ierr = VecNorm(x,&norm); CHKERRQ(ierr); 33df60cc22SBarry Smith if (norm >= neP->delta) { 34a935fc98SLois Curfman McInnes PLogInfo((PetscObject)snes, 35a935fc98SLois Curfman McInnes "Ending linear iteration early, delta %g length %g\n",neP->delta,norm); 36df60cc22SBarry Smith return 1; 37df60cc22SBarry Smith } 38df60cc22SBarry Smith return(0); 39df60cc22SBarry Smith } 40df60cc22SBarry Smith /* 41*ddbbdb52SLois Curfman McInnes SNESSolve_TR - Implements Newton's Method with a very simple trust 42*ddbbdb52SLois Curfman McInnes region approach for solving systems of nonlinear equations. 434800dd8cSBarry Smith 444800dd8cSBarry Smith The basic algorithm is taken from "The Minpack Project", by More', 454800dd8cSBarry Smith Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 46*ddbbdb52SLois Curfman McInnes of Mathematical Software", Wayne Cowell, editor. 47*ddbbdb52SLois Curfman McInnes 484800dd8cSBarry Smith This is intended as a model implementation, since it does not 494800dd8cSBarry Smith necessarily have many of the bells and whistles of other 504800dd8cSBarry Smith implementations. 514800dd8cSBarry Smith */ 52fbe28522SBarry Smith static int SNESSolve_TR(SNES snes,int *its) 534800dd8cSBarry Smith { 54fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *) snes->data; 556b5873e3SBarry Smith Vec X, F, Y, G, TMP, Ytmp; 56*ddbbdb52SLois Curfman McInnes int maxits, i, history_len, ierr, lits; 57df60cc22SBarry Smith MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN; 58fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 594800dd8cSBarry Smith double *history, ynorm; 60eafb4bcbSBarry Smith Scalar one = 1.0,cnorm; 616b5873e3SBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 62df60cc22SBarry Smith KSP ksp; 63df60cc22SBarry Smith SLES sles; 644800dd8cSBarry Smith 65fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 66fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 67fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 68fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 6939e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 70fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 71fbe28522SBarry Smith G = snes->work[1]; 726b5873e3SBarry Smith Ytmp = snes->work[2]; 734800dd8cSBarry Smith 7478b31e54SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */ 75fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 764800dd8cSBarry Smith 7778b31e54SBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */ 78fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 79fbe28522SBarry Smith snes->norm = fnorm; 804800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 814800dd8cSBarry Smith delta = neP->delta0*fnorm; 824800dd8cSBarry Smith neP->delta = delta; 83a935fc98SLois Curfman McInnes if (snes->Monitor) 84a935fc98SLois Curfman McInnes {ierr = (*snes->Monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);} 854800dd8cSBarry Smith 86a935fc98SLois Curfman McInnes /* Set the stopping criteria to use the More' trick. */ 8778b31e54SBarry Smith ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr); 8878b31e54SBarry Smith ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr); 89df60cc22SBarry Smith ierr = KSPSetConvergenceTest(ksp,TRConverged_Private,(void *) snes); 9078b31e54SBarry Smith CHKERRQ(ierr); 91df60cc22SBarry Smith 924800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 93fbe28522SBarry Smith snes->iter = i+1; 944800dd8cSBarry Smith 95df60cc22SBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre, 9678b31e54SBarry Smith &flg,snes->jacP); CHKERRQ(ierr); 97a935fc98SLois Curfman McInnes ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre, 98a935fc98SLois Curfman McInnes flg); CHKERRQ(ierr); 9978b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERRQ(ierr); 1006b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 1016b5873e3SBarry Smith while(1) { 1026b5873e3SBarry Smith VecCopy(Ytmp,Y); 103fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 1046b5873e3SBarry Smith 105eafb4bcbSBarry Smith if (norm >= delta) { 106fbe28522SBarry Smith norm = delta/norm; 107fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 108eafb4bcbSBarry Smith cnorm = norm; 109df60cc22SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 110eafb4bcbSBarry Smith VecScale( &cnorm, Y ); 111eafb4bcbSBarry Smith norm = gpnorm; 112fbe28522SBarry Smith ynorm = delta; 113fbe28522SBarry Smith } else { 114fbe28522SBarry Smith gpnorm = 0.0; 115fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 116fbe28522SBarry Smith ynorm = norm; 117fbe28522SBarry Smith } 118fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 11981b6cf68SLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol_update_always); CHKERRQ(ierr); 12078b31e54SBarry Smith ierr = SNESComputeFunction(snes,Y,G); CHKERRQ(ierr); /* (+/-) F(X) */ 121fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 1224800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 123fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 1244800dd8cSBarry Smith 1254800dd8cSBarry Smith /* Update size of trust region */ 1264800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 1274800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 1284800dd8cSBarry Smith else delta *= neP->delta3; 1294800dd8cSBarry Smith 130fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 1314800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 132fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 133fbe28522SBarry Smith gpnorm, rho, delta, lits); 1344800dd8cSBarry Smith 1354800dd8cSBarry Smith neP->delta = delta; 1364800dd8cSBarry Smith if (rho > neP->sigma) break; 137eafb4bcbSBarry Smith PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 1386b5873e3SBarry Smith /* check to see if progress is hopeless */ 1396b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 1404800dd8cSBarry Smith } 1414800dd8cSBarry Smith fnorm = gnorm; 142fbe28522SBarry Smith snes->norm = fnorm; 1434800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 14439e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 14539e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 146fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 147a935fc98SLois Curfman McInnes if (snes->Monitor) 148a935fc98SLois Curfman McInnes {(*snes->Monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);} 1494800dd8cSBarry Smith 1504800dd8cSBarry Smith /* Test for convergence */ 151fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1524800dd8cSBarry Smith /* Verify solution is in corect location */ 15339e2f89bSBarry Smith if (X != snes->vec_sol) { 15439e2f89bSBarry Smith VecCopy(X, snes->vec_sol ); 15539e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 15639e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 15739e2f89bSBarry Smith } 1584800dd8cSBarry Smith break; 1594800dd8cSBarry Smith } 1604800dd8cSBarry Smith } 161614e12f8SBarry Smith if (i == maxits) *its = i-1; else *its = i + 1; 162fbe28522SBarry Smith return 0; 1634800dd8cSBarry Smith } 1644800dd8cSBarry Smith /*------------------------------------------------------------*/ 165fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1664800dd8cSBarry Smith { 167fbe28522SBarry Smith int ierr; 16881b6cf68SLois Curfman McInnes snes->nwork = 4; 16978b31e54SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERRQ(ierr); 17081b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 171fbe28522SBarry Smith return 0; 1724800dd8cSBarry Smith } 1734800dd8cSBarry Smith /*------------------------------------------------------------*/ 174fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1754800dd8cSBarry Smith { 176fbe28522SBarry Smith SNES snes = (SNES) obj; 177fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 17878b31e54SBarry Smith PETSCFREE(snes->data); 179fbe28522SBarry Smith return 0; 1804800dd8cSBarry Smith } 1814800dd8cSBarry Smith /*------------------------------------------------------------*/ 1824800dd8cSBarry Smith 183fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1844800dd8cSBarry Smith { 185fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 186fbe28522SBarry Smith double tmp; 1874800dd8cSBarry Smith 188df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 189df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 190df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 191df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 192df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 193df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 194df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 195fbe28522SBarry Smith return 0; 1964800dd8cSBarry Smith } 1974800dd8cSBarry Smith 198fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 1994800dd8cSBarry Smith { 200fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 201fbe28522SBarry Smith char *prefix = "-"; 202fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 203fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 204fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 205fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 206fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 207fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 208fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 209fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 210fbe28522SBarry Smith return 0; 2114800dd8cSBarry Smith } 2124800dd8cSBarry Smith 213a935fc98SLois Curfman McInnes static int SNESView_TR(PetscObject obj,Viewer viewer) 214a935fc98SLois Curfman McInnes { 215a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 216a935fc98SLois Curfman McInnes SNES_TR *tr = (SNES_TR *)snes->data; 217a935fc98SLois Curfman McInnes FILE *fd = ViewerFileGetPointer_Private(viewer); 218a935fc98SLois Curfman McInnes 219a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," mu=%g, eta=%g, sigma=%g\n", 220a935fc98SLois Curfman McInnes tr->mu,tr->eta,tr->sigma); 221a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd, 222a935fc98SLois Curfman McInnes " delta0=%g, delta1=%g, delta2=%g, delta3=%g\n", 223a935fc98SLois Curfman McInnes tr->delta0,tr->delta1,tr->delta2,tr->delta3); 224a935fc98SLois Curfman McInnes return 0; 225a935fc98SLois Curfman McInnes } 226a935fc98SLois Curfman McInnes 227fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 2284800dd8cSBarry Smith { 229fbe28522SBarry Smith SNES_TR *neP; 2304800dd8cSBarry Smith 231fbe28522SBarry Smith snes->type = SNES_NTR; 232a935fc98SLois Curfman McInnes snes->method_class = SNES_T; 23306be10caSBarry Smith snes->setup = SNESSetUp_TR; 23406be10caSBarry Smith snes->solve = SNESSolve_TR; 235fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 2366b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 23706be10caSBarry Smith snes->printhelp = SNESPrintHelp_TR; 23806be10caSBarry Smith snes->setfromoptions = SNESSetFromOptions_TR; 239a935fc98SLois Curfman McInnes snes->view = SNESView_TR; 240fbe28522SBarry Smith 24178b31e54SBarry Smith neP = PETSCNEW(SNES_TR); CHKPTRQ(neP); 242fbe28522SBarry Smith snes->data = (void *) neP; 243fbe28522SBarry Smith neP->mu = 0.25; 244fbe28522SBarry Smith neP->eta = 0.75; 245fbe28522SBarry Smith neP->delta = 0.0; 246fbe28522SBarry Smith neP->delta0 = 0.2; 247fbe28522SBarry Smith neP->delta1 = 0.3; 248fbe28522SBarry Smith neP->delta2 = 0.75; 249fbe28522SBarry Smith neP->delta3 = 2.0; 250fbe28522SBarry Smith neP->sigma = 0.0001; 251fbe28522SBarry Smith neP->itflag = 0; 2526b5873e3SBarry Smith return 0; 2534800dd8cSBarry Smith } 254