14800dd8cSBarry Smith #ifndef lint 2*369a4401SLois Curfman McInnes static char vcid[] = "$Id: tr.c,v 1.17 1995/07/20 15:35:04 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; 1925c7317fSLois Curfman McInnes int ierr, mkit; 20df60cc22SBarry Smith 2125c7317fSLois Curfman McInnes KSPGetTolerances(ksp,&rtol,&atol,&dtol,&mkit); 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 /* 41ddbbdb52SLois Curfman McInnes SNESSolve_TR - Implements Newton's Method with a very simple trust 42ddbbdb52SLois 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 46ddbbdb52SLois Curfman McInnes of Mathematical Software", Wayne Cowell, editor. 47ddbbdb52SLois 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; 56ddbbdb52SLois 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; 83bbb6d6a8SBarry Smith if (snes->monitor) 84bbb6d6a8SBarry Smith {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, 96bbb6d6a8SBarry Smith &flg); 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 || */ 147bbb6d6a8SBarry Smith if (snes->monitor) 148bbb6d6a8SBarry Smith {(*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);} 1494800dd8cSBarry Smith 1504800dd8cSBarry Smith /* Test for convergence */ 151bbb6d6a8SBarry 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; 20325c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," method tr:\n"); 20425c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %smu mu (default %g)\n",prefix,ctx->mu); 20525c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %seta eta (default %g)\n",prefix,ctx->eta); 20625c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %ssigma sigma (default %g)\n",prefix,ctx->sigma); 20725c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 20825c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 20925c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 21025c7317fSLois Curfman McInnes MPIU_fprintf(snes->comm,stdout," %sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 211fbe28522SBarry Smith return 0; 2124800dd8cSBarry Smith } 2134800dd8cSBarry Smith 214a935fc98SLois Curfman McInnes static int SNESView_TR(PetscObject obj,Viewer viewer) 215a935fc98SLois Curfman McInnes { 216a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 217a935fc98SLois Curfman McInnes SNES_TR *tr = (SNES_TR *)snes->data; 218a935fc98SLois Curfman McInnes FILE *fd = ViewerFileGetPointer_Private(viewer); 219a935fc98SLois Curfman McInnes 220a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," mu=%g, eta=%g, sigma=%g\n", 221a935fc98SLois Curfman McInnes tr->mu,tr->eta,tr->sigma); 222a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd, 223a935fc98SLois Curfman McInnes " delta0=%g, delta1=%g, delta2=%g, delta3=%g\n", 224a935fc98SLois Curfman McInnes tr->delta0,tr->delta1,tr->delta2,tr->delta3); 225a935fc98SLois Curfman McInnes return 0; 226a935fc98SLois Curfman McInnes } 227a935fc98SLois Curfman McInnes 228fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 2294800dd8cSBarry Smith { 230fbe28522SBarry Smith SNES_TR *neP; 2314800dd8cSBarry Smith 232*369a4401SLois Curfman McInnes if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1, 233*369a4401SLois Curfman McInnes "SNESCreate_TR: Valid for SNES_NONLINEAR_EQUATIONS problems only"); 23425c7317fSLois Curfman McInnes snes->type = SNES_EQ_NTR; 23506be10caSBarry Smith snes->setup = SNESSetUp_TR; 23606be10caSBarry Smith snes->solve = SNESSolve_TR; 237fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 238bbb6d6a8SBarry Smith snes->converged = SNESDefaultConverged; 23906be10caSBarry Smith snes->printhelp = SNESPrintHelp_TR; 24006be10caSBarry Smith snes->setfromoptions = SNESSetFromOptions_TR; 241a935fc98SLois Curfman McInnes snes->view = SNESView_TR; 242fbe28522SBarry Smith 24378b31e54SBarry Smith neP = PETSCNEW(SNES_TR); CHKPTRQ(neP); 244fbe28522SBarry Smith snes->data = (void *) neP; 245fbe28522SBarry Smith neP->mu = 0.25; 246fbe28522SBarry Smith neP->eta = 0.75; 247fbe28522SBarry Smith neP->delta = 0.0; 248fbe28522SBarry Smith neP->delta0 = 0.2; 249fbe28522SBarry Smith neP->delta1 = 0.3; 250fbe28522SBarry Smith neP->delta2 = 0.75; 251fbe28522SBarry Smith neP->delta3 = 2.0; 252fbe28522SBarry Smith neP->sigma = 0.0001; 253fbe28522SBarry Smith neP->itflag = 0; 2546b5873e3SBarry Smith return 0; 2554800dd8cSBarry Smith } 256