14800dd8cSBarry Smith #ifndef lint 2*a935fc98SLois Curfman McInnes static char vcid[] = "$Id: tr.c,v 1.13 1995/06/13 02:24:21 curfman Exp curfman $"; 34800dd8cSBarry Smith #endif 44800dd8cSBarry Smith 54800dd8cSBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "tr.h" 7*a935fc98SLois 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 30*a935fc98SLois 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) { 34*a935fc98SLois Curfman McInnes PLogInfo((PetscObject)snes, 35*a935fc98SLois 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 /* 4139e2f89bSBarry Smith Implements Newton's Method with a very simple trust region 424800dd8cSBarry Smith approach for solving systems of nonlinear equations. 434800dd8cSBarry Smith 444800dd8cSBarry Smith Input parameters: 456b5873e3SBarry Smith . nlP - nonlinear context obtained from SNESCreate() 464800dd8cSBarry Smith 474800dd8cSBarry Smith The basic algorithm is taken from "The Minpack Project", by More', 484800dd8cSBarry Smith Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 494800dd8cSBarry Smith of Mathematical Software", Wayne Cowell, editor. See the examples 504800dd8cSBarry Smith in nonlin/examples. 51fbe28522SBarry Smith */ 524800dd8cSBarry Smith /* 534800dd8cSBarry Smith This is intended as a model implementation, since it does not 544800dd8cSBarry Smith necessarily have many of the bells and whistles of other 554800dd8cSBarry Smith implementations. 564800dd8cSBarry Smith 574800dd8cSBarry Smith */ 58fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its ) 594800dd8cSBarry Smith { 60fbe28522SBarry Smith SNES_TR *neP = (SNES_TR *) snes->data; 616b5873e3SBarry Smith Vec X, F, Y, G, TMP, Ytmp; 62edd2f0e1SBarry Smith int maxits, i, history_len, nlconv,ierr,lits; 63df60cc22SBarry Smith MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN; 64fbe28522SBarry Smith double rho, fnorm, gnorm, gpnorm, xnorm, delta,norm; 654800dd8cSBarry Smith double *history, ynorm; 66eafb4bcbSBarry Smith Scalar one = 1.0,cnorm; 676b5873e3SBarry Smith double epsmch = 1.0e-14; /* This must be fixed */ 68df60cc22SBarry Smith KSP ksp; 69df60cc22SBarry Smith SLES sles; 704800dd8cSBarry Smith 714800dd8cSBarry Smith nlconv = 0; /* convergence monitor */ 72fbe28522SBarry Smith history = snes->conv_hist; /* convergence history */ 73fbe28522SBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 74fbe28522SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 75fbe28522SBarry Smith X = snes->vec_sol; /* solution vector */ 7639e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 77fbe28522SBarry Smith Y = snes->work[0]; /* work vectors */ 78fbe28522SBarry Smith G = snes->work[1]; 796b5873e3SBarry Smith Ytmp = snes->work[2]; 804800dd8cSBarry Smith 8178b31e54SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */ 82fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 834800dd8cSBarry Smith 8478b31e54SBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */ 85fbe28522SBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 86fbe28522SBarry Smith snes->norm = fnorm; 874800dd8cSBarry Smith if (history && history_len > 0) history[0] = fnorm; 884800dd8cSBarry Smith delta = neP->delta0*fnorm; 894800dd8cSBarry Smith neP->delta = delta; 90*a935fc98SLois Curfman McInnes if (snes->Monitor) 91*a935fc98SLois Curfman McInnes {ierr = (*snes->Monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);} 924800dd8cSBarry Smith 93*a935fc98SLois Curfman McInnes /* Set the stopping criteria to use the More' trick. */ 9478b31e54SBarry Smith ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr); 9578b31e54SBarry Smith ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr); 96df60cc22SBarry Smith ierr = KSPSetConvergenceTest(ksp,TRConverged_Private,(void *) snes); 9778b31e54SBarry Smith CHKERRQ(ierr); 98df60cc22SBarry Smith 994800dd8cSBarry Smith for ( i=0; i<maxits; i++ ) { 100fbe28522SBarry Smith snes->iter = i+1; 1014800dd8cSBarry Smith 102df60cc22SBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre, 10378b31e54SBarry Smith &flg,snes->jacP); CHKERRQ(ierr); 104*a935fc98SLois Curfman McInnes ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre, 105*a935fc98SLois Curfman McInnes flg); CHKERRQ(ierr); 10678b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERRQ(ierr); 1076b5873e3SBarry Smith VecNorm( Ytmp, &norm ); 1086b5873e3SBarry Smith while(1) { 1096b5873e3SBarry Smith VecCopy(Ytmp,Y); 110fbe28522SBarry Smith /* Scale Y if need be and predict new value of F norm */ 1116b5873e3SBarry Smith 112eafb4bcbSBarry Smith if (norm >= delta) { 113fbe28522SBarry Smith norm = delta/norm; 114fbe28522SBarry Smith gpnorm = (1.0 - norm)*fnorm; 115eafb4bcbSBarry Smith cnorm = norm; 116df60cc22SBarry Smith PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm ); 117eafb4bcbSBarry Smith VecScale( &cnorm, Y ); 118eafb4bcbSBarry Smith norm = gpnorm; 119fbe28522SBarry Smith ynorm = delta; 120fbe28522SBarry Smith } else { 121fbe28522SBarry Smith gpnorm = 0.0; 122fbe28522SBarry Smith PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" ); 123fbe28522SBarry Smith ynorm = norm; 124fbe28522SBarry Smith } 125fbe28522SBarry Smith VecAXPY(&one, X, Y ); /* Y <- X + Y */ 12681b6cf68SLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol_update_always); CHKERRQ(ierr); 12778b31e54SBarry Smith ierr = SNESComputeFunction(snes,Y,G); CHKERRQ(ierr); /* (+/-) F(X) */ 128fbe28522SBarry Smith VecNorm( G, &gnorm ); /* gnorm <- || g || */ 1294800dd8cSBarry Smith if (fnorm == gpnorm) rho = 0.0; 130fbe28522SBarry Smith else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); 1314800dd8cSBarry Smith 1324800dd8cSBarry Smith /* Update size of trust region */ 1334800dd8cSBarry Smith if (rho < neP->mu) delta *= neP->delta1; 1344800dd8cSBarry Smith else if (rho < neP->eta) delta *= neP->delta2; 1354800dd8cSBarry Smith else delta *= neP->delta3; 1364800dd8cSBarry Smith 137fbe28522SBarry Smith PLogInfo((PetscObject)snes,"%d: f_norm=%g, g_norm=%g, ynorm=%g\n", 1384800dd8cSBarry Smith i, fnorm, gnorm, ynorm ); 139fbe28522SBarry Smith PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n", 140fbe28522SBarry Smith gpnorm, rho, delta, lits); 1414800dd8cSBarry Smith 1424800dd8cSBarry Smith neP->delta = delta; 1434800dd8cSBarry Smith if (rho > neP->sigma) break; 144eafb4bcbSBarry Smith PLogInfo((PetscObject)snes,"Trying again in smaller region\n"); 1456b5873e3SBarry Smith /* check to see if progress is hopeless */ 1466b5873e3SBarry Smith if (neP->delta < xnorm * epsmch) return -1; 1474800dd8cSBarry Smith } 1484800dd8cSBarry Smith fnorm = gnorm; 149fbe28522SBarry Smith snes->norm = fnorm; 1504800dd8cSBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 15139e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 15239e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 153fbe28522SBarry Smith VecNorm(X, &xnorm ); /* xnorm = || X || */ 154*a935fc98SLois Curfman McInnes if (snes->Monitor) 155*a935fc98SLois Curfman McInnes {(*snes->Monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);} 1564800dd8cSBarry Smith 1574800dd8cSBarry Smith /* Test for convergence */ 158fbe28522SBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 1594800dd8cSBarry Smith /* Verify solution is in corect location */ 16039e2f89bSBarry Smith if (X != snes->vec_sol) { 16139e2f89bSBarry Smith VecCopy(X, snes->vec_sol ); 16239e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 16339e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 16439e2f89bSBarry Smith } 1654800dd8cSBarry Smith break; 1664800dd8cSBarry Smith } 1674800dd8cSBarry Smith } 168614e12f8SBarry Smith if (i == maxits) *its = i-1; else *its = i + 1; 169fbe28522SBarry Smith return 0; 1704800dd8cSBarry Smith } 1714800dd8cSBarry Smith /*------------------------------------------------------------*/ 172fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes ) 1734800dd8cSBarry Smith { 174fbe28522SBarry Smith int ierr; 17581b6cf68SLois Curfman McInnes snes->nwork = 4; 17678b31e54SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERRQ(ierr); 17781b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 178fbe28522SBarry Smith return 0; 1794800dd8cSBarry Smith } 1804800dd8cSBarry Smith /*------------------------------------------------------------*/ 181fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj ) 1824800dd8cSBarry Smith { 183fbe28522SBarry Smith SNES snes = (SNES) obj; 184fbe28522SBarry Smith VecFreeVecs(snes->work, snes->nwork ); 18578b31e54SBarry Smith PETSCFREE(snes->data); 186fbe28522SBarry Smith return 0; 1874800dd8cSBarry Smith } 1884800dd8cSBarry Smith /*------------------------------------------------------------*/ 1894800dd8cSBarry Smith 190fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes) 1914800dd8cSBarry Smith { 192fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 193fbe28522SBarry Smith double tmp; 1944800dd8cSBarry Smith 195df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;} 196df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;} 197df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;} 198df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;} 199df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;} 200df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;} 201df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;} 202fbe28522SBarry Smith return 0; 2034800dd8cSBarry Smith } 2044800dd8cSBarry Smith 205fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes) 2064800dd8cSBarry Smith { 207fbe28522SBarry Smith SNES_TR *ctx = (SNES_TR *)snes->data; 208fbe28522SBarry Smith char *prefix = "-"; 209fbe28522SBarry Smith if (snes->prefix) prefix = snes->prefix; 210fbe28522SBarry Smith fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu); 211fbe28522SBarry Smith fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta); 212fbe28522SBarry Smith fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma); 213fbe28522SBarry Smith fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0); 214fbe28522SBarry Smith fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1); 215fbe28522SBarry Smith fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2); 216fbe28522SBarry Smith fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3); 217fbe28522SBarry Smith return 0; 2184800dd8cSBarry Smith } 2194800dd8cSBarry Smith 220*a935fc98SLois Curfman McInnes static int SNESView_TR(PetscObject obj,Viewer viewer) 221*a935fc98SLois Curfman McInnes { 222*a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 223*a935fc98SLois Curfman McInnes SNES_TR *tr = (SNES_TR *)snes->data; 224*a935fc98SLois Curfman McInnes FILE *fd = ViewerFileGetPointer_Private(viewer); 225*a935fc98SLois Curfman McInnes 226*a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," mu=%g, eta=%g, sigma=%g\n", 227*a935fc98SLois Curfman McInnes tr->mu,tr->eta,tr->sigma); 228*a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd, 229*a935fc98SLois Curfman McInnes " delta0=%g, delta1=%g, delta2=%g, delta3=%g\n", 230*a935fc98SLois Curfman McInnes tr->delta0,tr->delta1,tr->delta2,tr->delta3); 231*a935fc98SLois Curfman McInnes return 0; 232*a935fc98SLois Curfman McInnes } 233*a935fc98SLois Curfman McInnes 234fbe28522SBarry Smith int SNESCreate_TR(SNES snes ) 2354800dd8cSBarry Smith { 236fbe28522SBarry Smith SNES_TR *neP; 2374800dd8cSBarry Smith 238fbe28522SBarry Smith snes->type = SNES_NTR; 239*a935fc98SLois Curfman McInnes snes->method_class = SNES_T; 24006be10caSBarry Smith snes->setup = SNESSetUp_TR; 24106be10caSBarry Smith snes->solve = SNESSolve_TR; 242fbe28522SBarry Smith snes->destroy = SNESDestroy_TR; 2436b5873e3SBarry Smith snes->Converged = SNESDefaultConverged; 24406be10caSBarry Smith snes->printhelp = SNESPrintHelp_TR; 24506be10caSBarry Smith snes->setfromoptions = SNESSetFromOptions_TR; 246*a935fc98SLois Curfman McInnes snes->view = SNESView_TR; 247fbe28522SBarry Smith 24878b31e54SBarry Smith neP = PETSCNEW(SNES_TR); CHKPTRQ(neP); 249fbe28522SBarry Smith snes->data = (void *) neP; 250fbe28522SBarry Smith neP->mu = 0.25; 251fbe28522SBarry Smith neP->eta = 0.75; 252fbe28522SBarry Smith neP->delta = 0.0; 253fbe28522SBarry Smith neP->delta0 = 0.2; 254fbe28522SBarry Smith neP->delta1 = 0.3; 255fbe28522SBarry Smith neP->delta2 = 0.75; 256fbe28522SBarry Smith neP->delta3 = 2.0; 257fbe28522SBarry Smith neP->sigma = 0.0001; 258fbe28522SBarry Smith neP->itflag = 0; 2596b5873e3SBarry Smith return 0; 2604800dd8cSBarry Smith } 261