PetscErrorCode KSPSolve_FGMRES(KSP ksp) { PetscErrorCode ierr; PetscInt cycle_its = 0; /* iterations done in a call to KSPFGMRESCycle */ KSP_FGMRES *fgmres = (KSP_FGMRES *)ksp->data; PetscBool diagonalscale; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its = 0; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); /* Compute the initial (NOT preconditioned) residual */ if (!ksp->guess_zero) { ierr = KSPFGMRESResidual(ksp);CHKERRQ(ierr); } else { /* guess is 0 so residual is F (which is in ksp->vec_rhs) */ ierr = VecCopy(ksp->vec_rhs,VEC_VV(0));CHKERRQ(ierr); } /* now the residual is in VEC_VV(0) - which is what KSPFGMRESCycle expects... */ ierr = KSPFGMRESCycle(&cycle_its,ksp);CHKERRQ(ierr); while (!ksp->reason) { ierr = KSPFGMRESResidual(ksp);CHKERRQ(ierr); if (ksp->its >= ksp->max_it) break; ierr = KSPFGMRESCycle(&cycle_its,ksp);CHKERRQ(ierr); } /* mark lack of convergence */ if (ksp->its >= ksp->max_it && !ksp->reason) ksp->reason = KSP_DIVERGED_ITS; PetscFunctionReturn(0); }
PetscErrorCode PETSC_DLLEXPORT PetscObjectChangeTypeName(PetscObject obj,const char type_name[]) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeader(obj,1); ierr = PetscObjectTakeAccess(obj);CHKERRQ(ierr); ierr = PetscStrfree(obj->type_name);CHKERRQ(ierr); ierr = PetscStrallocpy(type_name,&obj->type_name);CHKERRQ(ierr); ierr = PetscObjectGrantAccess(obj);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_LGMRES(KSP ksp) { PetscErrorCode ierr; PetscInt cycle_its; /* iterations done in a call to KSPLGMRESCycle */ PetscInt itcount; /* running total of iterations, incl. those in restarts */ KSP_LGMRES *lgmres = (KSP_LGMRES *)ksp->data; PetscBool guess_zero = ksp->guess_zero; PetscInt ii; /*LGMRES_MOD variable */ PetscFunctionBegin; if (ksp->calc_sings && !lgmres->Rsvd) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_ORDER,"Must call KSPSetComputeSingularValues() before KSPSetUp() is called"); ierr = PetscObjectTakeAccess(ksp); CHKERRQ(ierr); ksp->its = 0; lgmres->aug_ct = 0; lgmres->matvecs = 0; ierr = PetscObjectGrantAccess(ksp); CHKERRQ(ierr); /* initialize */ itcount = 0; ksp->reason = KSP_CONVERGED_ITERATING; /*LGMRES_MOD*/ for (ii=0; ii<lgmres->aug_dim; ii++) { lgmres->aug_order[ii] = 0; } while (!ksp->reason) { /* calc residual - puts in VEC_VV(0) */ ierr = KSPInitialResidual(ksp,ksp->vec_sol,VEC_TEMP,VEC_TEMP_MATOP,VEC_VV(0),ksp->vec_rhs); CHKERRQ(ierr); ierr = KSPLGMRESCycle(&cycle_its,ksp); CHKERRQ(ierr); itcount += cycle_its; if (itcount >= ksp->max_it) { if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS; break; } ksp->guess_zero = PETSC_FALSE; /* every future call to KSPInitialResidual() will have nonzero guess */ } ksp->guess_zero = guess_zero; /* restore if user provided nonzero initial guess */ PetscFunctionReturn(0); }
PetscErrorCode KSPLGMRESCycle(PetscInt *itcount,KSP ksp) { KSP_LGMRES *lgmres = (KSP_LGMRES *)(ksp->data); PetscReal res_norm, res; PetscReal hapbnd, tt; PetscScalar tmp; PetscBool hapend = PETSC_FALSE; /* indicates happy breakdown ending */ PetscErrorCode ierr; PetscInt loc_it; /* local count of # of dir. in Krylov space */ PetscInt max_k = lgmres->max_k; /* max approx space size */ PetscInt max_it = ksp->max_it; /* max # of overall iterations for the method */ /* LGMRES_MOD - new variables*/ PetscInt aug_dim = lgmres->aug_dim; PetscInt spot = 0; PetscInt order = 0; PetscInt it_arnoldi; /* number of arnoldi steps to take */ PetscInt it_total; /* total number of its to take (=approx space size)*/ PetscInt ii, jj; PetscReal tmp_norm; PetscScalar inv_tmp_norm; PetscScalar *avec; PetscFunctionBegin; /* Number of pseudo iterations since last restart is the number of prestart directions */ loc_it = 0; /* LGMRES_MOD: determine number of arnoldi steps to take */ /* if approx_constant then we keep the space the same size even if we don't have the full number of aug vectors yet*/ if (lgmres->approx_constant) { it_arnoldi = max_k - lgmres->aug_ct; } else { it_arnoldi = max_k - aug_dim; } it_total = it_arnoldi + lgmres->aug_ct; /* initial residual is in VEC_VV(0) - compute its norm*/ ierr = VecNorm(VEC_VV(0),NORM_2,&res_norm); CHKERRQ(ierr); res = res_norm; /* first entry in right-hand-side of hessenberg system is just the initial residual norm */ *GRS(0) = res_norm; /* check for the convergence */ if (!res) { if (itcount) *itcount = 0; ksp->reason = KSP_CONVERGED_ATOL; ierr = PetscInfo(ksp,"Converged due to zero residual norm on entry\n"); CHKERRQ(ierr); PetscFunctionReturn(0); } /* scale VEC_VV (the initial residual) */ tmp = 1.0/res_norm; ierr = VecScale(VEC_VV(0),tmp); CHKERRQ(ierr); ksp->rnorm = res; /* note: (lgmres->it) is always set one less than (loc_it) It is used in KSPBUILDSolution_LGMRES, where it is passed to KSPLGMRESBuildSoln. Note that when KSPLGMRESBuildSoln is called from this function, (loc_it -1) is passed, so the two are equivalent */ lgmres->it = (loc_it - 1); /* MAIN ITERATION LOOP BEGINNING*/ /* keep iterating until we have converged OR generated the max number of directions OR reached the max number of iterations for the method */ ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP); CHKERRQ(ierr); while (!ksp->reason && loc_it < it_total && ksp->its < max_it) { /* LGMRES_MOD: changed to it_total */ KSPLogResidualHistory(ksp,res); lgmres->it = (loc_it - 1); ierr = KSPMonitor(ksp,ksp->its,res); CHKERRQ(ierr); /* see if more space is needed for work vectors */ if (lgmres->vv_allocated <= loc_it + VEC_OFFSET + 1) { ierr = KSPLGMRESGetNewVectors(ksp,loc_it+1); CHKERRQ(ierr); /* (loc_it+1) is passed in as number of the first vector that should be allocated */ } /*LGMRES_MOD: decide whether this is an arnoldi step or an aug step */ if (loc_it < it_arnoldi) { /* Arnoldi */ ierr = KSP_PCApplyBAorAB(ksp,VEC_VV(loc_it),VEC_VV(1+loc_it),VEC_TEMP_MATOP); CHKERRQ(ierr); } else { /*aug step */ order = loc_it - it_arnoldi + 1; /* which aug step */ for (ii=0; ii<aug_dim; ii++) { if (lgmres->aug_order[ii] == order) { spot = ii; break; /* must have this because there will be duplicates before aug_ct = aug_dim */ } } ierr = VecCopy(A_AUGVEC(spot), VEC_VV(1+loc_it)); CHKERRQ(ierr); /*note: an alternate implementation choice would be to only save the AUGVECS and not A_AUGVEC and then apply the PC here to the augvec */ } /* update hessenberg matrix and do Gram-Schmidt - new direction is in VEC_VV(1+loc_it)*/ ierr = (*lgmres->orthog)(ksp,loc_it); CHKERRQ(ierr); /* new entry in hessenburg is the 2-norm of our new direction */ ierr = VecNorm(VEC_VV(loc_it+1),NORM_2,&tt); CHKERRQ(ierr); *HH(loc_it+1,loc_it) = tt; *HES(loc_it+1,loc_it) = tt; /* check for the happy breakdown */ hapbnd = PetscAbsScalar(tt / *GRS(loc_it));/* GRS(loc_it) contains the res_norm from the last iteration */ if (hapbnd > lgmres->haptol) hapbnd = lgmres->haptol; if (tt > hapbnd) { tmp = 1.0/tt; ierr = VecScale(VEC_VV(loc_it+1),tmp); CHKERRQ(ierr); /* scale new direction by its norm */ } else { ierr = PetscInfo2(ksp,"Detected happy breakdown, current hapbnd = %G tt = %G\n",hapbnd,tt); CHKERRQ(ierr); hapend = PETSC_TRUE; } /* Now apply rotations to new col of hessenberg (and right side of system), calculate new rotation, and get new residual norm at the same time*/ ierr = KSPLGMRESUpdateHessenberg(ksp,loc_it,hapend,&res); CHKERRQ(ierr); if (ksp->reason) break; loc_it++; lgmres->it = (loc_it-1); /* Add this here in case it has converged */ ierr = PetscObjectTakeAccess(ksp); CHKERRQ(ierr); ksp->its++; ksp->rnorm = res; ierr = PetscObjectGrantAccess(ksp); CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP); CHKERRQ(ierr); /* Catch error in happy breakdown and signal convergence and break from loop */ if (hapend) { if (!ksp->reason) { SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_PLIB,"You reached the happy break down,but convergence was not indicated. Residual norm = %G",res); } break; } } /* END OF ITERATION LOOP */ KSPLogResidualHistory(ksp,res); /* Monitor if we know that we will not return for a restart */ if (ksp->reason || ksp->its >= max_it) { ierr = KSPMonitor(ksp, ksp->its, res); CHKERRQ(ierr); } if (itcount) *itcount = loc_it; /* Down here we have to solve for the "best" coefficients of the Krylov columns, add the solution values together, and possibly unwind the preconditioning from the solution */ /* Form the solution (or the solution so far) */ /* Note: must pass in (loc_it-1) for iteration count so that KSPLGMRESBuildSoln properly navigates */ ierr = KSPLGMRESBuildSoln(GRS(0),ksp->vec_sol,ksp->vec_sol,ksp,loc_it-1); CHKERRQ(ierr); /* LGMRES_MOD collect aug vector and A*augvector for future restarts - only if we will be restarting (i.e. this cycle performed it_total iterations) */ if (!ksp->reason && ksp->its < max_it && aug_dim > 0) { /*AUG_TEMP contains the new augmentation vector (assigned in KSPLGMRESBuildSoln) */ if (!lgmres->aug_ct) { spot = 0; lgmres->aug_ct++; } else if (lgmres->aug_ct < aug_dim) { spot = lgmres->aug_ct; lgmres->aug_ct++; } else { /* truncate */ for (ii=0; ii<aug_dim; ii++) { if (lgmres->aug_order[ii] == aug_dim) { spot = ii; } } } ierr = VecCopy(AUG_TEMP, AUGVEC(spot)); CHKERRQ(ierr); /*need to normalize */ ierr = VecNorm(AUGVEC(spot), NORM_2, &tmp_norm); CHKERRQ(ierr); inv_tmp_norm = 1.0/tmp_norm; ierr = VecScale(AUGVEC(spot),inv_tmp_norm); CHKERRQ(ierr); /*set new aug vector to order 1 - move all others back one */ for (ii=0; ii < aug_dim; ii++) { AUG_ORDER(ii)++; } AUG_ORDER(spot) = 1; /*now add the A*aug vector to A_AUGVEC(spot) - this is independ. of preconditioning type*/ /* want V*H*y - y is in GRS, V is in VEC_VV and H is in HES */ /* first do H+*y */ avec = lgmres->hwork; ierr = PetscMemzero(avec,(it_total+1)*sizeof(*avec)); CHKERRQ(ierr); for (ii=0; ii < it_total + 1; ii++) { for (jj=0; jj <= ii+1 && jj < it_total+1; jj++) { avec[jj] += *HES(jj ,ii) * *GRS(ii); } } /*now multiply result by V+ */ ierr = VecSet(VEC_TEMP,0.0); CHKERRQ(ierr); ierr = VecMAXPY(VEC_TEMP, it_total+1, avec, &VEC_VV(0)); CHKERRQ(ierr); /*answer is in VEC_TEMP*/ /*copy answer to aug location and scale*/ ierr = VecCopy(VEC_TEMP, A_AUGVEC(spot)); CHKERRQ(ierr); ierr = VecScale(A_AUGVEC(spot),inv_tmp_norm); CHKERRQ(ierr); } PetscFunctionReturn(0); }
PetscErrorCode KSPFGMRESCycle(PetscInt *itcount,KSP ksp) { KSP_FGMRES *fgmres = (KSP_FGMRES *)(ksp->data); PetscReal res_norm; PetscReal hapbnd,tt; PetscBool hapend = PETSC_FALSE; /* indicates happy breakdown ending */ PetscErrorCode ierr; PetscInt loc_it; /* local count of # of dir. in Krylov space */ PetscInt max_k = fgmres->max_k; /* max # of directions Krylov space */ Mat Amat,Pmat; MatStructure pflag; PetscFunctionBegin; /* Number of pseudo iterations since last restart is the number of prestart directions */ loc_it = 0; /* note: (fgmres->it) is always set one less than (loc_it) It is used in KSPBUILDSolution_FGMRES, where it is passed to KSPFGMRESBuildSoln. Note that when KSPFGMRESBuildSoln is called from this function, (loc_it -1) is passed, so the two are equivalent */ fgmres->it = (loc_it - 1); /* initial residual is in VEC_VV(0) - compute its norm*/ ierr = VecNorm(VEC_VV(0),NORM_2,&res_norm);CHKERRQ(ierr); /* first entry in right-hand-side of hessenberg system is just the initial residual norm */ *RS(0) = res_norm; ksp->rnorm = res_norm; KSPLogResidualHistory(ksp,res_norm); /* check for the convergence - maybe the current guess is good enough */ ierr = (*ksp->converged)(ksp,ksp->its,res_norm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) { if (itcount) *itcount = 0; PetscFunctionReturn(0); } /* scale VEC_VV (the initial residual) */ ierr = VecScale(VEC_VV(0),1.0/res_norm);CHKERRQ(ierr); /* MAIN ITERATION LOOP BEGINNING*/ /* keep iterating until we have converged OR generated the max number of directions OR reached the max number of iterations for the method */ while (!ksp->reason && loc_it < max_k && ksp->its < ksp->max_it) { if (loc_it) KSPLogResidualHistory(ksp,res_norm); fgmres->it = (loc_it - 1); ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); /* see if more space is needed for work vectors */ if (fgmres->vv_allocated <= loc_it + VEC_OFFSET + 1) { ierr = KSPFGMRESGetNewVectors(ksp,loc_it+1);CHKERRQ(ierr); /* (loc_it+1) is passed in as number of the first vector that should be allocated */ } /* CHANGE THE PRECONDITIONER? */ /* ModifyPC is the callback function that can be used to change the PC or its attributes before its applied */ (*fgmres->modifypc)(ksp,ksp->its,loc_it,res_norm,fgmres->modifyctx); /* apply PRECONDITIONER to direction vector and store with preconditioned vectors in prevec */ ierr = KSP_PCApply(ksp,VEC_VV(loc_it),PREVEC(loc_it));CHKERRQ(ierr); ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); /* Multiply preconditioned vector by operator - put in VEC_VV(loc_it+1) */ ierr = MatMult(Amat,PREVEC(loc_it),VEC_VV(1+loc_it));CHKERRQ(ierr); /* update hessenberg matrix and do Gram-Schmidt - new direction is in VEC_VV(1+loc_it)*/ ierr = (*fgmres->orthog)(ksp,loc_it);CHKERRQ(ierr); /* new entry in hessenburg is the 2-norm of our new direction */ ierr = VecNorm(VEC_VV(loc_it+1),NORM_2,&tt);CHKERRQ(ierr); *HH(loc_it+1,loc_it) = tt; *HES(loc_it+1,loc_it) = tt; /* Happy Breakdown Check */ hapbnd = PetscAbsScalar((tt) / *RS(loc_it)); /* RS(loc_it) contains the res_norm from the last iteration */ hapbnd = PetscMin(fgmres->haptol,hapbnd); if (tt > hapbnd) { /* scale new direction by its norm */ ierr = VecScale(VEC_VV(loc_it+1),1.0/tt);CHKERRQ(ierr); } else { /* This happens when the solution is exactly reached. */ /* So there is no new direction... */ ierr = VecSet(VEC_TEMP,0.0);CHKERRQ(ierr); /* set VEC_TEMP to 0 */ hapend = PETSC_TRUE; } /* note that for FGMRES we could get HES(loc_it+1, loc_it) = 0 and the current solution would not be exact if HES was singular. Note that HH non-singular implies that HES is no singular, and HES is guaranteed to be nonsingular when PREVECS are linearly independent and A is nonsingular (in GMRES, the nonsingularity of A implies the nonsingularity of HES). So we should really add a check to verify that HES is nonsingular.*/ /* Now apply rotations to new col of hessenberg (and right side of system), calculate new rotation, and get new residual norm at the same time*/ ierr = KSPFGMRESUpdateHessenberg(ksp,loc_it,hapend,&res_norm);CHKERRQ(ierr); if (ksp->reason) break; loc_it++; fgmres->it = (loc_it-1); /* Add this here in case it has converged */ ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = res_norm; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,ksp->its,res_norm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); /* Catch error in happy breakdown and signal convergence and break from loop */ if (hapend) { if (!ksp->reason) { SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_PLIB,"You reached the happy break down,but convergence was not indicated."); } break; } } /* END OF ITERATION LOOP */ KSPLogResidualHistory(ksp,res_norm); /* Monitor if we know that we will not return for a restart */ if (ksp->reason || ksp->its >= ksp->max_it) { ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); } if (itcount) *itcount = loc_it; /* Down here we have to solve for the "best" coefficients of the Krylov columns, add the solution values together, and possibly unwind the preconditioning from the solution */ /* Form the solution (or the solution so far) */ /* Note: must pass in (loc_it-1) for iteration count so that KSPFGMRESBuildSoln properly navigates */ ierr = KSPFGMRESBuildSoln(RS(0),ksp->vec_sol,ksp->vec_sol,ksp,loc_it-1);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode SNESSolve_TR(SNES snes) { SNES_TR *neP = (SNES_TR*)snes->data; Vec X,F,Y,G,Ytmp; PetscErrorCode ierr; PetscInt maxits,i,lits; MatStructure flg = DIFFERENT_NONZERO_PATTERN; PetscReal rho,fnorm,gnorm,gpnorm,xnorm=0,delta,nrm,ynorm,norm1; PetscScalar cnorm; KSP ksp; SNESConvergedReason reason = SNES_CONVERGED_ITERATING; PetscBool conv = PETSC_FALSE,breakout = PETSC_FALSE; PetscBool domainerror; PetscFunctionBegin; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* solution vector */ F = snes->vec_func; /* residual vector */ Y = snes->work[0]; /* work vectors */ G = snes->work[1]; Ytmp = snes->work[2]; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); /* F(X) */ ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- || F || */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); delta = neP->delta0*fnorm; neP->delta = delta; SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); /* Set the stopping criteria to use the More' trick. */ ierr = PetscOptionsGetBool(PETSC_NULL,"-snes_tr_ksp_regular_convergence_test",&conv,PETSC_NULL);CHKERRQ(ierr); if (!conv) { SNES_TR_KSPConverged_Ctx *ctx; ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); ierr = PetscNew(SNES_TR_KSPConverged_Ctx,&ctx);CHKERRQ(ierr); ctx->snes = snes; ierr = KSPDefaultConvergedCreate(&ctx->ctx);CHKERRQ(ierr); ierr = KSPSetConvergenceTest(ksp,SNES_TR_KSPConverged_Private,ctx,SNES_TR_KSPConverged_Destroy);CHKERRQ(ierr); ierr = PetscInfo(snes,"Using Krylov convergence test SNES_TR_KSPConverged_Private\n");CHKERRQ(ierr); } for (i=0; i<maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* Solve J Y = F, where J is Jacobian matrix */ ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); ierr = SNES_KSPSolve(snes,snes->ksp,F,Ytmp);CHKERRQ(ierr); ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); ierr = VecNorm(Ytmp,NORM_2,&nrm);CHKERRQ(ierr); norm1 = nrm; while(1) { ierr = VecCopy(Ytmp,Y);CHKERRQ(ierr); nrm = norm1; /* Scale Y if need be and predict new value of F norm */ if (nrm >= delta) { nrm = delta/nrm; gpnorm = (1.0 - nrm)*fnorm; cnorm = nrm; ierr = PetscInfo1(snes,"Scaling direction by %G\n",nrm);CHKERRQ(ierr); ierr = VecScale(Y,cnorm);CHKERRQ(ierr); nrm = gpnorm; ynorm = delta; } else { gpnorm = 0.0; ierr = PetscInfo(snes,"Direction is in Trust Region\n");CHKERRQ(ierr); ynorm = nrm; } ierr = VecAYPX(Y,-1.0,X);CHKERRQ(ierr); /* Y <- X - Y */ ierr = VecCopy(X,snes->vec_sol_update);CHKERRQ(ierr); ierr = SNESComputeFunction(snes,Y,G);CHKERRQ(ierr); /* F(X) */ ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); /* gnorm <- || g || */ if (fnorm == gpnorm) rho = 0.0; else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm); /* Update size of trust region */ if (rho < neP->mu) delta *= neP->delta1; else if (rho < neP->eta) delta *= neP->delta2; else delta *= neP->delta3; ierr = PetscInfo3(snes,"fnorm=%G, gnorm=%G, ynorm=%G\n",fnorm,gnorm,ynorm);CHKERRQ(ierr); ierr = PetscInfo3(snes,"gpred=%G, rho=%G, delta=%G\n",gpnorm,rho,delta);CHKERRQ(ierr); neP->delta = delta; if (rho > neP->sigma) break; ierr = PetscInfo(snes,"Trying again in smaller region\n");CHKERRQ(ierr); /* check to see if progress is hopeless */ neP->itflag = PETSC_FALSE; ierr = SNES_TR_Converged_Private(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr); if (!reason) { ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr); } if (reason) { /* We're not progressing, so return with the current iterate */ ierr = SNESMonitor(snes,i+1,fnorm);CHKERRQ(ierr); breakout = PETSC_TRUE; break; } snes->numFailures++; } if (!breakout) { /* Update function and solution vectors */ fnorm = gnorm; ierr = VecCopy(G,F);CHKERRQ(ierr); ierr = VecCopy(Y,X);CHKERRQ(ierr); /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,lits); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence, xnorm = || X || */ neP->itflag = PETSC_TRUE; if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);CHKERRQ(ierr); if (reason) break; } else { break; } } if (i == maxits) { ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); if (!reason) reason = SNES_DIVERGED_MAX_IT; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->reason = reason; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_BiCG(KSP ksp) { PetscErrorCode ierr; PetscInt i; PetscTruth diagonalscale; PetscScalar dpi,a=1.0,beta,betaold=1.0,b,ma; PetscReal dp; Vec X,B,Zl,Zr,Rl,Rr,Pl,Pr; Mat Amat,Pmat; MatStructure pflag; PetscFunctionBegin; if (ksp->normtype == KSP_NORM_NATURAL) SETERRQ(PETSC_ERR_SUP,"Cannot use natural residual norm with KSPIBCGS"); ierr = PCDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); X = ksp->vec_sol; B = ksp->vec_rhs; Rl = ksp->work[0]; Zl = ksp->work[1]; Pl = ksp->work[2]; Rr = ksp->work[3]; Zr = ksp->work[4]; Pr = ksp->work[5]; ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,X,Rr);CHKERRQ(ierr); /* r <- b - Ax */ ierr = VecAYPX(Rr,-1.0,B);CHKERRQ(ierr); } else { ierr = VecCopy(B,Rr);CHKERRQ(ierr); /* r <- b (x is 0) */ } ierr = VecCopy(Rr,Rl);CHKERRQ(ierr); ierr = KSP_PCApply(ksp,Rr,Zr);CHKERRQ(ierr); /* z <- Br */ ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = KSP_PCApplyTranspose(ksp,Rl,Zl);CHKERRQ(ierr); ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = VecConjugate(Zl);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = VecNorm(Zr,NORM_2,&dp);CHKERRQ(ierr); /* dp <- z'*z */ } else { ierr = VecNorm(Rr,NORM_2,&dp);CHKERRQ(ierr); /* dp <- r'*r */ } KSPMonitor(ksp,0,dp); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); i = 0; do { ierr = VecDot(Zr,Rl,&beta);CHKERRQ(ierr); /* beta <- r'z */ if (!i) { if (beta == 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN_BICG; PetscFunctionReturn(0); } ierr = VecCopy(Zr,Pr);CHKERRQ(ierr); /* p <- z */ ierr = VecCopy(Zl,Pl);CHKERRQ(ierr); } else { b = beta/betaold; ierr = VecAYPX(Pr,b,Zr);CHKERRQ(ierr); /* p <- z + b* p */ b = PetscConj(b); ierr = VecAYPX(Pl,b,Zl);CHKERRQ(ierr); } betaold = beta; ierr = KSP_MatMult(ksp,Amat,Pr,Zr);CHKERRQ(ierr); /* z <- Kp */ ierr = VecConjugate(Pl);CHKERRQ(ierr); ierr = KSP_MatMultTranspose(ksp,Amat,Pl,Zl);CHKERRQ(ierr); ierr = VecConjugate(Pl);CHKERRQ(ierr); ierr = VecConjugate(Zl);CHKERRQ(ierr); ierr = VecDot(Zr,Pl,&dpi);CHKERRQ(ierr); /* dpi <- z'p */ a = beta/dpi; /* a = beta/p'z */ ierr = VecAXPY(X,a,Pr);CHKERRQ(ierr); /* x <- x + ap */ ma = -a; ierr = VecAXPY(Rr,ma,Zr);CHKERRQ(ierr) ma = PetscConj(ma); ierr = VecAXPY(Rl,ma,Zl);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = KSP_PCApply(ksp,Rr,Zr);CHKERRQ(ierr); /* z <- Br */ ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = KSP_PCApplyTranspose(ksp,Rl,Zl);CHKERRQ(ierr); ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = VecConjugate(Zl);CHKERRQ(ierr); ierr = VecNorm(Zr,NORM_2,&dp);CHKERRQ(ierr); /* dp <- z'*z */ } else { ierr = VecNorm(Rr,NORM_2,&dp);CHKERRQ(ierr); /* dp <- r'*r */ } ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its = i+1; ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); KSPMonitor(ksp,i+1,dp); ierr = (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = KSP_PCApply(ksp,Rr,Zr);CHKERRQ(ierr); /* z <- Br */ ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = KSP_PCApplyTranspose(ksp,Rl,Zl);CHKERRQ(ierr); ierr = VecConjugate(Rl);CHKERRQ(ierr); ierr = VecConjugate(Zl);CHKERRQ(ierr); } i++; } while (i<ksp->max_it); if (i >= ksp->max_it) { ksp->reason = KSP_DIVERGED_ITS; } PetscFunctionReturn(0); }
static PetscErrorCode SNESSolve_MS(SNES snes) { SNES_MS *ms = (SNES_MS*)snes->data; Vec X = snes->vec_sol,F = snes->vec_func; PetscReal fnorm; MatStructure mstruct; PetscInt i; PetscErrorCode ierr; PetscFunctionBegin; snes->reason = SNES_CONVERGED_ITERATING; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (snes->jacobian) { /* This method does not require a Jacobian, but it is usually preconditioned by PBJacobi */ ierr = SNESComputeJacobian(snes,snes->vec_sol,&snes->jacobian,&snes->jacobian_pre,&mstruct);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,mstruct);CHKERRQ(ierr); } if (ms->norms) { if (!snes->norm_init_set) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,0); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes,snes->iter);CHKERRQ(ierr); } for (i = 0; i < snes->max_its; i++) { ierr = SNESMSStep_3Sstar(snes,X,F);CHKERRQ(ierr); if (i+1 < snes->max_its || ms->norms) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } if (ms->norms) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,0); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } } if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_TFQMR(KSP ksp) { PetscErrorCode ierr; PetscInt i,m; PetscScalar rho,rhoold,a,s,b,eta,etaold,psiold,cf; PetscReal dp,dpold,w,dpest,tau,psi,cm; Vec X,B,V,P,R,RP,T,T1,Q,U,D,AUQ; PetscFunctionBegin; X = ksp->vec_sol; B = ksp->vec_rhs; R = ksp->work[0]; RP = ksp->work[1]; V = ksp->work[2]; T = ksp->work[3]; Q = ksp->work[4]; P = ksp->work[5]; U = ksp->work[6]; D = ksp->work[7]; T1 = ksp->work[8]; AUQ = V; /* Compute initial preconditioned residual */ ierr = KSPInitialResidual(ksp,X,V,T,R,B);CHKERRQ(ierr); /* Test for nothing to do */ ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->rnorm = dp; ksp->its = 0; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); /* Make the initial Rp == R */ ierr = VecCopy(R,RP);CHKERRQ(ierr); /* Set the initial conditions */ etaold = 0.0; psiold = 0.0; tau = dp; dpold = dp; ierr = VecDot(R,RP,&rhoold);CHKERRQ(ierr); /* rhoold = (r,rp) */ ierr = VecCopy(R,U);CHKERRQ(ierr); ierr = VecCopy(R,P);CHKERRQ(ierr); ierr = KSP_PCApplyBAorAB(ksp,P,V,T);CHKERRQ(ierr); ierr = VecSet(D,0.0);CHKERRQ(ierr); i=0; do { ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); ierr = VecDot(V,RP,&s);CHKERRQ(ierr); /* s <- (v,rp) */ a = rhoold / s; /* a <- rho / s */ ierr = VecWAXPY(Q,-a,V,U);CHKERRQ(ierr); /* q <- u - a v */ ierr = VecWAXPY(T,1.0,U,Q);CHKERRQ(ierr); /* t <- u + q */ ierr = KSP_PCApplyBAorAB(ksp,T,AUQ,T1);CHKERRQ(ierr); ierr = VecAXPY(R,-a,AUQ);CHKERRQ(ierr); /* r <- r - a K (u + q) */ ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); for (m=0; m<2; m++) { if (!m) { w = PetscSqrtReal(dp*dpold); } else { w = dp; } psi = w / tau; cm = 1.0 / PetscSqrtReal(1.0 + psi * psi); tau = tau * psi * cm; eta = cm * cm * a; cf = psiold * psiold * etaold / a; if (!m) { ierr = VecAYPX(D,cf,U);CHKERRQ(ierr); } else { ierr = VecAYPX(D,cf,Q);CHKERRQ(ierr); } ierr = VecAXPY(X,eta,D);CHKERRQ(ierr); dpest = PetscSqrtReal(m + 1.0) * tau; ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->rnorm = dpest; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dpest); ierr = KSPMonitor(ksp,i+1,dpest);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i+1,dpest,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; etaold = eta; psiold = psi; } if (ksp->reason) break; ierr = VecDot(R,RP,&rho);CHKERRQ(ierr); /* rho <- (r,rp) */ b = rho / rhoold; /* b <- rho / rhoold */ ierr = VecWAXPY(U,b,Q,R);CHKERRQ(ierr); /* u <- r + b q */ ierr = VecAXPY(Q,b,P);CHKERRQ(ierr); ierr = VecWAXPY(P,b,Q,U);CHKERRQ(ierr); /* p <- u + b(q + b p) */ ierr = KSP_PCApplyBAorAB(ksp,P,V,Q);CHKERRQ(ierr); /* v <- K p */ rhoold = rho; dpold = dp; i++; } while (i<ksp->max_it); if (i >= ksp->max_it) { ksp->reason = KSP_DIVERGED_ITS; } ierr = KSPUnwindPreconditioner(ksp,X,T);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_Chebychev(KSP ksp) { PetscErrorCode ierr; PetscInt k,kp1,km1,maxit,ktmp,i; PetscScalar alpha,omegaprod,mu,omega,Gamma,c[3],scale; PetscReal rnorm = 0.0; Vec x,b,p[3],r; KSP_Chebychev *chebychevP = (KSP_Chebychev*)ksp->data; Mat Amat,Pmat; MatStructure pflag; PetscTruth diagonalscale; PetscFunctionBegin; if (ksp->normtype == KSP_NORM_NATURAL) SETERRQ(PETSC_ERR_SUP,"Cannot use natural residual norm with KSPCHEBYCHEV"); ierr = PCDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); ksp->its = 0; ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); maxit = ksp->max_it; /* These three point to the three active solutions, we rotate these three at each solution update */ km1 = 0; k = 1; kp1 = 2; x = ksp->vec_sol; b = ksp->vec_rhs; p[km1] = x; p[k] = ksp->work[0]; p[kp1] = ksp->work[1]; r = ksp->work[2]; /* use scale*B as our preconditioner */ scale = 2.0/(chebychevP->emax + chebychevP->emin); /* -alpha <= scale*lambda(B^{-1}A) <= alpha */ alpha = 1.0 - scale*(chebychevP->emin); ; Gamma = 1.0; mu = 1.0/alpha; omegaprod = 2.0/alpha; c[km1] = 1.0; c[k] = mu; if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,x,r);CHKERRQ(ierr); /* r = b - Ax */ ierr = VecAYPX(r,-1.0,b);CHKERRQ(ierr); } else { ierr = VecCopy(b,r);CHKERRQ(ierr); } ierr = KSP_PCApply(ksp,r,p[k]);CHKERRQ(ierr); /* p[k] = scale B^{-1}r + x */ ierr = VecAYPX(p[k],scale,x);CHKERRQ(ierr); for (i=0; i<maxit; i++) { ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); c[kp1] = 2.0*mu*c[k] - c[km1]; omega = omegaprod*c[k]/c[kp1]; ierr = KSP_MatMult(ksp,Amat,p[k],r);CHKERRQ(ierr); /* r = b - Ap[k] */ ierr = VecAYPX(r,-1.0,b);CHKERRQ(ierr); ierr = KSP_PCApply(ksp,r,p[kp1]);CHKERRQ(ierr); /* p[kp1] = B^{-1}z */ /* calculate residual norm if requested */ if (ksp->normtype != KSP_NORM_NO) { if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) {ierr = VecNorm(r,NORM_2,&rnorm);CHKERRQ(ierr);} else {ierr = VecNorm(p[kp1],NORM_2,&rnorm);CHKERRQ(ierr);} ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->rnorm = rnorm; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); ksp->vec_sol = p[k]; KSPLogResidualHistory(ksp,rnorm); KSPMonitor(ksp,i,rnorm); ierr = (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; } /* y^{k+1} = omega(y^{k} - y^{k-1} + Gamma*r^{k}) + y^{k-1} */ ierr = VecScale(p[kp1],omega*Gamma*scale);CHKERRQ(ierr); ierr = VecAXPY(p[kp1],1.0-omega,p[km1]);CHKERRQ(ierr); ierr = VecAXPY(p[kp1],omega,p[k]);CHKERRQ(ierr); ktmp = km1; km1 = k; k = kp1; kp1 = ktmp; } if (!ksp->reason) { if (ksp->normtype != KSP_NORM_NO) { ierr = KSP_MatMult(ksp,Amat,p[k],r);CHKERRQ(ierr); /* r = b - Ap[k] */ ierr = VecAYPX(r,-1.0,b);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = VecNorm(r,NORM_2,&rnorm);CHKERRQ(ierr); } else { ierr = KSP_PCApply(ksp,r,p[kp1]);CHKERRQ(ierr); /* p[kp1] = B^{-1}z */ ierr = VecNorm(p[kp1],NORM_2,&rnorm);CHKERRQ(ierr); } ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->rnorm = rnorm; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); ksp->vec_sol = p[k]; KSPLogResidualHistory(ksp,rnorm); KSPMonitor(ksp,i,rnorm); } if (ksp->its >= ksp->max_it) { if (ksp->normtype != KSP_NORM_NO) { ierr = (*ksp->converged)(ksp,i,rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS; } else { ksp->reason = KSP_CONVERGED_ITS; } } } /* make sure solution is in vector x */ ksp->vec_sol = x; if (k) { ierr = VecCopy(p[k],x);CHKERRQ(ierr); } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_Multiblock(SNES snes) { SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; Vec X, Y, F; PetscReal fnorm; PetscInt maxits, i; PetscErrorCode ierr; PetscFunctionBegin; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* X^n */ Y = snes->vec_sol_update; /* \tilde X */ F = snes->vec_func; /* residual vector */ ierr = VecSetBlockSize(X, mb->bs);CHKERRQ(ierr); ierr = VecSetBlockSize(Y, mb->bs);CHKERRQ(ierr); ierr = VecSetBlockSize(F, mb->bs);CHKERRQ(ierr); ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); if (!snes->vec_func_init_set){ ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); for (i = 0; i < maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* Compute X^{new} from subsolves */ if (mb->type == PC_COMPOSITE_ADDITIVE) { BlockDesc blocks = mb->blocks; if (mb->defaultblocks) { /*TODO: Make an array of Vecs for this */ /*ierr = VecStrideGatherAll(X, mb->x, INSERT_VALUES);CHKERRQ(ierr);*/ while (blocks) { ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr); blocks = blocks->next; } /*ierr = VecStrideScatterAll(mb->x, X, INSERT_VALUES);CHKERRQ(ierr);*/ } else { while (blocks) { ierr = VecScatterBegin(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr); ierr = VecScatterBegin(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); blocks = blocks->next; } } } else { SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Unsupported or unknown composition", (int) mb->type); } CHKMEMQ; /* Compute F(X^{new}) */ ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated norm"); if (snes->nfuncs >= snes->max_funcs) { snes->reason = SNES_DIVERGED_FUNCTION_COUNT; break; } if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,0); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } if (i == maxits) { ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_FAS(SNES snes) { PetscErrorCode ierr; PetscInt i, maxits; Vec X, F; PetscReal fnorm; SNES_FAS *fas = (SNES_FAS *)snes->data,*ffas; DM dm; PetscBool isFine; PetscFunctionBegin; maxits = snes->max_its; /* maximum number of iterations */ snes->reason = SNES_CONVERGED_ITERATING; X = snes->vec_sol; F = snes->vec_func; ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr); /*norm setup */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); if (isFine) { /* propagate scale-dependent data up the hierarchy */ ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); for (ffas=fas; ffas->next; ffas=(SNES_FAS*)ffas->next->data) { DM dmcoarse; ierr = SNESGetDM(ffas->next,&dmcoarse);CHKERRQ(ierr); ierr = DMRestrict(dm,ffas->restrct,ffas->rscale,ffas->inject,dmcoarse);CHKERRQ(ierr); dm = dmcoarse; } } for (i = 0; i < maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } if (fas->fastype == SNES_FAS_MULTIPLICATIVE) { ierr = SNESFASCycle_Multiplicative(snes, X);CHKERRQ(ierr); } else { ierr = SNESFASCycle_Additive(snes, X);CHKERRQ(ierr); } /* check for FAS cycle divergence */ if (snes->reason != SNES_CONVERGED_ITERATING) { PetscFunctionReturn(0); } /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,0); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ if (isFine) { ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,snes->norm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } } if (i == maxits) { ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_CR(KSP ksp) { PetscErrorCode ierr; PetscInt i = 0; MatStructure pflag; PetscReal dp; PetscScalar ai, bi; PetscScalar apq,btop, bbot; Vec X,B,R,RT,P,AP,ART,Q; Mat Amat, Pmat; PetscFunctionBegin; X = ksp->vec_sol; B = ksp->vec_rhs; R = ksp->work[0]; RT = ksp->work[1]; P = ksp->work[2]; AP = ksp->work[3]; ART = ksp->work[4]; Q = ksp->work[5]; /* R is the true residual norm, RT is the preconditioned residual norm */ ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,X,R);CHKERRQ(ierr); /* R <- A*X */ ierr = VecAYPX(R,-1.0,B);CHKERRQ(ierr); /* R <- B-R == B-A*X */ } else { ierr = VecCopy(B,R);CHKERRQ(ierr); /* R <- B (X is 0) */ } ierr = KSP_PCApply(ksp,R,P);CHKERRQ(ierr); /* P <- B*R */ ierr = KSP_MatMult(ksp,Amat,P,AP);CHKERRQ(ierr); /* AP <- A*P */ ierr = VecCopy(P,RT);CHKERRQ(ierr); /* RT <- P */ ierr = VecCopy(AP,ART);CHKERRQ(ierr); /* ART <- AP */ ierr = VecDotBegin(RT,ART,&btop);CHKERRQ(ierr); /* (RT,ART) */ if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = VecNormBegin(RT,NORM_2,&dp);CHKERRQ(ierr); /* dp <- RT'*RT */ ierr = VecDotEnd (RT,ART,&btop) ;CHKERRQ(ierr); /* (RT,ART) */ ierr = VecNormEnd (RT,NORM_2,&dp);CHKERRQ(ierr); /* dp <- RT'*RT */ } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = VecNormBegin(R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- R'*R */ ierr = VecDotEnd (RT,ART,&btop);CHKERRQ(ierr); /* (RT,ART) */ ierr = VecNormEnd (R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- RT'*RT */ } else if (ksp->normtype == KSP_NORM_NATURAL) { ierr = VecDotEnd (RT,ART,&btop) ;CHKERRQ(ierr); /* (RT,ART) */ dp = sqrt(PetscAbsScalar(btop)); /* dp = sqrt(R,AR) */ } if (PetscAbsScalar(btop) < 0.0) { ksp->reason = KSP_DIVERGED_INDEFINITE_MAT; ierr = PetscInfo(ksp,"diverging due to indefinite or negative definite matrix\n");CHKERRQ(ierr); PetscFunctionReturn(0); } ksp->its = 0; KSPMonitor(ksp,0,dp); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); i = 0; do { ierr = KSP_PCApply(ksp,AP,Q);CHKERRQ(ierr);/* Q <- B* AP */ ierr = VecDot(AP,Q,&apq);CHKERRQ(ierr); if (PetscAbsScalar(apq) <= 0.0) { ksp->reason = KSP_DIVERGED_INDEFINITE_PC; ierr = PetscInfo(ksp,"KSPSolve_CR:diverging due to indefinite or negative definite PC\n");CHKERRQ(ierr); break; } ai = btop/apq; /* ai = (RT,ART)/(AP,Q) */ ierr = VecAXPY(X,ai,P);CHKERRQ(ierr); /* X <- X + ai*P */ ierr = VecAXPY(RT,-ai,Q);CHKERRQ(ierr); /* RT <- RT - ai*Q */ ierr = KSP_MatMult(ksp,Amat,RT,ART);CHKERRQ(ierr);/* ART <- A*RT */ bbot = btop; ierr = VecDotBegin(RT,ART,&btop);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = VecNormBegin(RT,NORM_2,&dp);CHKERRQ(ierr); /* dp <- || RT || */ ierr = VecDotEnd (RT,ART,&btop) ;CHKERRQ(ierr); ierr = VecNormEnd (RT,NORM_2,&dp);CHKERRQ(ierr); /* dp <- || RT || */ } else if (ksp->normtype == KSP_NORM_NATURAL) { ierr = VecDotEnd(RT,ART,&btop);CHKERRQ(ierr); dp = sqrt(PetscAbsScalar(btop)); /* dp = sqrt(R,AR) */ } else if (ksp->normtype == KSP_NORM_NO) { ierr = VecDotEnd(RT,ART,&btop);CHKERRQ(ierr); dp = 0.0; } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = VecAXPY(R,ai,AP);CHKERRQ(ierr); /* R <- R - ai*AP */ ierr = VecNormBegin(R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- R'*R */ ierr = VecDotEnd (RT,ART,&btop);CHKERRQ(ierr); ierr = VecNormEnd (R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- R'*R */ } else { SETERRQ1(PETSC_ERR_SUP,"KSPNormType of %d not supported",(int)ksp->normtype); } if (PetscAbsScalar(btop) < 0.0) { ksp->reason = KSP_DIVERGED_INDEFINITE_MAT; ierr = PetscInfo(ksp,"diverging due to indefinite or negative definite PC\n");CHKERRQ(ierr); break; } ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); KSPMonitor(ksp,i+1,dp); ierr = (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; bi = btop/bbot; ierr = VecAYPX(P,bi,RT);CHKERRQ(ierr); /* P <- RT + Bi P */ ierr = VecAYPX(AP,bi,ART);CHKERRQ(ierr); /* AP <- ART + Bi AP */ i++; } while (i<ksp->max_it); if (i >= ksp->max_it) { ksp->reason = KSP_DIVERGED_ITS; } PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_LSQR(KSP ksp) { PetscErrorCode ierr; PetscInt i,size1,size2; PetscScalar rho,rhobar,phi,phibar,theta,c,s,tmp,tau,alphac; PetscReal beta,alpha,rnorm; Vec X,B,V,V1,U,U1,TMP,W,W2,SE,Z = PETSC_NULL; Mat Amat,Pmat; MatStructure pflag; KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data; PetscTruth diagonalscale,nopreconditioner; PetscFunctionBegin; ierr = PCDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); ierr = PetscTypeCompare((PetscObject)ksp->pc,PCNONE,&nopreconditioner);CHKERRQ(ierr); /* nopreconditioner =PETSC_FALSE; */ /* Calculate norm of right hand side */ ierr = VecNorm(ksp->vec_rhs,NORM_2,&lsqr->rhs_norm);CHKERRQ(ierr); /* Calculate norm of matrix*/ ierr = MatNorm( Amat, NORM_FROBENIUS, &lsqr->anorm);CHKERRQ(ierr); /* vectors of length m, where system size is mxn */ B = ksp->vec_rhs; U = lsqr->vwork_m[0]; U1 = lsqr->vwork_m[1]; /* vectors of length n */ X = ksp->vec_sol; W = lsqr->vwork_n[0]; V = lsqr->vwork_n[1]; V1 = lsqr->vwork_n[2]; W2 = lsqr->vwork_n[3]; if (!nopreconditioner) { Z = lsqr->vwork_n[4]; } /* standard error vector */ SE = lsqr->se; if (SE){ ierr = VecGetSize(SE,&size1);CHKERRQ(ierr); ierr = VecGetSize(X ,&size2);CHKERRQ(ierr); if (size1 != size2) SETERRQ2(PETSC_ERR_ARG_SIZ,"Standard error vector (size %d) does not match solution vector (size %d)",size1,size2); ierr = VecSet(SE,0.0);CHKERRQ(ierr); } /* Compute initial residual, temporarily use work vector u */ if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,X,U);CHKERRQ(ierr); /* u <- b - Ax */ ierr = VecAYPX(U,-1.0,B);CHKERRQ(ierr); } else { ierr = VecCopy(B,U);CHKERRQ(ierr); /* u <- b (x is 0) */ } /* Test for nothing to do */ ierr = VecNorm(U,NORM_2,&rnorm);CHKERRQ(ierr); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = rnorm; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,rnorm); KSPMonitor(ksp,0,rnorm); ierr = (*ksp->converged)(ksp,0,rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); ierr = VecCopy(B,U);CHKERRQ(ierr); ierr = VecNorm(U,NORM_2,&beta);CHKERRQ(ierr); ierr = VecScale(U,1.0/beta);CHKERRQ(ierr); ierr = KSP_MatMultTranspose(ksp,Amat,U,V); CHKERRQ(ierr); if (nopreconditioner) { ierr = VecNorm(V,NORM_2,&alpha); CHKERRQ(ierr); } else { ierr = PCApply(ksp->pc,V,Z);CHKERRQ(ierr); ierr = VecDot(V,Z,&alphac);CHKERRQ(ierr); if (PetscRealPart(alphac) <= 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; PetscFunctionReturn(0); } alpha = sqrt(PetscRealPart(alphac)); ierr = VecScale(Z,1.0/alpha); CHKERRQ(ierr); } ierr = VecScale(V,1.0/alpha);CHKERRQ(ierr); if (nopreconditioner){ ierr = VecCopy(V,W);CHKERRQ(ierr); } else { ierr = VecCopy(Z,W);CHKERRQ(ierr); } ierr = VecSet(X,0.0);CHKERRQ(ierr); lsqr->arnorm = alpha * beta; phibar = beta; rhobar = alpha; tau = -beta; i = 0; do { if (nopreconditioner) { ierr = KSP_MatMult(ksp,Amat,V,U1);CHKERRQ(ierr); } else { ierr = KSP_MatMult(ksp,Amat,Z,U1);CHKERRQ(ierr); } ierr = VecAXPY(U1,-alpha,U);CHKERRQ(ierr); ierr = VecNorm(U1,NORM_2,&beta);CHKERRQ(ierr); if (beta == 0.0){ ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } ierr = VecScale(U1,1.0/beta);CHKERRQ(ierr); ierr = KSP_MatMultTranspose(ksp,Amat,U1,V1);CHKERRQ(ierr); ierr = VecAXPY(V1,-beta,V);CHKERRQ(ierr); if (nopreconditioner) { ierr = VecNorm(V1,NORM_2,&alpha); CHKERRQ(ierr); } else { ierr = PCApply(ksp->pc,V1,Z);CHKERRQ(ierr); ierr = VecDot(V1,Z,&alphac);CHKERRQ(ierr); if (PetscRealPart(alphac) <= 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } alpha = sqrt(PetscRealPart(alphac)); ierr = VecScale(Z,1.0/alpha);CHKERRQ(ierr); } ierr = VecScale(V1,1.0/alpha);CHKERRQ(ierr); rho = PetscSqrtScalar(rhobar*rhobar + beta*beta); c = rhobar / rho; s = beta / rho; theta = s * alpha; rhobar = - c * alpha; phi = c * phibar; phibar = s * phibar; tau = s * phi; ierr = VecAXPY(X,phi/rho,W);CHKERRQ(ierr); /* x <- x + (phi/rho) w */ if (SE) { ierr = VecCopy(W,W2);CHKERRQ(ierr); ierr = VecSquare(W2);CHKERRQ(ierr); ierr = VecScale(W2,1.0/(rho*rho));CHKERRQ(ierr); ierr = VecAXPY(SE, 1.0, W2);CHKERRQ(ierr); /* SE <- SE + (w^2/rho^2) */ } if (nopreconditioner) { ierr = VecAYPX(W,-theta/rho,V1);CHKERRQ(ierr); /* w <- v - (theta/rho) w */ } else { ierr = VecAYPX(W,-theta/rho,Z);CHKERRQ(ierr); /* w <- z - (theta/rho) w */ } lsqr->arnorm = alpha*PetscAbsScalar(tau); rnorm = PetscRealPart(phibar); ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = rnorm; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,rnorm); KSPMonitor(ksp,i+1,rnorm); ierr = (*ksp->converged)(ksp,i+1,rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; SWAP(U1,U,TMP); SWAP(V1,V,TMP); i++; } while (i<ksp->max_it); if (i >= ksp->max_it && !ksp->reason) { ksp->reason = KSP_DIVERGED_ITS; } /* Finish off the standard error estimates */ if (SE) { tmp = 1.0; ierr = MatGetSize(Amat,&size1,&size2);CHKERRQ(ierr); if ( size1 > size2 ) tmp = size1 - size2; tmp = rnorm / PetscSqrtScalar(tmp); ierr = VecSqrt(SE);CHKERRQ(ierr); ierr = VecScale(SE,tmp);CHKERRQ(ierr); } PetscFunctionReturn(0); }
static PetscErrorCode SNESSolve_QN(SNES snes) { PetscErrorCode ierr; SNES_QN *qn = (SNES_QN*) snes->data; Vec X,Xold; Vec F,B; Vec Y,FPC,D,Dold; SNESConvergedReason reason; PetscInt i, i_r; PetscReal fnorm,xnorm,ynorm,gnorm; PetscBool lssucceed,powell,periodic; PetscScalar DolddotD,DolddotDold,DdotD,YdotD; MatStructure flg = DIFFERENT_NONZERO_PATTERN; /* basically just a regular newton's method except for the application of the jacobian */ PetscFunctionBegin; F = snes->vec_func; /* residual vector */ Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ B = snes->vec_rhs; X = snes->vec_sol; /* solution vector */ Xold = snes->work[0]; /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */ D = snes->work[1]; Dold = snes->work[2]; snes->reason = SNES_CONVERGED_ITERATING; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); if (!snes->vec_func_init_set){ ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); /* composed solve */ if (snes->pc && snes->pcside == PC_RIGHT) { ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); ierr = VecCopy(FPC, F);CHKERRQ(ierr); ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); ierr = VecCopy(F, Y);CHKERRQ(ierr); } else { ierr = VecCopy(F, Y);CHKERRQ(ierr); } ierr = VecCopy(Y, D);CHKERRQ(ierr); /* scale the initial update */ if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); } for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { switch(qn->type) { case SNES_QN_BADBROYDEN: ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); break; case SNES_QN_BROYDEN: ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); break; case SNES_QN_LBFGS: SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr); break; } /* line search for lambda */ ynorm = 1; gnorm = fnorm; ierr = VecCopy(D, Dold);CHKERRQ(ierr); ierr = VecCopy(X, Xold);CHKERRQ(ierr); ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); if (!lssucceed) { if (++snes->numFailures >= snes->maxFailures) { snes->reason = SNES_DIVERGED_LINE_SEARCH; break; } } ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr); } /* convergence monitoring */ ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); ierr = SNESSetFunctionNorm(snes, fnorm);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,snes->iter); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); if (snes->pc && snes->pcside == PC_RIGHT) { ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); ierr = SNESSolve(snes->pc, B, X);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); ierr = VecCopy(FPC, F);CHKERRQ(ierr); ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); ierr = VecCopy(F, D);CHKERRQ(ierr); } else { ierr = VecCopy(F, D);CHKERRQ(ierr); } powell = PETSC_FALSE; if (qn->restart_type == SNES_QN_RESTART_POWELL) { /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */ ierr = VecDotBegin(Dold, Dold, &DolddotDold);CHKERRQ(ierr); ierr = VecDotBegin(Dold, D, &DolddotD);CHKERRQ(ierr); ierr = VecDotBegin(D, D, &DdotD);CHKERRQ(ierr); ierr = VecDotBegin(Y, D, &YdotD);CHKERRQ(ierr); ierr = VecDotEnd(Dold, Dold, &DolddotDold);CHKERRQ(ierr); ierr = VecDotEnd(Dold, D, &DolddotD);CHKERRQ(ierr); ierr = VecDotEnd(D, D, &DdotD);CHKERRQ(ierr); ierr = VecDotEnd(Y, D, &YdotD);CHKERRQ(ierr); if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE; } periodic = PETSC_FALSE; if (qn->restart_type == SNES_QN_RESTART_PERIODIC) { if (i_r>qn->m-1) periodic = PETSC_TRUE; } /* restart if either powell or periodic restart is satisfied. */ if (powell || periodic) { if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "restart! |%14.12e| > %4.2f*|%14.12e| or i_r = %d\n", PetscRealPart(DolddotD), qn->powell_gamma, PetscRealPart(DolddotDold), i_r);CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } i_r = -1; /* general purpose update */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); } } /* general purpose update */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } } if (i == snes->max_its) { ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_NEWTONLS(SNES snes) { PetscErrorCode ierr; PetscInt maxits,i,lits; PetscBool lssucceed; MatStructure flg = DIFFERENT_NONZERO_PATTERN; PetscReal fnorm,gnorm,xnorm,ynorm; Vec Y,X,F,G,W,FPC; KSPConvergedReason kspreason; PetscBool domainerror; SNESLineSearch linesearch; SNESConvergedReason reason; PetscFunctionBegin; snes->numFailures = 0; snes->numLinearSolveFailures = 0; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* solution vector */ F = snes->vec_func; /* residual vector */ Y = snes->vec_sol_update; /* newton step */ G = snes->work[0]; W = snes->work[1]; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNormBegin(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ ierr = VecNormEnd(F,NORM_2,&fnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); for (i=0; i<maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* apply the nonlinear preconditioner if it's right preconditioned */ if (snes->pc && snes->pcside == PC_RIGHT) { ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); ierr = SNESSolve(snes->pc, snes->vec_rhs, X);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); ierr = VecCopy(FPC, F);CHKERRQ(ierr); ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); } /* Solve J Y = F, where J is Jacobian matrix */ ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr); ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); if (kspreason < 0) { if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); snes->reason = SNES_DIVERGED_LINEAR_SOLVE; break; } } ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); if (PetscLogPrintInfo){ ierr = SNESNEWTONLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); } /* Compute a (scaled) negative update in the line search routine: X <- X - lambda*Y and evaluate F = function(X) (depends on the line search). */ gnorm = fnorm; ierr = SNESLineSearchApply(linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); ierr = SNESLineSearchGetSuccess(linesearch, &lssucceed);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)gnorm,(double)fnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } if (!lssucceed) { if (snes->stol*xnorm > ynorm) { snes->reason = SNES_CONVERGED_SNORM_RELATIVE; PetscFunctionReturn(0); } if (++snes->numFailures >= snes->maxFailures) { PetscBool ismin; snes->reason = SNES_DIVERGED_LINE_SEARCH; ierr = SNESNEWTONLSCheckLocalMin_Private(snes,snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,lits); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } if (i == maxits) { ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_LS(SNES snes) { SNES_LS *neP = (SNES_LS*)snes->data; PetscErrorCode ierr; PetscInt maxits,i,lits; PetscTruth lssucceed; MatStructure flg = DIFFERENT_NONZERO_PATTERN; PetscReal fnorm,gnorm,xnorm=0,ynorm; Vec Y,X,F,G,W; KSPConvergedReason kspreason; PetscFunctionBegin; snes->numFailures = 0; snes->numLinearSolveFailures = 0; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* solution vector */ F = snes->vec_func; /* residual vector */ Y = snes->work[0]; /* work vectors */ G = snes->work[1]; W = snes->work[2]; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } ierr = VecNormBegin(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm <- ||x|| */ ierr = VecNormEnd(F,NORM_2,&fnorm);CHKERRQ(ierr); ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); if PetscIsInfOrNanReal(fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); SNESMonitor(snes,0,fnorm); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); for (i=0; i<maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* Solve J Y = F, where J is Jacobian matrix */ ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr); ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); if (kspreason < 0) { if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); snes->reason = SNES_DIVERGED_LINEAR_SOLVE; break; } } ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); if (neP->precheckstep) { PetscTruth changed_y = PETSC_FALSE; ierr = (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);CHKERRQ(ierr); } if (PetscLogPrintInfo){ ierr = SNESLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); } /* Compute a (scaled) negative update in the line search routine: Y <- X - lambda*Y and evaluate G = function(Y) (depends on the line search). */ ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr); ynorm = 1; gnorm = fnorm; ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,xnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr); if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } if (!lssucceed) { if (++snes->numFailures >= snes->maxFailures) { PetscTruth ismin; snes->reason = SNES_DIVERGED_LS_FAILURE; ierr = SNESLSCheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Update function and solution vectors */ fnorm = gnorm; ierr = VecCopy(G,F);CHKERRQ(ierr); ierr = VecCopy(W,X);CHKERRQ(ierr); /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,lits); SNESMonitor(snes,snes->iter,snes->norm); /* Test for convergence, xnorm = || X || */ if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } if (i == maxits) { ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes) { SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data; PetscErrorCode ierr; PetscInt maxits,i,lits; PetscBool lssucceed; MatStructure flg = DIFFERENT_NONZERO_PATTERN; PetscReal fnorm,gnorm,xnorm=0,ynorm; Vec Y,X,F; KSPConvergedReason kspreason; PetscFunctionBegin; snes->numFailures = 0; snes->numLinearSolveFailures = 0; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* solution vector */ F = snes->vec_func; /* residual vector */ Y = snes->work[0]; /* work vectors */ ierr = SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm);CHKERRQ(ierr); ierr = SNESLineSearchSetVecs(snes->linesearch, X, PETSC_NULL, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); ierr = SNESLineSearchSetUp(snes->linesearch);CHKERRQ(ierr); ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr); ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr); ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm <- ||x|| */ ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(fnorm)) SETERRQ(((PetscObject)X)->comm,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); for (i=0; i<maxits; i++) { IS IS_act,IS_inact; /* _act -> active set _inact -> inactive set */ IS IS_redact; /* redundant active set */ VecScatter scat_act,scat_inact; PetscInt nis_act,nis_inact; Vec Y_act,Y_inact,F_inact; Mat jac_inact_inact,prejac_inact_inact; PetscBool isequal; /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); /* Create active and inactive index sets */ /*original ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&IS_inact);CHKERRQ(ierr); */ ierr = SNESVIGetActiveSetIS(snes,X,F,&IS_act);CHKERRQ(ierr); if (vi->checkredundancy) { (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);CHKERRQ(ierr); if (IS_redact){ ierr = ISSort(IS_redact);CHKERRQ(ierr); ierr = ISComplement(IS_redact,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr); ierr = ISDestroy(&IS_redact);CHKERRQ(ierr); } else { ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr); } } else { ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&IS_inact);CHKERRQ(ierr); } /* Create inactive set submatrix */ ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr); if (0) { /* Dead code (temporary developer hack) */ IS keptrows; ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr); if (keptrows) { PetscInt cnt,*nrows,k; const PetscInt *krows,*inact; PetscInt rstart=jac_inact_inact->rmap->rstart; ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr); ierr = ISDestroy(&IS_act);CHKERRQ(ierr); ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr); ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr); ierr = ISGetIndices(IS_inact,&inact);CHKERRQ(ierr); ierr = PetscMalloc(cnt*sizeof(PetscInt),&nrows);CHKERRQ(ierr); for (k=0; k<cnt; k++) { nrows[k] = inact[krows[k]-rstart]; } ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr); ierr = ISRestoreIndices(IS_inact,&inact);CHKERRQ(ierr); ierr = ISDestroy(&keptrows);CHKERRQ(ierr); ierr = ISDestroy(&IS_inact);CHKERRQ(ierr); ierr = ISCreateGeneral(((PetscObject)snes)->comm,cnt,nrows,PETSC_OWN_POINTER,&IS_inact);CHKERRQ(ierr); ierr = ISComplement(IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr); ierr = MatGetSubMatrix(snes->jacobian,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr); } } ierr = DMSetVI(snes->dm,IS_inact);CHKERRQ(ierr); /* remove later */ /* ierr = VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm));CHKERRQ(ierr); ierr = VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm));CHKERRQ(ierr); ierr = VecView(X,PETSC_VIEWER_BINARY_(((PetscObject)X)->comm));CHKERRQ(ierr); ierr = VecView(F,PETSC_VIEWER_BINARY_(((PetscObject)F)->comm));CHKERRQ(ierr); ierr = ISView(IS_inact,PETSC_VIEWER_BINARY_(((PetscObject)IS_inact)->comm));CHKERRQ(ierr); */ /* Get sizes of active and inactive sets */ ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr); ierr = ISGetLocalSize(IS_inact,&nis_inact);CHKERRQ(ierr); /* Create active and inactive set vectors */ ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&F_inact);CHKERRQ(ierr); ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_act,&Y_act);CHKERRQ(ierr); ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&Y_inact);CHKERRQ(ierr); /* Create scatter contexts */ ierr = VecScatterCreate(Y,IS_act,Y_act,PETSC_NULL,&scat_act);CHKERRQ(ierr); ierr = VecScatterCreate(Y,IS_inact,Y_inact,PETSC_NULL,&scat_inact);CHKERRQ(ierr); /* Do a vec scatter to active and inactive set vectors */ ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); /* Active set direction = 0 */ ierr = VecSet(Y_act,0);CHKERRQ(ierr); if (snes->jacobian != snes->jacobian_pre) { ierr = MatGetSubMatrix(snes->jacobian_pre,IS_inact,IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr); } else prejac_inact_inact = jac_inact_inact; ierr = ISEqual(vi->IS_inact_prev,IS_inact,&isequal);CHKERRQ(ierr); if (!isequal) { ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr); flg = DIFFERENT_NONZERO_PATTERN; } /* ierr = ISView(IS_inact,0);CHKERRQ(ierr); */ /* ierr = ISView(IS_act,0);CHKERRQ(ierr);*/ /* ierr = MatView(snes->jacobian_pre,0); */ ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact,flg);CHKERRQ(ierr); ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr); { PC pc; PetscBool flg; ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr); if (flg) { KSP *subksps; ierr = PCFieldSplitGetSubKSP(pc,PETSC_NULL,&subksps);CHKERRQ(ierr); ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr); ierr = PetscFree(subksps);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr); if (flg) { PetscInt n,N = 101*101,j,cnts[3] = {0,0,0}; const PetscInt *ii; ierr = ISGetSize(IS_inact,&n);CHKERRQ(ierr); ierr = ISGetIndices(IS_inact,&ii);CHKERRQ(ierr); for (j=0; j<n; j++) { if (ii[j] < N) cnts[0]++; else if (ii[j] < 2*N) cnts[1]++; else if (ii[j] < 3*N) cnts[2]++; } ierr = ISRestoreIndices(IS_inact,&ii);CHKERRQ(ierr); ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr); } } } ierr = SNES_KSPSolve(snes,snes->ksp,F_inact,Y_inact);CHKERRQ(ierr); ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); if (kspreason < 0) { if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); snes->reason = SNES_DIVERGED_LINEAR_SOLVE; break; } } ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecDestroy(&F_inact);CHKERRQ(ierr); ierr = VecDestroy(&Y_act);CHKERRQ(ierr); ierr = VecDestroy(&Y_inact);CHKERRQ(ierr); ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr); ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr); ierr = ISDestroy(&IS_act);CHKERRQ(ierr); if (!isequal) { ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr); ierr = ISDuplicate(IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr); } ierr = ISDestroy(&IS_inact);CHKERRQ(ierr); ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr); if (snes->jacobian != snes->jacobian_pre) { ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr); } ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); /* if (snes->ops->precheck) { PetscBool changed_y = PETSC_FALSE; ierr = (*snes->ops->precheck)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr); } if (PetscLogPrintInfo){ ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); } */ /* Compute a (scaled) negative update in the line search routine: Y <- X - lambda*Y and evaluate G = function(Y) (depends on the line search). */ ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr); ynorm = 1; gnorm = fnorm; ierr = SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr); ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr); PetscFunctionReturn(0); } ierr = SNESLineSearchGetSuccess(snes->linesearch, &lssucceed);CHKERRQ(ierr); if (!lssucceed) { if (++snes->numFailures >= snes->maxFailures) { PetscBool ismin; snes->reason = SNES_DIVERGED_LINE_SEARCH; ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,F,X,gnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Update function and solution vectors */ fnorm = gnorm; /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,lits); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence, xnorm = || X || */ if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr); if (i == maxits) { ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_CGS(KSP ksp) { PetscErrorCode ierr; PetscInt i; PetscScalar rho,rhoold,a,s,b; Vec X,B,V,P,R,RP,T,Q,U,AUQ; PetscReal dp = 0.0; PetscBool diagonalscale; PetscFunctionBegin; /* not sure what residual norm it does use, should use for right preconditioning */ ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); X = ksp->vec_sol; B = ksp->vec_rhs; R = ksp->work[0]; RP = ksp->work[1]; V = ksp->work[2]; T = ksp->work[3]; Q = ksp->work[4]; P = ksp->work[5]; U = ksp->work[6]; AUQ = V; /* Compute initial preconditioned residual */ ierr = KSPInitialResidual(ksp,X,V,T,R,B);CHKERRQ(ierr); /* Test for nothing to do */ ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_NATURAL) { dp *= dp; } ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); /* Make the initial Rp == R */ ierr = VecCopy(R,RP);CHKERRQ(ierr); /* added for Fidap */ /* Penalize Startup - Isaac Hasbani Trick for CGS Since most initial conditions result in a mostly 0 residual, we change all the 0 values in the vector RP to the maximum. */ if (ksp->normtype == KSP_NORM_NATURAL) { PetscReal vr0max; PetscScalar *tmp_RP=0; PetscInt numnp=0, *max_pos=0; ierr = VecMax(RP, max_pos, &vr0max);CHKERRQ(ierr); ierr = VecGetArray(RP, &tmp_RP);CHKERRQ(ierr); ierr = VecGetLocalSize(RP, &numnp);CHKERRQ(ierr); for (i=0; i<numnp; i++) { if (tmp_RP[i] == 0.0) tmp_RP[i] = vr0max; } ierr = VecRestoreArray(RP, &tmp_RP);CHKERRQ(ierr); } /* end of addition for Fidap */ /* Set the initial conditions */ ierr = VecDot(R,RP,&rhoold);CHKERRQ(ierr); /* rhoold = (r,rp) */ ierr = VecCopy(R,U);CHKERRQ(ierr); ierr = VecCopy(R,P);CHKERRQ(ierr); ierr = KSP_PCApplyBAorAB(ksp,P,V,T);CHKERRQ(ierr); i = 0; do { ierr = VecDot(V,RP,&s);CHKERRQ(ierr); /* s <- (v,rp) */ a = rhoold / s; /* a <- rho / s */ ierr = VecWAXPY(Q,-a,V,U);CHKERRQ(ierr); /* q <- u - a v */ ierr = VecWAXPY(T,1.0,U,Q);CHKERRQ(ierr); /* t <- u + q */ ierr = VecAXPY(X,a,T);CHKERRQ(ierr); /* x <- x + a (u + q) */ ierr = KSP_PCApplyBAorAB(ksp,T,AUQ,U);CHKERRQ(ierr); ierr = VecAXPY(R,-a,AUQ);CHKERRQ(ierr); /* r <- r - a K (u + q) */ ierr = VecDot(R,RP,&rho);CHKERRQ(ierr); /* rho <- (r,rp) */ if (ksp->normtype == KSP_NORM_NATURAL) { dp = PetscAbsScalar(rho); } else { ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); } ierr = PetscObjectTakeAccess(ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = dp; ierr = PetscObjectGrantAccess(ksp);CHKERRQ(ierr); KSPLogResidualHistory(ksp,dp); ierr = KSPMonitor(ksp,i+1,dp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; b = rho / rhoold; /* b <- rho / rhoold */ ierr = VecWAXPY(U,b,Q,R);CHKERRQ(ierr); /* u <- r + b q */ ierr = VecAXPY(Q,b,P);CHKERRQ(ierr); ierr = VecWAXPY(P,b,Q,U);CHKERRQ(ierr); /* p <- u + b(q + b p) */ ierr = KSP_PCApplyBAorAB(ksp,P,V,Q);CHKERRQ(ierr); /* v <- K p */ rhoold = rho; i++; } while (i<ksp->max_it); if (i >= ksp->max_it) { ksp->reason = KSP_DIVERGED_ITS; } ierr = KSPUnwindPreconditioner(ksp,X,T);CHKERRQ(ierr); PetscFunctionReturn(0); }
EXTERN_C_END /* SNESSolve_NCG - Solves a nonlinear system with the Nonlinear Conjugate Gradient method. Input Parameters: . snes - the SNES context Output Parameter: . outits - number of iterations until termination Application Interface Routine: SNESSolve() */ #undef __FUNCT__ #define __FUNCT__ "SNESSolve_NCG" PetscErrorCode SNESSolve_NCG(SNES snes) { SNES_NCG *ncg = (SNES_NCG *)snes->data; Vec X, dX, lX, F, B, Fold; PetscReal fnorm, ynorm, xnorm, beta = 0.0; PetscScalar dXdotF, dXolddotFold, dXdotFold, lXdotF, lXdotFold; PetscInt maxits, i; PetscErrorCode ierr; SNESConvergedReason reason; PetscBool lsSuccess = PETSC_TRUE; SNESLineSearch linesearch; PetscFunctionBegin; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* X^n */ Fold = snes->work[0]; /* The previous iterate of X */ dX = snes->work[1]; /* the preconditioned direction */ lX = snes->vec_sol_update; /* the conjugate direction */ F = snes->vec_func; /* residual vector */ B = snes->vec_rhs; /* the right hand side */ ierr = SNESGetSNESLineSearch(snes, &linesearch); CHKERRQ(ierr); ierr = PetscObjectTakeAccess(snes); CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectGrantAccess(snes); CHKERRQ(ierr); /* compute the initial function and preconditioned update dX */ if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { /* convergence test */ ierr = VecNorm(F, NORM_2, &fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes); CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes); CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm); CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP); CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter); CHKERRQ(ierr); } /* first update -- just use the (preconditioned) residual direction for the initial conjugate direction */ if (snes->pc && snes->pcside == PC_RIGHT) { ierr = VecCopy(X, dX); CHKERRQ(ierr); ierr = SNESSetInitialFunction(snes->pc, F); CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm); CHKERRQ(ierr); ierr = SNESSolve(snes->pc, B, dX); CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason); CHKERRQ(ierr); if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = VecAYPX(dX,-1.0,X); CHKERRQ(ierr); } else { ierr = VecCopy(F, dX); CHKERRQ(ierr); } ierr = VecCopy(dX, lX); CHKERRQ(ierr); ierr = VecDot(F, dX, &dXdotF); CHKERRQ(ierr); /* } else { ierr = SNESNCGComputeYtJtF_Private(snes, X, F, dX, W, G, &dXdotF);CHKERRQ(ierr); } */ for (i = 1; i < maxits + 1; i++) { lsSuccess = PETSC_TRUE; /* some update types require the old update direction or conjugate direction */ if (ncg->type != SNES_NCG_FR) { ierr = VecCopy(F, Fold); CHKERRQ(ierr); } ierr = SNESLineSearchApply(linesearch, X, F, &fnorm, lX); CHKERRQ(ierr); ierr = SNESLineSearchGetSuccess(linesearch, &lsSuccess); CHKERRQ(ierr); if (!lsSuccess) { if (++snes->numFailures >= snes->maxFailures) { snes->reason = SNES_DIVERGED_LINE_SEARCH; PetscFunctionReturn(0); } } if (snes->nfuncs >= snes->max_funcs) { snes->reason = SNES_DIVERGED_FUNCTION_COUNT; PetscFunctionReturn(0); } if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm); CHKERRQ(ierr); /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes); CHKERRQ(ierr); snes->iter = i; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes); CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,0); ierr = SNESMonitor(snes,snes->iter,snes->norm); CHKERRQ(ierr); /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP); CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter); CHKERRQ(ierr); } if (snes->pc && snes->pcside == PC_RIGHT) { ierr = VecCopy(X,dX); CHKERRQ(ierr); ierr = SNESSetInitialFunction(snes->pc, F); CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm); CHKERRQ(ierr); ierr = SNESSolve(snes->pc, B, dX); CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason); CHKERRQ(ierr); if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = VecAYPX(dX,-1.0,X); CHKERRQ(ierr); } else { ierr = VecCopy(F, dX); CHKERRQ(ierr); } /* compute the conjugate direction lX = dX + beta*lX with beta = ((dX, dX) / (dX_old, dX_old) (Fletcher-Reeves update)*/ switch(ncg->type) { case SNES_NCG_FR: /* Fletcher-Reeves */ dXolddotFold = dXdotF; ierr = VecDot(dX, dX, &dXdotF); CHKERRQ(ierr); beta = PetscRealPart(dXdotF / dXolddotFold); break; case SNES_NCG_PRP: /* Polak-Ribiere-Poylak */ dXolddotFold = dXdotF; ierr = VecDotBegin(F, dX, &dXdotF); CHKERRQ(ierr); ierr = VecDotBegin(Fold, dX, &dXdotFold); CHKERRQ(ierr); ierr = VecDotEnd(F, dX, &dXdotF); CHKERRQ(ierr); ierr = VecDotEnd(Fold, dX, &dXdotFold); CHKERRQ(ierr); beta = PetscRealPart(((dXdotF - dXdotFold) / dXolddotFold)); if (beta < 0.0) beta = 0.0; /* restart */ break; case SNES_NCG_HS: /* Hestenes-Stiefel */ ierr = VecDotBegin(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotBegin(dX, Fold, &dXdotFold); CHKERRQ(ierr); ierr = VecDotBegin(lX, F, &lXdotF); CHKERRQ(ierr); ierr = VecDotBegin(lX, Fold, &lXdotFold); CHKERRQ(ierr); ierr = VecDotEnd(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotEnd(dX, Fold, &dXdotFold); CHKERRQ(ierr); ierr = VecDotEnd(lX, F, &lXdotF); CHKERRQ(ierr); ierr = VecDotEnd(lX, Fold, &lXdotFold); CHKERRQ(ierr); beta = PetscRealPart((dXdotF - dXdotFold) / (lXdotF - lXdotFold)); break; case SNES_NCG_DY: /* Dai-Yuan */ ierr = VecDotBegin(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotBegin(lX, F, &lXdotF); CHKERRQ(ierr); ierr = VecDotBegin(lX, Fold, &lXdotFold); CHKERRQ(ierr); ierr = VecDotEnd(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotEnd(lX, F, &lXdotF); CHKERRQ(ierr); ierr = VecDotEnd(lX, Fold, &lXdotFold); CHKERRQ(ierr); beta = PetscRealPart(dXdotF / (lXdotFold - lXdotF)); CHKERRQ(ierr); break; case SNES_NCG_CD: /* Conjugate Descent */ ierr = VecDotBegin(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotBegin(lX, Fold, &lXdotFold); CHKERRQ(ierr); ierr = VecDotEnd(dX, F, &dXdotF); CHKERRQ(ierr); ierr = VecDotEnd(lX, Fold, &lXdotFold); CHKERRQ(ierr); beta = PetscRealPart(dXdotF / lXdotFold); CHKERRQ(ierr); break; } if (ncg->monitor) { ierr = PetscViewerASCIIPrintf(ncg->monitor, "beta = %e\n", beta); CHKERRQ(ierr); } ierr = VecAYPX(lX, beta, dX); CHKERRQ(ierr); } ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits); CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_BCGSL(KSP ksp) { KSP_BCGSL *bcgsl = (KSP_BCGSL *) ksp->data; PetscScalar alpha, beta, omega, sigma; PetscScalar rho0, rho1; PetscReal kappa0, kappaA, kappa1; PetscReal ghat, epsilon, abstol; PetscReal zeta, zeta0, rnmax_computed, rnmax_true, nrm0; PetscTruth bUpdateX; PetscTruth bBombed = PETSC_FALSE; PetscInt maxit; PetscInt h, i, j, k, vi, ell; PetscBLASInt ldMZ,bierr; PetscErrorCode ierr; PetscFunctionBegin; if (ksp->normtype == KSP_NORM_NATURAL) SETERRQ(PETSC_ERR_SUP,"Cannot use natural norm with KSPBCGSL"); if (ksp->normtype == KSP_NORM_PRECONDITIONED && ksp->pc_side != PC_LEFT) SETERRQ(PETSC_ERR_SUP,"Use -ksp_norm_type unpreconditioned for right preconditioning and KSPBCGSL"); if (ksp->normtype == KSP_NORM_UNPRECONDITIONED && ksp->pc_side != PC_RIGHT) SETERRQ(PETSC_ERR_SUP,"Use -ksp_norm_type preconditioned for left preconditioning and KSPBCGSL"); /* set up temporary vectors */ vi = 0; ell = bcgsl->ell; bcgsl->vB = ksp->work[vi]; vi++; bcgsl->vRt = ksp->work[vi]; vi++; bcgsl->vTm = ksp->work[vi]; vi++; bcgsl->vvR = ksp->work+vi; vi += ell+1; bcgsl->vvU = ksp->work+vi; vi += ell+1; bcgsl->vXr = ksp->work[vi]; vi++; ldMZ = PetscBLASIntCast(ell+1); /* Prime the iterative solver */ ierr = KSPInitialResidual(ksp, VX, VTM, VB, VVR[0], ksp->vec_rhs); CHKERRQ(ierr); ierr = VecNorm(VVR[0], NORM_2, &zeta0); CHKERRQ(ierr); rnmax_computed = zeta0; rnmax_true = zeta0; ierr = (*ksp->converged)(ksp, 0, zeta0, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) { ierr = PetscObjectTakeAccess(ksp); CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = zeta0; ierr = PetscObjectGrantAccess(ksp); CHKERRQ(ierr); PetscFunctionReturn(0); } ierr = VecSet(VVU[0],0.0); CHKERRQ(ierr); alpha = 0.; rho0 = omega = 1; if (bcgsl->delta>0.0) { ierr = VecCopy(VX, VXR); CHKERRQ(ierr); ierr = VecSet(VX,0.0); CHKERRQ(ierr); ierr = VecCopy(VVR[0], VB); CHKERRQ(ierr); } else { ierr = VecCopy(ksp->vec_rhs, VB); CHKERRQ(ierr); } /* Life goes on */ ierr = VecCopy(VVR[0], VRT); CHKERRQ(ierr); zeta = zeta0; ierr = KSPGetTolerances(ksp, &epsilon, &abstol, PETSC_NULL, &maxit); CHKERRQ(ierr); for (k=0; k<maxit; k += bcgsl->ell) { ksp->its = k; ksp->rnorm = zeta; KSPLogResidualHistory(ksp, zeta); KSPMonitor(ksp, ksp->its, zeta); ierr = (*ksp->converged)(ksp, k, zeta, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) break; /* BiCG part */ rho0 = -omega*rho0; nrm0 = zeta; for (j=0; j<bcgsl->ell; j++) { /* rho1 <- r_j' * r_tilde */ ierr = VecDot(VVR[j], VRT, &rho1); CHKERRQ(ierr); if (rho1 == 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN_BICG; bBombed = PETSC_TRUE; break; } beta = alpha*(rho1/rho0); rho0 = rho1; for (i=0; i<=j; i++) { /* u_i <- r_i - beta*u_i */ ierr = VecAYPX(VVU[i], -beta, VVR[i]); CHKERRQ(ierr); } /* u_{j+1} <- inv(K)*A*u_j */ ierr = KSP_PCApplyBAorAB(ksp, VVU[j], VVU[j+1], VTM); CHKERRQ(ierr); ierr = VecDot(VVU[j+1], VRT, &sigma); CHKERRQ(ierr); if (sigma == 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN_BICG; bBombed = PETSC_TRUE; break; } alpha = rho1/sigma; /* x <- x + alpha*u_0 */ ierr = VecAXPY(VX, alpha, VVU[0]); CHKERRQ(ierr); for (i=0; i<=j; i++) { /* r_i <- r_i - alpha*u_{i+1} */ ierr = VecAXPY(VVR[i], -alpha, VVU[i+1]); CHKERRQ(ierr); } /* r_{j+1} <- inv(K)*A*r_j */ ierr = KSP_PCApplyBAorAB(ksp, VVR[j], VVR[j+1], VTM); CHKERRQ(ierr); ierr = VecNorm(VVR[0], NORM_2, &nrm0); CHKERRQ(ierr); if (bcgsl->delta>0.0) { if (rnmax_computed<nrm0) rnmax_computed = nrm0; if (rnmax_true<nrm0) rnmax_true = nrm0; } /* NEW: check for early exit */ ierr = (*ksp->converged)(ksp, k+j, nrm0, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) { ierr = PetscObjectTakeAccess(ksp); CHKERRQ(ierr); ksp->its = k+j; ksp->rnorm = nrm0; ierr = PetscObjectGrantAccess(ksp); CHKERRQ(ierr); break; } } if (bBombed==PETSC_TRUE) break; /* Polynomial part */ for(i = 0; i <= bcgsl->ell; ++i) { ierr = VecMDot(VVR[i], i+1, VVR, &MZa[i*ldMZ]); CHKERRQ(ierr); } /* Symmetrize MZa */ for(i = 0; i <= bcgsl->ell; ++i) { for(j = i+1; j <= bcgsl->ell; ++j) { MZa[i*ldMZ+j] = MZa[j*ldMZ+i] = PetscConj(MZa[j*ldMZ+i]); } } /* Copy MZa to MZb */ ierr = PetscMemcpy(MZb,MZa,ldMZ*ldMZ*sizeof(PetscScalar)); CHKERRQ(ierr); if (!bcgsl->bConvex || bcgsl->ell==1) { PetscBLASInt ione = 1,bell = PetscBLASIntCast(bcgsl->ell); AY0c[0] = -1; LAPACKpotrf_("Lower", &bell, &MZa[1+ldMZ], &ldMZ, &bierr); if (ierr!=0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; bBombed = PETSC_TRUE; break; } ierr = PetscMemcpy(&AY0c[1],&MZb[1],bcgsl->ell*sizeof(PetscScalar)); CHKERRQ(ierr); LAPACKpotrs_("Lower", &bell, &ione, &MZa[1+ldMZ], &ldMZ, &AY0c[1], &ldMZ, &bierr); } else { PetscBLASInt ione = 1; PetscScalar aone = 1.0, azero = 0.0; PetscBLASInt neqs = PetscBLASIntCast(bcgsl->ell-1); LAPACKpotrf_("Lower", &neqs, &MZa[1+ldMZ], &ldMZ, &bierr); if (ierr!=0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; bBombed = PETSC_TRUE; break; } ierr = PetscMemcpy(&AY0c[1],&MZb[1],(bcgsl->ell-1)*sizeof(PetscScalar)); CHKERRQ(ierr); LAPACKpotrs_("Lower", &neqs, &ione, &MZa[1+ldMZ], &ldMZ, &AY0c[1], &ldMZ, &bierr); AY0c[0] = -1; AY0c[bcgsl->ell] = 0.; ierr = PetscMemcpy(&AYlc[1],&MZb[1+ldMZ*(bcgsl->ell)],(bcgsl->ell-1)*sizeof(PetscScalar)); CHKERRQ(ierr); LAPACKpotrs_("Lower", &neqs, &ione, &MZa[1+ldMZ], &ldMZ, &AYlc[1], &ldMZ, &bierr); AYlc[0] = 0.; AYlc[bcgsl->ell] = -1; BLASgemv_("NoTr", &ldMZ, &ldMZ, &aone, MZb, &ldMZ, AY0c, &ione, &azero, AYtc, &ione); kappa0 = BLASdot_(&ldMZ, AY0c, &ione, AYtc, &ione); /* round-off can cause negative kappa's */ if (kappa0<0) kappa0 = -kappa0; kappa0 = sqrt(kappa0); kappaA = BLASdot_(&ldMZ, AYlc, &ione, AYtc, &ione); BLASgemv_("noTr", &ldMZ, &ldMZ, &aone, MZb, &ldMZ, AYlc, &ione, &azero, AYtc, &ione); kappa1 = BLASdot_(&ldMZ, AYlc, &ione, AYtc, &ione); if (kappa1<0) kappa1 = -kappa1; kappa1 = sqrt(kappa1); if (kappa0!=0.0 && kappa1!=0.0) { if (kappaA<0.7*kappa0*kappa1) { ghat = (kappaA<0.0) ? -0.7*kappa0/kappa1 : 0.7*kappa0/kappa1; } else { ghat = kappaA/(kappa1*kappa1); } for (i=0; i<=bcgsl->ell; i++) { AY0c[i] = AY0c[i] - ghat* AYlc[i]; } } } omega = AY0c[bcgsl->ell]; for (h=bcgsl->ell; h>0 && omega==0.0; h--) { omega = AY0c[h]; } if (omega==0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } ierr = VecMAXPY(VX, bcgsl->ell,AY0c+1, VVR); CHKERRQ(ierr); for (i=1; i<=bcgsl->ell; i++) { AY0c[i] *= -1.0; } ierr = VecMAXPY(VVU[0], bcgsl->ell,AY0c+1, VVU+1); CHKERRQ(ierr); ierr = VecMAXPY(VVR[0], bcgsl->ell,AY0c+1, VVR+1); CHKERRQ(ierr); for (i=1; i<=bcgsl->ell; i++) { AY0c[i] *= -1.0; } ierr = VecNorm(VVR[0], NORM_2, &zeta); CHKERRQ(ierr); /* Accurate Update */ if (bcgsl->delta>0.0) { if (rnmax_computed<zeta) rnmax_computed = zeta; if (rnmax_true<zeta) rnmax_true = zeta; bUpdateX = (PetscTruth) (zeta<bcgsl->delta*zeta0 && zeta0<=rnmax_computed); if ((zeta<bcgsl->delta*rnmax_true && zeta0<=rnmax_true) || bUpdateX) { /* r0 <- b-inv(K)*A*X */ ierr = KSP_PCApplyBAorAB(ksp, VX, VVR[0], VTM); CHKERRQ(ierr); ierr = VecAYPX(VVR[0], -1.0, VB); CHKERRQ(ierr); rnmax_true = zeta; if (bUpdateX) { ierr = VecAXPY(VXR,1.0,VX); CHKERRQ(ierr); ierr = VecSet(VX,0.0); CHKERRQ(ierr); ierr = VecCopy(VVR[0], VB); CHKERRQ(ierr); rnmax_computed = zeta; } } } } if (bcgsl->delta>0.0) { ierr = VecAXPY(VX,1.0,VXR); CHKERRQ(ierr); } ierr = (*ksp->converged)(ksp, k, zeta, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS; PetscFunctionReturn(0); }