1a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER 2*76be9ce4SBarry Smith static char vcid[] = "$Id: snesut.c,v 1.35 1998/01/06 20:12:19 bsmith Exp bsmith $"; 3e7e93795SLois Curfman McInnes #endif 4e7e93795SLois Curfman McInnes 5e7e93795SLois Curfman McInnes #include <math.h> 670f55243SBarry Smith #include "src/snes/snesimpl.h" /*I "snes.h" I*/ 7e7e93795SLois Curfman McInnes 85615d1e5SSatish Balay #undef __FUNC__ 9d4bb536fSBarry Smith #define __FUNC__ "SNESDefaultMonitor" 104b828684SBarry Smith /*@C 11f525115eSLois Curfman McInnes SNESDefaultMonitor - Monitoring progress of the SNES solvers (default). 12e7e93795SLois Curfman McInnes 13e7e93795SLois Curfman McInnes Input Parameters: 14e7e93795SLois Curfman McInnes . snes - the SNES context 15e7e93795SLois Curfman McInnes . its - iteration number 16e7e93795SLois Curfman McInnes . fgnorm - 2-norm of residual (or gradient) 17e7e93795SLois Curfman McInnes . dummy - unused context 18e7e93795SLois Curfman McInnes 19e7e93795SLois Curfman McInnes Notes: 20e7e93795SLois Curfman McInnes For SNES_NONLINEAR_EQUATIONS methods the routine prints the 21e7e93795SLois Curfman McInnes residual norm at each iteration. 22e7e93795SLois Curfman McInnes 23e7e93795SLois Curfman McInnes For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the 24e7e93795SLois Curfman McInnes function value and gradient norm at each iteration. 25e7e93795SLois Curfman McInnes 26e7e93795SLois Curfman McInnes .keywords: SNES, nonlinear, default, monitor, norm 27e7e93795SLois Curfman McInnes 28e7e93795SLois Curfman McInnes .seealso: SNESSetMonitor() 29e7e93795SLois Curfman McInnes @*/ 30e7e93795SLois Curfman McInnes int SNESDefaultMonitor(SNES snes,int its,double fgnorm,void *dummy) 31e7e93795SLois Curfman McInnes { 323a40ed3dSBarry Smith PetscFunctionBegin; 33*76be9ce4SBarry Smith if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 3477c4ece6SBarry Smith PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm); 35*76be9ce4SBarry Smith } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 363a40ed3dSBarry Smith PetscPrintf(snes->comm,"iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm); 37*76be9ce4SBarry Smith } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class"); 383a40ed3dSBarry Smith PetscFunctionReturn(0); 39e7e93795SLois Curfman McInnes } 40e7e93795SLois Curfman McInnes /* ---------------------------------------------------------------- */ 415615d1e5SSatish Balay #undef __FUNC__ 42d4bb536fSBarry Smith #define __FUNC__ "SNESDefaultSMonitor" 43be1f7002SBarry Smith /* 44be1f7002SBarry Smith Default (short) SNES Monitor, same as SNESDefaultMonitor() except 45be1f7002SBarry Smith it prints fewer digits of the residual as the residual gets smaller. 46be1f7002SBarry Smith This is because the later digits are meaningless and are often 47be1f7002SBarry Smith different on different machines; by using this routine different 48be1f7002SBarry Smith machines will usually generate the same output. 49be1f7002SBarry Smith */ 50e7e93795SLois Curfman McInnes int SNESDefaultSMonitor(SNES snes,int its, double fgnorm,void *dummy) 51e7e93795SLois Curfman McInnes { 523a40ed3dSBarry Smith PetscFunctionBegin; 53e7e93795SLois Curfman McInnes if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 548f240d10SBarry Smith if (fgnorm > 1.e-9) { 55c7ab52efSLois Curfman McInnes PetscPrintf(snes->comm, "iter = %d, SNES Function norm %g \n",its,fgnorm); 563a40ed3dSBarry Smith } else if (fgnorm > 1.e-11){ 57c7ab52efSLois Curfman McInnes PetscPrintf(snes->comm, "iter = %d, SNES Function norm %5.3e \n",its,fgnorm); 583a40ed3dSBarry Smith } else { 59c7ab52efSLois Curfman McInnes PetscPrintf(snes->comm, "iter = %d, SNES Function norm < 1.e-11\n",its); 60e7e93795SLois Curfman McInnes } 61e7e93795SLois Curfman McInnes } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 628f240d10SBarry Smith if (fgnorm > 1.e-9) { 6377c4ece6SBarry Smith PetscPrintf(snes->comm, 643a40ed3dSBarry Smith "iter = %d, SNES Function value %g, Gradient norm %g \n",its,snes->fc,fgnorm); 653a40ed3dSBarry Smith } else if (fgnorm > 1.e-11) { 6677c4ece6SBarry Smith PetscPrintf(snes->comm, 673a40ed3dSBarry Smith "iter = %d, SNES Function value %g, Gradient norm %5.3e \n",its,snes->fc,fgnorm); 683a40ed3dSBarry Smith } else { 6977c4ece6SBarry Smith PetscPrintf(snes->comm, 703a40ed3dSBarry Smith "iter = %d, SNES Function value %g, Gradient norm < 1.e-11\n",its,snes->fc); 71e7e93795SLois Curfman McInnes } 72a8c6a408SBarry Smith } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Unknown method class"); 733a40ed3dSBarry Smith PetscFunctionReturn(0); 74e7e93795SLois Curfman McInnes } 75e7e93795SLois Curfman McInnes /* ---------------------------------------------------------------- */ 765615d1e5SSatish Balay #undef __FUNC__ 775615d1e5SSatish Balay #define __FUNC__ "SNESConverged_EQ_LS" 784b828684SBarry Smith /*@C 79f525115eSLois Curfman McInnes SNESConverged_EQ_LS - Monitors the convergence of the solvers for 80f525115eSLois Curfman McInnes systems of nonlinear equations (default). 81e7e93795SLois Curfman McInnes 82e7e93795SLois Curfman McInnes Input Parameters: 83e7e93795SLois Curfman McInnes . snes - the SNES context 84e7e93795SLois Curfman McInnes . xnorm - 2-norm of current iterate 85e7e93795SLois Curfman McInnes . pnorm - 2-norm of current step 86e7e93795SLois Curfman McInnes . fnorm - 2-norm of function 87e7e93795SLois Curfman McInnes . dummy - unused context 88e7e93795SLois Curfman McInnes 89e7e93795SLois Curfman McInnes Returns: 90e7e93795SLois Curfman McInnes $ 2 if ( fnorm < atol ), 91e7e93795SLois Curfman McInnes $ 3 if ( pnorm < xtol*xnorm ), 925d2e0e51SBarry Smith $ 4 if ( fnorm < rtol*fnorm0 ), 93e7e93795SLois Curfman McInnes $ -2 if ( nfct > maxf ), 94e7e93795SLois Curfman McInnes $ 0 otherwise, 95e7e93795SLois Curfman McInnes 96e7e93795SLois Curfman McInnes where 97e7e93795SLois Curfman McInnes $ maxf - maximum number of function evaluations, 98acd914d5SLois Curfman McInnes $ set with SNESSetTolerances() 99e7e93795SLois Curfman McInnes $ nfct - number of function evaluations, 100e7e93795SLois Curfman McInnes $ atol - absolute function norm tolerance, 101acd914d5SLois Curfman McInnes $ set with SNESSetTolerances() 102d7a720efSLois Curfman McInnes $ rtol - relative function norm tolerance, 103acd914d5SLois Curfman McInnes $ set with SNESSetTolerances() 104e7e93795SLois Curfman McInnes 105e7e93795SLois Curfman McInnes .keywords: SNES, nonlinear, default, converged, convergence 106e7e93795SLois Curfman McInnes 107e7e93795SLois Curfman McInnes .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged() 108e7e93795SLois Curfman McInnes @*/ 10940191667SLois Curfman McInnes int SNESConverged_EQ_LS(SNES snes,double xnorm,double pnorm,double fnorm,void *dummy) 110e7e93795SLois Curfman McInnes { 1113a40ed3dSBarry Smith PetscFunctionBegin; 112d252947aSBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) { 113a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_WRONG,0,"For SNES_NONLINEAR_EQUATIONS only"); 114d252947aSBarry Smith } 115082acdaeSLois Curfman McInnes /* Note: Reserve return code 1, -1 for compatibility with SNESConverged_EQ_TR */ 116d252947aSBarry Smith if (fnorm != fnorm) { 117981c4779SBarry Smith PLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaN\n"); 1183a40ed3dSBarry Smith PetscFunctionReturn(-3); 119d252947aSBarry Smith } 1205d2e0e51SBarry Smith if (fnorm <= snes->ttol) { 12194a424c1SBarry Smith PLogInfo(snes, 122981c4779SBarry Smith "SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol); 1233a40ed3dSBarry Smith PetscFunctionReturn(4); 1245d2e0e51SBarry Smith } 1255d2e0e51SBarry Smith 126e7e93795SLois Curfman McInnes if (fnorm < snes->atol) { 12794a424c1SBarry Smith PLogInfo(snes, 128981c4779SBarry Smith "SNESConverged_EQ_LS: Converged due to function norm %g < %g\n",fnorm,snes->atol); 1293a40ed3dSBarry Smith PetscFunctionReturn(2); 130e7e93795SLois Curfman McInnes } 131e7e93795SLois Curfman McInnes if (pnorm < snes->xtol*(xnorm)) { 13294a424c1SBarry Smith PLogInfo(snes, 133981c4779SBarry Smith "SNESConverged_EQ_LS: Converged due to small update length: %g < %g * %g\n", 134e7e93795SLois Curfman McInnes pnorm,snes->xtol,xnorm); 1353a40ed3dSBarry Smith PetscFunctionReturn(3); 136e7e93795SLois Curfman McInnes } 137e7e93795SLois Curfman McInnes if (snes->nfuncs > snes->max_funcs) { 138981c4779SBarry Smith PLogInfo(snes,"SNESConverged_EQ_LS: Exceeded maximum number of function evaluations: %d > %d\n", 139e7e93795SLois Curfman McInnes snes->nfuncs, snes->max_funcs ); 1403a40ed3dSBarry Smith PetscFunctionReturn(-2); 141e7e93795SLois Curfman McInnes } 1423a40ed3dSBarry Smith PetscFunctionReturn(0); 143e7e93795SLois Curfman McInnes } 144e7e93795SLois Curfman McInnes /* ------------------------------------------------------------ */ 1455615d1e5SSatish Balay #undef __FUNC__ 1465615d1e5SSatish Balay #define __FUNC__ "SNES_KSP_SetConvergenceTestEW" 147e7e93795SLois Curfman McInnes /*@ 148f525115eSLois Curfman McInnes SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test 149e7e93795SLois Curfman McInnes for the linear solvers within an inexact Newton method. 150e7e93795SLois Curfman McInnes 151e7e93795SLois Curfman McInnes Input Parameter: 152e7e93795SLois Curfman McInnes . snes - SNES context 153e7e93795SLois Curfman McInnes 154e7e93795SLois Curfman McInnes Notes: 155e7e93795SLois Curfman McInnes Currently, the default is to use a constant relative tolerance for 156e7e93795SLois Curfman McInnes the inner linear solvers. Alternatively, one can use the 157e7e93795SLois Curfman McInnes Eisenstat-Walker method, where the relative convergence tolerance 158e7e93795SLois Curfman McInnes is reset at each Newton iteration according progress of the nonlinear 159e7e93795SLois Curfman McInnes solver. 160e7e93795SLois Curfman McInnes 161e7e93795SLois Curfman McInnes Reference: 162e7e93795SLois Curfman McInnes S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 163e7e93795SLois Curfman McInnes inexact Newton method", Utah State University Math. Stat. Dept. Res. 164e7e93795SLois Curfman McInnes Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 165e7e93795SLois Curfman McInnes 166e7e93795SLois Curfman McInnes .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton 167e7e93795SLois Curfman McInnes @*/ 168e7e93795SLois Curfman McInnes int SNES_KSP_SetConvergenceTestEW(SNES snes) 169e7e93795SLois Curfman McInnes { 1703a40ed3dSBarry Smith PetscFunctionBegin; 171e7e93795SLois Curfman McInnes snes->ksp_ewconv = 1; 1723a40ed3dSBarry Smith PetscFunctionReturn(0); 173e7e93795SLois Curfman McInnes } 174e7e93795SLois Curfman McInnes 1755615d1e5SSatish Balay #undef __FUNC__ 1765615d1e5SSatish Balay #define __FUNC__ "SNES_KSP_SetParametersEW" 177e7e93795SLois Curfman McInnes /*@ 178e7e93795SLois Curfman McInnes SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker 179e7e93795SLois Curfman McInnes convergence criteria for the linear solvers within an inexact 180e7e93795SLois Curfman McInnes Newton method. 181e7e93795SLois Curfman McInnes 182e7e93795SLois Curfman McInnes Input Parameters: 183e7e93795SLois Curfman McInnes . snes - SNES context 184e7e93795SLois Curfman McInnes . version - version 1 or 2 (default is 2) 185e7e93795SLois Curfman McInnes . rtol_0 - initial relative tolerance 186e7e93795SLois Curfman McInnes $ (0 <= rtol_0 < 1) 187e7e93795SLois Curfman McInnes . rtol_max - maximum relative tolerance 188e7e93795SLois Curfman McInnes $ (0 <= rtol_max < 1) 189e7e93795SLois Curfman McInnes . alpha - power for version 2 rtol computation 190e7e93795SLois Curfman McInnes $ (1 < alpha <= 2) 191e7e93795SLois Curfman McInnes . alpha2 - power for safeguard 192e7e93795SLois Curfman McInnes . gamma2 - multiplicative factor for version 2 rtol computation 193e7e93795SLois Curfman McInnes $ (0 <= gamma2 <= 1) 194e7e93795SLois Curfman McInnes . threshold - threshold for imposing safeguard 195e7e93795SLois Curfman McInnes $ (0 < threshold < 1) 196e7e93795SLois Curfman McInnes 197e7e93795SLois Curfman McInnes Note: 198e7e93795SLois Curfman McInnes Use PETSC_DEFAULT to retain the default for any of the parameters. 199e7e93795SLois Curfman McInnes 200e7e93795SLois Curfman McInnes Reference: 201e7e93795SLois Curfman McInnes S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 202e7e93795SLois Curfman McInnes inexact Newton method", Utah State University Math. Stat. Dept. Res. 203e7e93795SLois Curfman McInnes Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 204e7e93795SLois Curfman McInnes 205e7e93795SLois Curfman McInnes .keywords: SNES, KSP, Eisenstat, Walker, set, parameters 206e7e93795SLois Curfman McInnes 207e7e93795SLois Curfman McInnes .seealso: SNES_KSP_SetConvergenceTestEW() 208e7e93795SLois Curfman McInnes @*/ 209e7e93795SLois Curfman McInnes int SNES_KSP_SetParametersEW(SNES snes,int version,double rtol_0, 210e7e93795SLois Curfman McInnes double rtol_max,double gamma2,double alpha, 211e7e93795SLois Curfman McInnes double alpha2,double threshold) 212e7e93795SLois Curfman McInnes { 213e7e93795SLois Curfman McInnes SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 2143a40ed3dSBarry Smith 2153a40ed3dSBarry Smith PetscFunctionBegin; 216a8c6a408SBarry Smith if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context existing"); 217e7e93795SLois Curfman McInnes if (version != PETSC_DEFAULT) kctx->version = version; 218e7e93795SLois Curfman McInnes if (rtol_0 != PETSC_DEFAULT) kctx->rtol_0 = rtol_0; 219e7e93795SLois Curfman McInnes if (rtol_max != PETSC_DEFAULT) kctx->rtol_max = rtol_max; 220e7e93795SLois Curfman McInnes if (gamma2 != PETSC_DEFAULT) kctx->gamma = gamma2; 221e7e93795SLois Curfman McInnes if (alpha != PETSC_DEFAULT) kctx->alpha = alpha; 222e7e93795SLois Curfman McInnes if (alpha2 != PETSC_DEFAULT) kctx->alpha2 = alpha2; 223e7e93795SLois Curfman McInnes if (threshold != PETSC_DEFAULT) kctx->threshold = threshold; 224a8c6a408SBarry Smith if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) { 225a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_0 < 1.0\n"); 226a8c6a408SBarry Smith } 227a8c6a408SBarry Smith if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) { 228a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= rtol_max < 1.0\n"); 229a8c6a408SBarry Smith } 230a8c6a408SBarry Smith if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) { 231a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 < threshold < 1.0\n"); 232a8c6a408SBarry Smith } 233a8c6a408SBarry Smith if (kctx->gamma < 0.0 || kctx->gamma > 1.0) { 234a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"0.0 <= alpha <= 1.0\n"); 235a8c6a408SBarry Smith } 236a8c6a408SBarry Smith if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) { 237a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"1.0 < alpha <= 2.0\n"); 238a8c6a408SBarry Smith } 239a8c6a408SBarry Smith if (kctx->version != 1 && kctx->version !=2) { 240a8c6a408SBarry Smith SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 and 2 are supported"); 241a8c6a408SBarry Smith } 2423a40ed3dSBarry Smith PetscFunctionReturn(0); 243e7e93795SLois Curfman McInnes } 244e7e93795SLois Curfman McInnes 2455615d1e5SSatish Balay #undef __FUNC__ 2465615d1e5SSatish Balay #define __FUNC__ "SNES_KSP_EW_ComputeRelativeTolerance_Private" 247e7e93795SLois Curfman McInnes int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp) 248e7e93795SLois Curfman McInnes { 249e7e93795SLois Curfman McInnes SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 250e7e93795SLois Curfman McInnes double rtol, stol; 251e7e93795SLois Curfman McInnes int ierr; 2523a40ed3dSBarry Smith 2533a40ed3dSBarry Smith PetscFunctionBegin; 254a8c6a408SBarry Smith if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context exists"); 255e7e93795SLois Curfman McInnes if (snes->iter == 1) { 256e7e93795SLois Curfman McInnes rtol = kctx->rtol_0; 257e7e93795SLois Curfman McInnes } else { 258e7e93795SLois Curfman McInnes if (kctx->version == 1) { 259e7e93795SLois Curfman McInnes rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last; 260e7e93795SLois Curfman McInnes if (rtol < 0.0) rtol = -rtol; 261e7e93795SLois Curfman McInnes stol = pow(kctx->rtol_last,kctx->alpha2); 2620452661fSBarry Smith if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 263e7e93795SLois Curfman McInnes } else if (kctx->version == 2) { 264e7e93795SLois Curfman McInnes rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha); 265e7e93795SLois Curfman McInnes stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha); 2660452661fSBarry Smith if (stol > kctx->threshold) rtol = PetscMax(rtol,stol); 267a8c6a408SBarry Smith } else SETERRQ( PETSC_ERR_ARG_OUTOFRANGE,0,"Only versions 1 or 2 are supported"); 268e7e93795SLois Curfman McInnes } 2690452661fSBarry Smith rtol = PetscMin(rtol,kctx->rtol_max); 270e7e93795SLois Curfman McInnes kctx->rtol_last = rtol; 271981c4779SBarry Smith PLogInfo(snes,"SNESConverged_EQ_LS: iter %d, Eisenstat-Walker (version %d) KSP rtol = %g\n", 272e7e93795SLois Curfman McInnes snes->iter,kctx->version,rtol); 2733131a8b6SLois Curfman McInnes ierr = KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT); CHKERRQ(ierr); 274e7e93795SLois Curfman McInnes kctx->norm_last = snes->norm; 2753a40ed3dSBarry Smith PetscFunctionReturn(0); 276e7e93795SLois Curfman McInnes } 277e7e93795SLois Curfman McInnes 2785615d1e5SSatish Balay #undef __FUNC__ 2795615d1e5SSatish Balay #define __FUNC__ "SNES_KSP_EW_Converged_Private" 280e7e93795SLois Curfman McInnes int SNES_KSP_EW_Converged_Private(KSP ksp,int n,double rnorm,void *ctx) 281e7e93795SLois Curfman McInnes { 282e7e93795SLois Curfman McInnes SNES snes = (SNES)ctx; 283e7e93795SLois Curfman McInnes SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx; 284e7e93795SLois Curfman McInnes int convinfo; 285e7e93795SLois Curfman McInnes 2863a40ed3dSBarry Smith PetscFunctionBegin; 287a8c6a408SBarry Smith if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,0,"No Eisenstat-Walker context set"); 288e7e93795SLois Curfman McInnes if (n == 0) SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp); 289e7e93795SLois Curfman McInnes convinfo = KSPDefaultConverged(ksp,n,rnorm,ctx); 290e7e93795SLois Curfman McInnes kctx->lresid_last = rnorm; 2913a40ed3dSBarry Smith if (convinfo) { 292981c4779SBarry Smith PLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%g\n",n,rnorm); 2933a40ed3dSBarry Smith } 2943a40ed3dSBarry Smith PetscFunctionReturn(convinfo); 295e7e93795SLois Curfman McInnes } 296e7e93795SLois Curfman McInnes 297e7e93795SLois Curfman McInnes 298