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(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)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); }
static PetscErrorCode KSPSolve_PGMRES(KSP ksp) { PetscErrorCode ierr; PetscInt its,itcount; KSP_PGMRES *pgmres = (KSP_PGMRES*)ksp->data; PetscBool guess_zero = ksp->guess_zero; PetscFunctionBegin; if (ksp->calc_sings && !pgmres->Rsvd) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ORDER,"Must call KSPSetComputeSingularValues() before KSPSetUp() is called"); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); itcount = 0; ksp->reason = KSP_CONVERGED_ITERATING; while (!ksp->reason) { ierr = KSPInitialResidual(ksp,ksp->vec_sol,VEC_TEMP,VEC_TEMP_MATOP,VEC_VV(0),ksp->vec_rhs);CHKERRQ(ierr); ierr = KSPPGMRESCycle(&its,ksp);CHKERRQ(ierr); itcount += 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); }
static PetscErrorCode KSPSolve_AGMRES(KSP ksp) { PetscErrorCode ierr; PetscInt its; KSP_AGMRES *agmres = (KSP_AGMRES*)ksp->data; PetscBool guess_zero = ksp->guess_zero; PetscReal res_old, res; PetscInt test; PetscFunctionBegin; ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->reason = KSP_CONVERGED_ITERATING; if (!agmres->HasShifts) { /* Compute Shifts for the Newton basis */ ierr = KSPComputeShifts_DGMRES(ksp);CHKERRQ(ierr); } /* NOTE: At this step, the initial guess is not equal to zero since one cycle of the classical GMRES is performed to compute the shifts */ ierr = (*ksp->converged)(ksp,0,ksp->rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); while (!ksp->reason) { ierr = KSPInitialResidual(ksp,ksp->vec_sol,VEC_TMP,VEC_TMP_MATOP,VEC_V(0),ksp->vec_rhs);CHKERRQ(ierr); if ((ksp->pc_side == PC_LEFT) && agmres->r && agmres->DeflPrecond) { ierr = KSPDGMRESApplyDeflation_DGMRES(ksp, VEC_V(0), VEC_TMP);CHKERRQ(ierr); ierr = VecCopy(VEC_TMP, VEC_V(0));CHKERRQ(ierr); agmres->matvecs += 1; } ierr = VecNormalize(VEC_V(0),&(ksp->rnorm));CHKERRQ(ierr); KSPCheckNorm(ksp,ksp->rnorm); res_old = ksp->rnorm; /* Record the residual norm to test if deflation is needed */ ksp->ops->buildsolution = KSPBuildSolution_AGMRES; ierr = KSPAGMRESCycle(&its,ksp);CHKERRQ(ierr); if (ksp->its >= ksp->max_it) { if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS; break; } /* compute the eigenvectors to augment the subspace : use an adaptive strategy */ res = ksp->rnorm; if (!ksp->reason && agmres->neig > 0) { test = agmres->max_k * PetscLogReal(ksp->rtol/res) / PetscLogReal(res/res_old); /* estimate the remaining number of steps */ if ((test > agmres->smv*(ksp->max_it-ksp->its)) || agmres->force) { if (!agmres->force && ((test > agmres->bgv*(ksp->max_it-ksp->its)) && ((agmres->r + 1) < agmres->max_neig))) { agmres->neig += 1; /* Augment the number of eigenvalues to deflate if the convergence is too slow */ } ierr = KSPDGMRESComputeDeflationData_DGMRES(ksp,&agmres->neig);CHKERRQ(ierr); } } ksp->guess_zero = PETSC_FALSE; /* every future call to KSPInitialResidual() will have nonzero guess */ } ksp->guess_zero = guess_zero; /* restore if user has provided nonzero initial guess */ 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(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ORDER,"Must call KSPSetComputeSingularValues() before KSPSetUp() is called"); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; lgmres->aug_ct = 0; lgmres->matvecs = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)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); }
/* KSPSolve_PIPEFGMRES - This routine applies the PIPEFGMRES method. Input Parameter: . ksp - the Krylov space object that was set to use pipefgmres Output Parameter: . outits - number of iterations used */ static PetscErrorCode KSPSolve_PIPEFGMRES(KSP ksp) { PetscErrorCode ierr; PetscInt its,itcount; KSP_PIPEFGMRES *pipefgmres = (KSP_PIPEFGMRES*)ksp->data; PetscBool guess_zero = ksp->guess_zero; PetscFunctionBegin; /* We have not checked these routines for use with complex numbers. The inner products are likely not defined correctly for that case */ #if (defined(PETSC_USE_COMPLEX) && !defined(PETSC_SKIP_COMPLEX)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"PIPEFGMRES has not been implemented for use with complex scalars"); #endif ierr = PetscCitationsRegister(citation,&cited);CHKERRQ(ierr); if (ksp->calc_sings && !pipefgmres->Rsvd) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ORDER,"Must call KSPSetComputeSingularValues() before KSPSetUp() is called"); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); itcount = 0; ksp->reason = KSP_CONVERGED_ITERATING; while (!ksp->reason) { ierr = KSPInitialResidual(ksp,ksp->vec_sol,VEC_TEMP,VEC_TEMP_MATOP,VEC_VV(0),ksp->vec_rhs);CHKERRQ(ierr); ierr = KSPPIPEFGMRESCycle(&its,ksp);CHKERRQ(ierr); itcount += 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 KSPSolve_FBCGSR(KSP ksp) { PetscErrorCode ierr; PetscInt i,j,N; PetscScalar tau,sigma,alpha,omega,beta; PetscReal rho; PetscScalar xi1,xi2,xi3,xi4; Vec X,B,P,P2,RP,R,V,S,T,S2; PetscScalar *PETSC_RESTRICT rp, *PETSC_RESTRICT r, *PETSC_RESTRICT p; PetscScalar *PETSC_RESTRICT v, *PETSC_RESTRICT s, *PETSC_RESTRICT t, *PETSC_RESTRICT s2; PetscScalar insums[4],outsums[4]; KSP_BCGS *bcgs = (KSP_BCGS*)ksp->data; PC pc; PetscFunctionBegin; if (!ksp->vec_rhs->petscnative) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Only coded for PETSc vectors"); ierr = VecGetLocalSize(ksp->vec_sol,&N); CHKERRQ(ierr); X = ksp->vec_sol; B = ksp->vec_rhs; P2 = ksp->work[0]; /* The followings are involved in modified inner product calculations and vector updates */ RP = ksp->work[1]; ierr = VecGetArray(RP,(PetscScalar**)&rp); CHKERRQ(ierr); ierr = VecRestoreArray(RP,NULL); CHKERRQ(ierr); R = ksp->work[2]; ierr = VecGetArray(R,(PetscScalar**)&r); CHKERRQ(ierr); ierr = VecRestoreArray(R,NULL); CHKERRQ(ierr); P = ksp->work[3]; ierr = VecGetArray(P,(PetscScalar**)&p); CHKERRQ(ierr); ierr = VecRestoreArray(P,NULL); CHKERRQ(ierr); V = ksp->work[4]; ierr = VecGetArray(V,(PetscScalar**)&v); CHKERRQ(ierr); ierr = VecRestoreArray(V,NULL); CHKERRQ(ierr); S = ksp->work[5]; ierr = VecGetArray(S,(PetscScalar**)&s); CHKERRQ(ierr); ierr = VecRestoreArray(S,NULL); CHKERRQ(ierr); T = ksp->work[6]; ierr = VecGetArray(T,(PetscScalar**)&t); CHKERRQ(ierr); ierr = VecRestoreArray(T,NULL); CHKERRQ(ierr); S2 = ksp->work[7]; ierr = VecGetArray(S2,(PetscScalar**)&s2); CHKERRQ(ierr); ierr = VecRestoreArray(S2,NULL); CHKERRQ(ierr); /* Only supports right preconditioning */ if (ksp->pc_side != PC_RIGHT) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"KSP fbcgsr does not support %s",PCSides[ksp->pc_side]); if (!ksp->guess_zero) { if (!bcgs->guess) { ierr = VecDuplicate(X,&bcgs->guess); CHKERRQ(ierr); } ierr = VecCopy(X,bcgs->guess); CHKERRQ(ierr); } else { ierr = VecSet(X,0.0); CHKERRQ(ierr); } /* Compute initial residual */ ierr = KSPGetPC(ksp,&pc); CHKERRQ(ierr); ierr = PCSetUp(pc); CHKERRQ(ierr); if (!ksp->guess_zero) { ierr = MatMult(pc->mat,X,P2); CHKERRQ(ierr); /* P2 is used as temporary storage */ ierr = VecCopy(B,R); CHKERRQ(ierr); ierr = VecAXPY(R,-1.0,P2); CHKERRQ(ierr); } else { ierr = VecCopy(B,R); CHKERRQ(ierr); } /* Test for nothing to do */ if (ksp->normtype != KSP_NORM_NONE) { ierr = VecNorm(R,NORM_2,&rho); CHKERRQ(ierr); } ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp); CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = rho; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp); CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rho); CHKERRQ(ierr); ierr = KSPMonitor(ksp,0,rho); CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,0,rho,&ksp->reason,ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); /* Initialize iterates */ ierr = VecCopy(R,RP); CHKERRQ(ierr); /* rp <- r */ ierr = VecCopy(R,P); CHKERRQ(ierr); /* p <- r */ /* Big loop */ for (i=0; i<ksp->max_it; i++) { /* matmult and pc */ ierr = PCApply(pc,P,P2); CHKERRQ(ierr); /* p2 <- K p */ ierr = MatMult(pc->mat,P2,V); CHKERRQ(ierr); /* v <- A p2 */ /* inner prodcuts */ if (i==0) { tau = rho*rho; ierr = VecDot(V,RP,&sigma); CHKERRQ(ierr); /* sigma <- (v,rp) */ } else { ierr = PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0); CHKERRQ(ierr); tau = sigma = 0.0; for (j=0; j<N; j++) { tau += r[j]*rp[j]; /* tau <- (r,rp) */ sigma += v[j]*rp[j]; /* sigma <- (v,rp) */ } PetscLogFlops(4.0*N); ierr = PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0); CHKERRQ(ierr); insums[0] = tau; insums[1] = sigma; ierr = PetscLogEventBarrierBegin(VEC_ReduceBarrier,0,0,0,0,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); ierr = MPI_Allreduce(insums,outsums,2,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); ierr = PetscLogEventBarrierEnd(VEC_ReduceBarrier,0,0,0,0,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); tau = outsums[0]; sigma = outsums[1]; } /* scalar update */ alpha = tau / sigma; /* vector update */ ierr = VecWAXPY(S,-alpha,V,R); CHKERRQ(ierr); /* s <- r - alpha v */ /* matmult and pc */ ierr = PCApply(pc,S,S2); CHKERRQ(ierr); /* s2 <- K s */ ierr = MatMult(pc->mat,S2,T); CHKERRQ(ierr); /* t <- A s2 */ /* inner prodcuts */ ierr = PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0); CHKERRQ(ierr); xi1 = xi2 = xi3 = xi4 = 0.0; for (j=0; j<N; j++) { xi1 += s[j]*s[j]; /* xi1 <- (s,s) */ xi2 += t[j]*s[j]; /* xi2 <- (t,s) */ xi3 += t[j]*t[j]; /* xi3 <- (t,t) */ xi4 += t[j]*rp[j]; /* xi4 <- (t,rp) */ } PetscLogFlops(8.0*N); ierr = PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0); CHKERRQ(ierr); insums[0] = xi1; insums[1] = xi2; insums[2] = xi3; insums[3] = xi4; ierr = PetscLogEventBarrierBegin(VEC_ReduceBarrier,0,0,0,0,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); ierr = MPI_Allreduce(insums,outsums,4,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); ierr = PetscLogEventBarrierEnd(VEC_ReduceBarrier,0,0,0,0,PetscObjectComm((PetscObject)ksp)); CHKERRQ(ierr); xi1 = outsums[0]; xi2 = outsums[1]; xi3 = outsums[2]; xi4 = outsums[3]; /* test denominator */ if (xi3 == 0.0) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Divide by zero"); if (sigma == 0.0) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_PLIB,"Divide by zero"); /* scalar updates */ omega = xi2 / xi3; beta = -xi4 / sigma; rho = PetscSqrtReal(PetscAbsScalar(xi1 - omega * xi2)); /* residual norm */ /* vector updates */ ierr = VecAXPBYPCZ(X,alpha,omega,1.0,P2,S2); CHKERRQ(ierr); /* x <- alpha * p2 + omega * s2 + x */ /* convergence test */ ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp); CHKERRQ(ierr); ksp->its++; ksp->rnorm = rho; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp); CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rho); CHKERRQ(ierr); ierr = KSPMonitor(ksp,i+1,rho); CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i+1,rho,&ksp->reason,ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) break; /* vector updates */ ierr = PetscLogEventBegin(VEC_Ops,0,0,0,0); CHKERRQ(ierr); for (j=0; j<N; j++) { r[j] = s[j] - omega * t[j]; /* r <- s - omega t */ p[j] = r[j] + beta * (p[j] - omega * v[j]); /* p <- r + beta * (p - omega v) */ } PetscLogFlops(6.0*N); ierr = PetscLogEventEnd(VEC_Ops,0,0,0,0); CHKERRQ(ierr); } if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS; 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 */ ierr = KSPLogResidualHistory(ksp,res);CHKERRQ(ierr); 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = res; ierr = PetscObjectSAWsGrantAccess((PetscObject)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) { if (ksp->errorifnotconverged) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_NOT_CONVERGED,"You reached the happy break down, but convergence was not indicated. Residual norm = %G",res); else { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } } } } /* END OF ITERATION LOOP */ ierr = KSPLogResidualHistory(ksp,res);CHKERRQ(ierr); /* 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 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; ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { if (fas->eventresidual) {ierr = PetscLogEventBegin(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);} ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (fas->eventresidual) {ierr = PetscLogEventEnd(fas->eventresidual,0,0,0,0);CHKERRQ(ierr);} if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else snes->vec_func_init_set = PETSC_FALSE; ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* 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 if (fas->fastype == SNES_FAS_ADDITIVE) { ierr = SNESFASCycle_Additive(snes, X);CHKERRQ(ierr); } else if (fas->fastype == SNES_FAS_FULL) { ierr = SNESFASCycle_Full(snes, X);CHKERRQ(ierr); } else if (fas->fastype ==SNES_FAS_KASKADE) { ierr = SNESFASCycle_Kaskade(snes, X);CHKERRQ(ierr); } else { SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Unsupported FAS type"); } /* check for FAS cycle divergence */ if (snes->reason != SNES_CONVERGED_ITERATING) PetscFunctionReturn(0); /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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); }
PetscErrorCode SNESSolve_NASM(SNES snes) { Vec F; Vec X; Vec B; Vec Y; PetscInt i; PetscReal fnorm = 0.0; PetscErrorCode ierr; SNESNormSchedule normschedule; SNES_NASM *nasm = (SNES_NASM*)snes->data; PetscFunctionBegin; X = snes->vec_sol; Y = snes->vec_sol_update; F = snes->vec_func; B = snes->vec_rhs; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; ierr = SNESGetNormSchedule(snes, &normschedule);CHKERRQ(ierr); if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY) { /* compute the initial function and preconditioned update delX */ 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; ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } else { ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); } /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* copy the initial solution over for later */ if (nasm->fjtype == 2) {ierr = VecCopy(X,nasm->xinit);CHKERRQ(ierr);} for (i = 0; i < snes->max_its; i++) { ierr = SNESNASMSolveLocal_Private(snes,B,Y,X);CHKERRQ(ierr); if (normschedule == SNES_NORM_ALWAYS || ((i == snes->max_its - 1) && (normschedule == SNES_NORM_INITIAL_FINAL_ONLY || normschedule == SNES_NORM_FINAL_ONLY))) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; break; } ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; break; } } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ if (normschedule == SNES_NORM_ALWAYS) {ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);} if (snes->reason) break; /* Call general purpose update function */ if (snes->ops->update) {ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);} } if (nasm->finaljacobian) {ierr = SNESNASMComputeFinalJacobian_Private(snes,X);CHKERRQ(ierr);} if (normschedule == SNES_NORM_ALWAYS) { 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; } } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* NASM is meant to be used as a preconditioner */ PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_NCG(SNES snes) { SNES_NCG *ncg = (SNES_NCG*)snes->data; Vec X,dX,lX,F,dXold; PetscReal fnorm, ynorm, xnorm, beta = 0.0; PetscScalar dXdotdX, dXolddotdXold, dXdotdXold, lXdotdX, lXdotdXold; PetscInt maxits, i; PetscErrorCode ierr; PetscBool lsSuccess = PETSC_TRUE; SNESLineSearch linesearch; SNESConvergedReason reason; PetscFunctionBegin; ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* X^n */ dXold = 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 */ ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); /* compute the initial function and preconditioned update dX */ if (snes->pc && snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,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 = VecCopy(dX,F);CHKERRQ(ierr); ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); } else { 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; /* convergence test */ ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } ierr = VecCopy(F,dX);CHKERRQ(ierr); } if (snes->pc) { if (snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { ierr = SNESApplyNPC(snes,X,F,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 = VecCopy(dX,lX);CHKERRQ(ierr); ierr = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* 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 */ 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(dX, dXold);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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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) { if (snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,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 = VecCopy(dX,F);CHKERRQ(ierr); } else { ierr = SNESApplyNPC(snes,X,F,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); } } } 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 */ dXolddotdXold= dXdotdX; ierr = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr); beta = PetscRealPart(dXdotdX / dXolddotdXold); break; case SNES_NCG_PRP: /* Polak-Ribiere-Poylak */ dXolddotdXold= dXdotdX; ierr = VecDotBegin(dX, dX, &dXdotdXold);CHKERRQ(ierr); ierr = VecDotBegin(dXold, dX, &dXdotdXold);CHKERRQ(ierr); ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(dXold, dX, &dXdotdXold);CHKERRQ(ierr); beta = PetscRealPart(((dXdotdX - dXdotdXold) / dXolddotdXold)); if (beta < 0.0) beta = 0.0; /* restart */ break; case SNES_NCG_HS: /* Hestenes-Stiefel */ ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotBegin(dX, dXold, &dXdotdXold);CHKERRQ(ierr); ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr); ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr); ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(dX, dXold, &dXdotdXold);CHKERRQ(ierr); ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr); beta = PetscRealPart((dXdotdX - dXdotdXold) / (lXdotdX - lXdotdXold)); break; case SNES_NCG_DY: /* Dai-Yuan */ ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr); ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr); ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr); beta = PetscRealPart(dXdotdX / (lXdotdXold - lXdotdX));CHKERRQ(ierr); break; case SNES_NCG_CD: /* Conjugate Descent */ ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr); ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr); ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr); beta = PetscRealPart(dXdotdX / lXdotdXold);CHKERRQ(ierr); break; } if (ncg->monitor) { ierr = PetscViewerASCIIPrintf(ncg->monitor, "beta = %e\n", (double)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); }
PetscErrorCode SNESSolve_Anderson(SNES snes) { SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data; /* present solution, residual, and preconditioned residual */ Vec X,F,B,D; /* candidate linear combination answers */ Vec XA,FA,XM,FM; /* coefficients and RHS to the minimization problem */ PetscReal fnorm,fMnorm,fAnorm; PetscReal xnorm,ynorm; PetscReal dnorm,dminnorm=0.0,fminnorm; PetscInt restart_count=0; PetscInt k,k_restart,l,ivec; PetscBool selectRestart; SNESConvergedReason reason; PetscErrorCode ierr; PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) { SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); } ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); /* variable initialization */ snes->reason = SNES_CONVERGED_ITERATING; X = snes->vec_sol; F = snes->vec_func; B = snes->vec_rhs; XA = snes->vec_sol_update; FA = snes->work[0]; D = snes->work[1]; /* work for the line search */ XM = snes->work[3]; FM = snes->work[4]; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); /* initialization */ /* r = F(x) */ if (snes->pc && snes->pcside == PC_LEFT) { ierr = SNESApplyNPC(snes,X,NULL,F);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 = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); } else { if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); } else snes->vec_func_init_set = PETSC_FALSE; ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); SNESCheckFunctionNorm(snes,fnorm); } fminnorm = fnorm; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); k_restart = 0; l = 0; ivec = 0; for (k=1; k < snes->max_its+1; k++) { /* select which vector of the stored subspace will be updated */ if (snes->pc && snes->pcside == PC_RIGHT) { ierr = VecCopy(X,XM);CHKERRQ(ierr); ierr = SNESSetInitialFunction(snes->pc,F);CHKERRQ(ierr); ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,XM,B,0);CHKERRQ(ierr); ierr = SNESSolve(snes->pc,B,XM);CHKERRQ(ierr); ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,XM,B,0);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 = SNESGetNPCFunction(snes,FM,&fMnorm);CHKERRQ(ierr); if (ngmres->andersonBeta != 1.0) { VecAXPBY(XM,(1.0 - ngmres->andersonBeta),ngmres->andersonBeta,X);CHKERRQ(ierr); } } else { ierr = VecCopy(F,FM);CHKERRQ(ierr); ierr = VecCopy(X,XM);CHKERRQ(ierr); ierr = VecAXPY(XM,-ngmres->andersonBeta,FM);CHKERRQ(ierr); fMnorm = fnorm; } ierr = SNESNGMRESFormCombinedSolution_Private(snes,ivec,l,XM,FM,fMnorm,X,XA,FA);CHKERRQ(ierr); ivec = k_restart % ngmres->msize; if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) { ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,&dnorm,&dminnorm,NULL,NULL,NULL,&xnorm,&fAnorm,&ynorm);CHKERRQ(ierr); ierr = SNESNGMRESSelectRestart_Private(snes,l,fMnorm,fnorm,dnorm,fminnorm,dminnorm,&selectRestart);CHKERRQ(ierr); /* if the restart conditions persist for more than restart_it iterations, restart. */ if (selectRestart) restart_count++; else restart_count = 0; } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) { ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,NULL,NULL,NULL,&xnorm,&fAnorm,&ynorm);CHKERRQ(ierr); if (k_restart > ngmres->restart_periodic) { if (ngmres->monitor) ierr = PetscViewerASCIIPrintf(ngmres->monitor,"periodic restart after %D iterations\n",k_restart);CHKERRQ(ierr); restart_count = ngmres->restart_it; } } else { ierr = SNESNGMRESNorms_Private(snes,l,X,F,XM,FM,XA,FA,D,NULL,NULL,NULL,NULL,NULL,&xnorm,&fAnorm,&ynorm);CHKERRQ(ierr); } /* restart after restart conditions have persisted for a fixed number of iterations */ if (restart_count >= ngmres->restart_it) { if (ngmres->monitor) { ierr = PetscViewerASCIIPrintf(ngmres->monitor,"Restarted at iteration %d\n",k_restart);CHKERRQ(ierr); } restart_count = 0; k_restart = 0; l = 0; ivec = 0; } else { if (l < ngmres->msize) l++; k_restart++; ierr = SNESNGMRESUpdateSubspace_Private(snes,ivec,l,FM,fnorm,XM);CHKERRQ(ierr); } fnorm = fAnorm; if (fminnorm > fnorm) fminnorm = fnorm; ierr = VecCopy(XA,X);CHKERRQ(ierr); ierr = VecCopy(FA,F);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = k; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } 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(PetscObjectComm((PetscObject)ksp),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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);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); /* 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); 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); }
PetscErrorCode KSPSolve_BiCG(KSP ksp) { PetscErrorCode ierr; PetscInt i; PetscBool 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; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),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);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 */ } ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = i+1; ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); 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; 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 KSPPIPEFGMRESCycle(PetscInt *itcount,KSP ksp) { KSP_PIPEFGMRES *pipefgmres = (KSP_PIPEFGMRES*)(ksp->data); PetscReal res_norm; PetscReal hapbnd,tt; PetscScalar *hh,*hes,*lhh,shift = pipefgmres->shift; PetscBool hapend = PETSC_FALSE; /* indicates happy breakdown ending */ PetscErrorCode ierr; PetscInt loc_it; /* local count of # of dir. in Krylov space */ PetscInt max_k = pipefgmres->max_k; /* max # of directions Krylov space */ PetscInt i,j,k; Mat Amat,Pmat; Vec Q,W; /* Pipelining vectors */ Vec *redux = pipefgmres->redux; /* workspace for single reduction */ PetscFunctionBegin; if (itcount) *itcount = 0; /* Assign simpler names to these vectors, allocated as pipelining workspace */ Q = VEC_Q; W = VEC_W; /* Allocate memory for orthogonalization work (freed in the GMRES Destroy routine)*/ /* Note that we add an extra value here to allow for a single reduction */ if (!pipefgmres->orthogwork) { ierr = PetscMalloc1(pipefgmres->max_k + 2 ,&pipefgmres->orthogwork);CHKERRQ(ierr); } lhh = pipefgmres->orthogwork; /* Number of pseudo iterations since last restart is the number of prestart directions */ loc_it = 0; /* note: (pipefgmres->it) is always set one less than (loc_it) It is used in KSPBUILDSolution_PIPEFGMRES, where it is passed to KSPPIPEFGMRESBuildSoln. Note that when KSPPIPEFGMRESBuildSoln is called from this function, (loc_it -1) is passed, so the two are equivalent */ pipefgmres->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; ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); /* 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); /* Fill the pipeline */ ierr = KSP_PCApply(ksp,VEC_VV(loc_it),PREVEC(loc_it));CHKERRQ(ierr); ierr = PCGetOperators(ksp->pc,&Amat,&Pmat);CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,PREVEC(loc_it),ZVEC(loc_it));CHKERRQ(ierr); ierr = VecAXPY(ZVEC(loc_it),-shift,VEC_VV(loc_it));CHKERRQ(ierr); /* Note shift */ /* 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) { ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); } pipefgmres->it = (loc_it - 1); /* see if more space is needed for work vectors */ if (pipefgmres->vv_allocated <= loc_it + VEC_OFFSET + 1) { ierr = KSPPIPEFGMRESGetNewVectors(ksp,loc_it+1);CHKERRQ(ierr); /* (loc_it+1) is passed in as number of the first vector that should be allocated */ } /* Note that these inner products are with "Z" now, so in particular, lhh[loc_it] is the 'barred' or 'shifted' value, not the value from the equivalent FGMRES run (even in exact arithmetic) That is, the H we need for the Arnoldi relation is different from the coefficients we use in the orthogonalization process,because of the shift */ /* Do some local twiddling to allow for a single reduction */ for(i=0;i<loc_it+1;i++){ redux[i] = VEC_VV(i); } redux[loc_it+1] = ZVEC(loc_it); /* note the extra dot product which ends up in lh[loc_it+1], which computes ||z||^2 */ ierr = VecMDotBegin(ZVEC(loc_it),loc_it+2,redux,lhh);CHKERRQ(ierr); /* Start the split reduction (This actually calls the MPI_Iallreduce, otherwise, the reduction is simply delayed until the "end" call)*/ ierr = PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)ZVEC(loc_it)));CHKERRQ(ierr); /* The work to be overlapped with the inner products follows. This is application of the preconditioner and the operator to compute intermediate quantites which will be combined (locally) with the results of the inner products. */ ierr = KSP_PCApply(ksp,ZVEC(loc_it),Q);CHKERRQ(ierr); ierr = PCGetOperators(ksp->pc,&Amat,&Pmat);CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,Q,W);CHKERRQ(ierr); /* Compute inner products of the new direction with previous directions, and the norm of the to-be-orthogonalized direction "Z". This information is enough to build the required entries of H. The inner product with VEC_VV(it_loc) is *different* than in the standard FGMRES and need to be dealt with specially. That is, for standard FGMRES the orthogonalization coefficients are the same as the coefficients used in the Arnoldi relation to reconstruct, but here this is not true (albeit only for the one entry of H which we "unshift" below. */ /* Finish the dot product, retrieving the extra entry */ ierr = VecMDotEnd(ZVEC(loc_it),loc_it+2,redux,lhh);CHKERRQ(ierr); tt = PetscRealPart(lhh[loc_it+1]); /* Hessenberg entries, and entries for (naive) classical Graham-Schmidt Note that the Hessenberg entries require a shift, as these are for the relation AU = VH, which is wrt unshifted basis vectors */ hh = HH(0,loc_it); hes=HES(0,loc_it); for (j=0; j<loc_it; j++) { hh[j] = lhh[j]; hes[j] = lhh[j]; } hh[loc_it] = lhh[loc_it] + shift; hes[loc_it] = lhh[loc_it] + shift; /* we delay applying the shift here */ for (j=0; j<=loc_it; j++) { lhh[j] = -lhh[j]; /* flip sign */ } /* Compute the norm of the un-normalized new direction using the rearranged formula Note that these are shifted ("barred") quantities */ for(k=0;k<=loc_it;k++) tt -= ((PetscReal)(PetscAbsScalar(lhh[k]) * PetscAbsScalar(lhh[k]))); /* On AVX512 this is accumulating roundoff errors for eg: tt=-2.22045e-16 */ if ((tt < 0.0) && tt > -PETSC_SMALL) tt = 0.0 ; if (tt < 0.0) { /* If we detect square root breakdown in the norm, we must restart the algorithm. Here this means we simply break the current loop and reconstruct the solution using the basis we have computed thus far. Note that by breaking immediately, we do not update the iteration count, so computation done in this iteration should be disregarded. */ ierr = PetscInfo2(ksp,"Restart due to square root breakdown at it = %D, tt=%g\n",ksp->its,(double)tt);CHKERRQ(ierr); break; } else { tt = PetscSqrtReal(tt); } /* new entry in hessenburg is the 2-norm of our new direction */ hh[loc_it+1] = tt; hes[loc_it+1] = tt; /* The recurred computation for the new direction The division by tt is delayed to the happy breakdown check later Note placement BEFORE the unshift */ ierr = VecCopy(ZVEC(loc_it),VEC_VV(loc_it+1));CHKERRQ(ierr); ierr = VecMAXPY(VEC_VV(loc_it+1),loc_it+1,lhh,&VEC_VV(0));CHKERRQ(ierr); /* (VEC_VV(loc_it+1) is not normalized yet) */ /* The recurred computation for the preconditioned vector (u) */ ierr = VecCopy(Q,PREVEC(loc_it+1));CHKERRQ(ierr); ierr = VecMAXPY(PREVEC(loc_it+1),loc_it+1,lhh,&PREVEC(0));CHKERRQ(ierr); ierr = VecScale(PREVEC(loc_it+1),1.0/tt);CHKERRQ(ierr); /* Unshift an entry in the GS coefficients ("removing the bar") */ lhh[loc_it] -= shift; /* The recurred computation for z (Au) Note placement AFTER the "unshift" */ ierr = VecCopy(W,ZVEC(loc_it+1));CHKERRQ(ierr); ierr = VecMAXPY(ZVEC(loc_it+1),loc_it+1,lhh,&ZVEC(0));CHKERRQ(ierr); ierr = VecScale(ZVEC(loc_it+1),1.0/tt);CHKERRQ(ierr); /* Happy Breakdown Check */ hapbnd = PetscAbsScalar((tt) / *RS(loc_it)); /* RS(loc_it) contains the res_norm from the last iteration */ hapbnd = PetscMin(pipefgmres->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 pipefgmres 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 not 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.*/ /* Note that to be thorough, in debug mode, one could call a LAPACK routine here to check that the hessenberg matrix is indeed non-singular (since FGMRES does not guarantee this) */ /* 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 = KSPPIPEFGMRESUpdateHessenberg(ksp,loc_it,&hapend,&res_norm);CHKERRQ(ierr); if (ksp->reason) break; loc_it++; pipefgmres->it = (loc_it-1); /* Add this here in case it has converged */ ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = res_norm; ierr = PetscObjectSAWsGrantAccess((PetscObject)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) { if (ksp->errorifnotconverged) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_NOT_CONVERGED,"You reached the happy break down, but convergence was not indicated. Residual norm = %g",(double)res_norm); else { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } } } } /* END OF ITERATION LOOP */ ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); /* Monitor if we know that we will not return for a restart */ if (loc_it && (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 KSPPIPEGMRESIIBuildSoln properly navigates */ ierr = KSPPIPEFGMRESBuildSoln(RS(0),ksp->vec_sol,ksp->vec_sol,ksp,loc_it-1);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode SNESSolve_QN(SNES snes) { PetscErrorCode ierr; SNES_QN *qn = (SNES_QN*) snes->data; Vec X,Xold; Vec F,W; Vec Y,D,Dold; PetscInt i, i_r; PetscReal fnorm,xnorm,ynorm,gnorm; SNESLineSearchReason lssucceed; PetscBool powell,periodic; PetscScalar DolddotD,DolddotDold; SNESConvergedReason reason; /* basically just a regular newton's method except for the application of the Jacobian */ PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) { SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); } ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); F = snes->vec_func; /* residual vector */ Y = snes->vec_sol_update; /* search direction generated by J^-1D*/ W = snes->work[3]; 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,F);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 = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); } else { if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); } else snes->vec_func_init_set = PETSC_FALSE; ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); SNESCheckFunctionNorm(snes,fnorm); } if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } } else { ierr = VecCopy(F,D);CHKERRQ(ierr); } ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* 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 (snes->pc && snes->pcside == PC_RIGHT) { ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);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 = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr); ierr = VecCopy(F,D);CHKERRQ(ierr); } /* scale the initial update */ if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); } for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) { if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) { PetscScalar ff,xf; ierr = VecCopy(Dold,Y);CHKERRQ(ierr); ierr = VecCopy(Xold,W);CHKERRQ(ierr); ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr); ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr); ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr); ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr); ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr); ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr); qn->scaling = PetscRealPart(xf)/PetscRealPart(ff); } 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);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; ierr = SNESLineSearchGetReason(snes->linesearch, &lssucceed);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); if (lssucceed) { if (++snes->numFailures >= snes->maxFailures) { snes->reason = SNES_DIVERGED_LINE_SEARCH; break; } } 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); if (snes->pc && snes->pcside == PC_RIGHT) { ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr); ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr); ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);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 = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr); } ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr); snes->norm = fnorm; ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr); 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_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } } 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| */ if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr); } else { ierr = VecCopy(Dold,W);CHKERRQ(ierr); } ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr); ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr); ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr); ierr = VecDotEnd(W, D, &DolddotD);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);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_NGS(SNES snes) { Vec F; Vec X; Vec B; PetscInt i; PetscReal fnorm; PetscErrorCode ierr; SNESNormSchedule normschedule; PetscFunctionBegin; ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); X = snes->vec_sol; F = snes->vec_func; B = snes->vec_rhs; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; ierr = SNESGetNormSchedule(snes, &normschedule);CHKERRQ(ierr); if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY) { /* compute the initial function and preconditioned update delX */ 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; ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } else { ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); } /* 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 = SNESComputeNGS(snes, B, X);CHKERRQ(ierr); /* only compute norms if requested or about to exit due to maximum iterations */ if (normschedule == SNES_NORM_ALWAYS || ((i == snes->max_its - 1) && (normschedule == SNES_NORM_INITIAL_FINAL_ONLY || normschedule == SNES_NORM_FINAL_ONLY))) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ if (normschedule == SNES_NORM_ALWAYS) 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 (normschedule == SNES_NORM_ALWAYS) { 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; } } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* GS is meant to be used as a preconditioner */ PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_Chebyshev(KSP ksp) { KSP_Chebyshev *cheb = (KSP_Chebyshev*)ksp->data; PetscErrorCode ierr; PetscInt k,kp1,km1,maxit,ktmp,i; PetscScalar alpha,omegaprod,mu,omega,Gamma,c[3],scale; PetscReal rnorm = 0.0; Vec sol_orig,b,p[3],r; Mat Amat,Pmat; PetscBool diagonalscale; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); if (cheb->kspest && !cheb->estimate_current) { PetscReal max=0.0,min=0.0; Vec X,B; X = ksp->work[0]; if (cheb->random) { B = ksp->work[1]; ierr = VecSetRandom(B,cheb->random);CHKERRQ(ierr); } else { B = ksp->vec_rhs; } ierr = KSPSolve(cheb->kspest,B,X);CHKERRQ(ierr); if (ksp->guess_zero) { ierr = VecZeroEntries(X);CHKERRQ(ierr); } ierr = KSPChebyshevComputeExtremeEigenvalues_Private(cheb->kspest,&min,&max);CHKERRQ(ierr); cheb->emin = cheb->tform[0]*min + cheb->tform[1]*max; cheb->emax = cheb->tform[2]*min + cheb->tform[3]*max; cheb->estimate_current = PETSC_TRUE; } ksp->its = 0; ierr = PCGetOperators(ksp->pc,&Amat,&Pmat);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; sol_orig = ksp->vec_sol; /* ksp->vec_sol will be asigned to rotating vector p[k], thus save its address */ b = ksp->vec_rhs; p[km1] = sol_orig; p[k] = ksp->work[0]; p[kp1] = ksp->work[1]; r = ksp->work[2]; /* use scale*B as our preconditioner */ scale = 2.0/(cheb->emax + cheb->emin); /* -alpha <= scale*lambda(B^{-1}A) <= alpha */ alpha = 1.0 - scale*(cheb->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,p[km1],r);CHKERRQ(ierr); /* r = b - A*p[km1] */ 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 + p[km1] */ ierr = VecAYPX(p[k],scale,p[km1]);CHKERRQ(ierr); for (i=0; i<maxit; i++) { ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ierr = PetscObjectSAWsGrantAccess((PetscObject)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}r */ ksp->vec_sol = p[k]; /* calculate residual norm if requested */ if (ksp->normtype != KSP_NORM_NONE || ksp->numbermonitors) { 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->rnorm = rnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rnorm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,i,rnorm);CHKERRQ(ierr); 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 = VecAXPBYPCZ(p[kp1],1.0-omega,omega,omega*Gamma*scale,p[km1],p[k]);CHKERRQ(ierr); ktmp = km1; km1 = k; k = kp1; kp1 = ktmp; } if (!ksp->reason) { if (ksp->normtype != KSP_NORM_NONE) { 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}r */ ierr = VecNorm(p[kp1],NORM_2,&rnorm);CHKERRQ(ierr); } ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->rnorm = rnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->vec_sol = p[k]; ierr = KSPLogResidualHistory(ksp,rnorm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,i,rnorm);CHKERRQ(ierr); } if (ksp->its >= ksp->max_it) { if (ksp->normtype != KSP_NORM_NONE) { 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 = sol_orig; if (k) { ierr = VecCopy(p[k],sol_orig);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/* SNESSolve_VINEWTONSSLS - Solves the complementarity problem with a semismooth Newton method using a line search. Input Parameters: . snes - the SNES context Application Interface Routine: SNESSolve() Notes: This implements essentially a semismooth Newton method with a line search. The default line search does not do any line search but rather takes a full Newton step. Developer Note: the code in this file should be slightly modified so that this routine need not exist and the SNESSolve_NEWTONLS() routine is called directly with the appropriate wrapped function and Jacobian evaluations */ PetscErrorCode SNESSolve_VINEWTONSSLS(SNES snes) { SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*)snes->data; PetscErrorCode ierr; PetscInt maxits,i,lits; SNESLineSearchReason lssucceed; PetscReal gnorm,xnorm=0,ynorm; Vec Y,X,F; KSPConvergedReason kspreason; DM dm; DMSNES sdm; PetscFunctionBegin; ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); ierr = DMGetDMSNES(dm,&sdm);CHKERRQ(ierr); vi->computeuserfunction = sdm->ops->computefunction; sdm->ops->computefunction = SNESVIComputeFunction; 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr); ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr); if (snes->domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; sdm->ops->computefunction = vi->computeuserfunction; PetscFunctionReturn(0); } /* Compute Merit function */ ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr); ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm <- ||x|| */ ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); SNESCheckFunctionNorm(snes,vi->merit); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = vi->phinorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,vi->phinorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr); /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) { sdm->ops->computefunction = vi->computeuserfunction; 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 = Phi, where J is the semismooth jacobian */ /* Get the jacobian -- note that the function must be the original function for snes_fd and snes_fd_color to work for this*/ sdm->ops->computefunction = vi->computeuserfunction; ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); SNESCheckJacobianDomainerror(snes); sdm->ops->computefunction = SNESVIComputeFunction; /* Get the diagonal shift and row scaling vectors */ ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr); /* Compute the semismooth jacobian */ ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr); /* Compute the merit function gradient */ ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); ierr = KSPSolve(snes->ksp,vi->phi,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 (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 = vi->phinorm; ierr = SNESLineSearchApply(snes->linesearch, X, vi->phi, &gnorm, Y);CHKERRQ(ierr); ierr = SNESLineSearchGetReason(snes->linesearch, &lssucceed);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)vi->phinorm,(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; sdm->ops->computefunction = vi->computeuserfunction; PetscFunctionReturn(0); } if (lssucceed) { if (++snes->numFailures >= snes->maxFailures) { PetscBool ismin; snes->reason = SNES_DIVERGED_LINE_SEARCH; ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,vi->phi,X,gnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Update function and solution vectors */ vi->phinorm = gnorm; vi->merit = 0.5*vi->phinorm*vi->phinorm; /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = vi->phinorm; snes->xnorm = xnorm; snes->ynorm = ynorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence, xnorm = || X || */ if (snes->ops->converged != SNESConvergedSkip) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&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; } sdm->ops->computefunction = vi->computeuserfunction; PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_NEWTONLS(SNES snes) { PetscErrorCode ierr; PetscInt maxits,i,lits; SNESLineSearchReason lssucceed; PetscReal fnorm,gnorm,xnorm,ynorm; Vec Y,X,F; SNESLineSearch linesearch; SNESConvergedReason reason; PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 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 */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); /* compute the preconditioned function first in the case of left preconditioning with preconditioned function */ if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,F);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 = VecNormBegin(F,NORM_2,&fnorm);CHKERRQ(ierr); ierr = VecNormEnd(F,NORM_2,&fnorm);CHKERRQ(ierr); } else { if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); } else snes->vec_func_init_set = PETSC_FALSE; } ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ SNESCheckFunctionNorm(snes,fnorm); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* 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 (snes->pc) { if (snes->pcside == PC_RIGHT) { ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,snes->vec_rhs,0);CHKERRQ(ierr); ierr = SNESSolve(snes->pc, snes->vec_rhs, X);CHKERRQ(ierr); ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,snes->vec_rhs,0);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 = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr); } else if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { ierr = SNESApplyNPC(snes,X,F,F);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } } } /* Solve J Y = F, where J is Jacobian matrix */ ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); ierr = KSPSolve(snes->ksp,F,Y);CHKERRQ(ierr); SNESCheckKSPSolve(snes); 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);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 = SNESLineSearchGetReason(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; SNESCheckFunctionNorm(snes,fnorm); 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,fnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr); 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); }
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; PetscReal zeta, zeta0, rnmax_computed, rnmax_true, nrm0; PetscBool bUpdateX; PetscInt maxit; PetscInt h, i, j, k, vi, ell; PetscBLASInt ldMZ,bierr; PetscScalar utb; PetscReal max_s, pinv_tol; PetscErrorCode ierr; PetscFunctionBegin; /* 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++; ierr = PetscBLASIntCast(ell+1,&ldMZ);CHKERRQ(ierr); /* 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = zeta0; ierr = PetscObjectSAWsGrantAccess((PetscObject)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, NULL, NULL, NULL, &maxit);CHKERRQ(ierr); for (k=0; k<maxit; k += bcgsl->ell) { ksp->its = k; ksp->rnorm = zeta; ierr = KSPLogResidualHistory(ksp, zeta);CHKERRQ(ierr); ierr = KSPMonitor(ksp, ksp->its, zeta);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp, k, zeta, &ksp->reason, ksp->cnvP);CHKERRQ(ierr); if (ksp->reason < 0) PetscFunctionReturn(0); else 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; PetscFunctionReturn(0); } 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; PetscFunctionReturn(0); } 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = k+j; ksp->rnorm = nrm0; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); if (ksp->reason < 0) PetscFunctionReturn(0); } } /* 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; ierr = PetscBLASIntCast(bcgsl->ell,&bell);CHKERRQ(ierr); AY0c[0] = -1; if (bcgsl->pinv) { #if defined(PETSC_MISSING_LAPACK_GESVD) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"GESVD - Lapack routine is unavailable."); #else # if defined(PETSC_USE_COMPLEX) PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("A","A",&bell,&bell,&MZa[1+ldMZ],&ldMZ,bcgsl->s,bcgsl->u,&bell,bcgsl->v,&bell,bcgsl->work,&bcgsl->lwork,bcgsl->realwork,&bierr)); # else PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("A","A",&bell,&bell,&MZa[1+ldMZ],&ldMZ,bcgsl->s,bcgsl->u,&bell,bcgsl->v,&bell,bcgsl->work,&bcgsl->lwork,&bierr)); # endif #endif if (bierr!=0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; PetscFunctionReturn(0); } /* Apply pseudo-inverse */ max_s = bcgsl->s[0]; for (i=1; i<bell; i++) { if (bcgsl->s[i] > max_s) { max_s = bcgsl->s[i]; } } /* tolerance is hardwired to bell*max(s)*PETSC_MACHINE_EPSILON */ pinv_tol = bell*max_s*PETSC_MACHINE_EPSILON; ierr = PetscMemzero(&AY0c[1],bell*sizeof(PetscScalar));CHKERRQ(ierr); for (i=0; i<bell; i++) { if (bcgsl->s[i] >= pinv_tol) { utb=0.; for (j=0; j<bell; j++) { utb += MZb[1+j]*bcgsl->u[i*bell+j]; } for (j=0; j<bell; j++) { AY0c[1+j] += utb/bcgsl->s[i]*bcgsl->v[j*bell+i]; } } } } else { #if defined(PETSC_MISSING_LAPACK_POTRF) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"POTRF - Lapack routine is unavailable."); #else PetscStackCallBLAS("LAPACKpotrf",LAPACKpotrf_("Lower", &bell, &MZa[1+ldMZ], &ldMZ, &bierr)); #endif if (bierr!=0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; PetscFunctionReturn(0); } ierr = PetscMemcpy(&AY0c[1],&MZb[1],bcgsl->ell*sizeof(PetscScalar));CHKERRQ(ierr); PetscStackCallBLAS("LAPACKpotrs",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; ierr = PetscBLASIntCast(bcgsl->ell-1,&neqs);CHKERRQ(ierr); #if defined(PETSC_MISSING_LAPACK_POTRF) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"POTRF - Lapack routine is unavailable."); #else PetscStackCallBLAS("LAPACKpotrf",LAPACKpotrf_("Lower", &neqs, &MZa[1+ldMZ], &ldMZ, &bierr)); #endif if (bierr!=0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; PetscFunctionReturn(0); } ierr = PetscMemcpy(&AY0c[1],&MZb[1],(bcgsl->ell-1)*sizeof(PetscScalar));CHKERRQ(ierr); PetscStackCallBLAS("LAPACKpotrs",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); PetscStackCallBLAS("LAPACKpotrs",LAPACKpotrs_("Lower", &neqs, &ione, &MZa[1+ldMZ], &ldMZ, &AYlc[1], &ldMZ, &bierr)); AYlc[0] = 0.; AYlc[bcgsl->ell] = -1; PetscStackCallBLAS("BLASgemv",BLASgemv_("NoTr", &ldMZ, &ldMZ, &aone, MZb, &ldMZ, AY0c, &ione, &azero, AYtc, &ione)); kappa0 = PetscRealPart(BLASdot_(&ldMZ, AY0c, &ione, AYtc, &ione)); /* round-off can cause negative kappa's */ if (kappa0<0) kappa0 = -kappa0; kappa0 = PetscSqrtReal(kappa0); kappaA = PetscRealPart(BLASdot_(&ldMZ, AYlc, &ione, AYtc, &ione)); PetscStackCallBLAS("BLASgemv",BLASgemv_("noTr", &ldMZ, &ldMZ, &aone, MZb, &ldMZ, AYlc, &ione, &azero, AYtc, &ione)); kappa1 = PetscRealPart(BLASdot_(&ldMZ, AYlc, &ione, AYtc, &ione)); if (kappa1<0) kappa1 = -kappa1; kappa1 = PetscSqrtReal(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; PetscFunctionReturn(0); } 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 = (PetscBool) (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); }
/* SNESSolve_NEWTONTR - Implements Newton's Method with a very simple trust region approach for solving systems of nonlinear equations. */ static PetscErrorCode SNESSolve_NEWTONTR(SNES snes) { SNES_NEWTONTR *neP = (SNES_NEWTONTR*)snes->data; Vec X,F,Y,G,Ytmp; PetscErrorCode ierr; PetscInt maxits,i,lits; 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; PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); /* F(X) */ } else snes->vec_func_init_set = PETSC_FALSE; ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- || F || */ SNESCheckFunctionNorm(snes,fnorm); ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); /* fnorm <- || F || */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); delta = xnorm ? neP->delta0*xnorm : neP->delta0; neP->delta = delta; ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* 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(((PetscObject)snes)->options,((PetscObject)snes)->prefix,"-snes_tr_ksp_regular_convergence_test",&conv,NULL);CHKERRQ(ierr); if (!conv) { SNES_TR_KSPConverged_Ctx *ctx; ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); ierr = PetscNew(&ctx);CHKERRQ(ierr); ctx->snes = snes; ierr = KSPConvergedDefaultCreate(&ctx->ctx);CHKERRQ(ierr); ierr = KSPSetConvergenceTest(ksp,SNESTR_KSPConverged_Private,ctx,SNESTR_KSPConverged_Destroy);CHKERRQ(ierr); ierr = PetscInfo(snes,"Using Krylov convergence test SNESTR_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);CHKERRQ(ierr); SNESCheckJacobianDomainerror(snes); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); ierr = KSPSolve(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",(double)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",(double)fnorm,(double)gnorm,(double)ynorm);CHKERRQ(ierr); ierr = PetscInfo3(snes,"gpred=%g, rho=%g, delta=%g\n",(double)gpnorm,(double)rho,(double)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 = SNESTR_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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; snes->xnorm = xnorm; snes->ynorm = ynorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence, xnorm = || X || */ neP->itflag = PETSC_TRUE; if (snes->ops->converged != SNESConvergedSkip) { 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 = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->reason = reason; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 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; PetscInt i; PetscErrorCode ierr; PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); } 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);CHKERRQ(ierr); } if (ms->norms) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ SNESCheckFunctionNorm(snes,fnorm); /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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); } 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 (ms->norms) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ SNESCheckFunctionNorm(snes,fnorm); /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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); }
PetscErrorCode SNESSolve_Composite(SNES snes) { Vec F; Vec X; Vec B; PetscInt i; PetscReal fnorm = 0.0, xnorm = 0.0, snorm = 0.0; PetscErrorCode ierr; SNESNormSchedule normtype; SNES_Composite *comp = (SNES_Composite*)snes->data; PetscFunctionBegin; X = snes->vec_sol; F = snes->vec_func; B = snes->vec_rhs; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; comp->innerFailures = 0; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESSetWorkVecs(snes, 1);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; ierr = SNESGetNormSchedule(snes, &normtype);CHKERRQ(ierr); if (normtype == SNES_NORM_ALWAYS || normtype == SNES_NORM_INITIAL_ONLY || normtype == SNES_NORM_INITIAL_FINAL_ONLY) { if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); } else snes->vec_func_init_set = PETSC_FALSE; if (snes->xl && snes->xu) { ierr = SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm);CHKERRQ(ierr); } else { ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ } SNESCheckFunctionNorm(snes,fnorm); ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); } else { ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,0,snes->norm);CHKERRQ(ierr); } /* 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++) { /* Copy the state before modification by application of the composite solver; we will subtract the new state after application */ ierr = VecCopy(X, snes->work[0]);CHKERRQ(ierr); if (comp->type == SNES_COMPOSITE_ADDITIVE) { ierr = SNESCompositeApply_Additive(snes,X,B,F,&fnorm);CHKERRQ(ierr); } else if (comp->type == SNES_COMPOSITE_MULTIPLICATIVE) { ierr = SNESCompositeApply_Multiplicative(snes,X,B,F,&fnorm);CHKERRQ(ierr); } else if (comp->type == SNES_COMPOSITE_ADDITIVEOPTIMAL) { ierr = SNESCompositeApply_AdditiveOptimal(snes,X,B,F,&fnorm);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Unsupported SNESComposite type"); if (snes->reason < 0) break; /* Compute the solution update for convergence testing */ ierr = VecAXPY(snes->work[0], -1.0, X);CHKERRQ(ierr); ierr = VecScale(snes->work[0], -1.0);CHKERRQ(ierr); if ((i == snes->max_its - 1) && (normtype == SNES_NORM_INITIAL_FINAL_ONLY || normtype == SNES_NORM_FINAL_ONLY)) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); if (snes->xl && snes->xu) { ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormBegin(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); ierr = SNESVIComputeInactiveSetFnorm(snes, F, X, &fnorm);CHKERRQ(ierr); ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormEnd(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); } else { ierr = VecNormBegin(F, NORM_2, &fnorm);CHKERRQ(ierr); ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormBegin(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); ierr = VecNormEnd(F, NORM_2, &fnorm);CHKERRQ(ierr); ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormEnd(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); } SNESCheckFunctionNorm(snes,fnorm); } else if (normtype == SNES_NORM_ALWAYS) { ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormBegin(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr); ierr = VecNormEnd(snes->work[0], NORM_2, &snorm);CHKERRQ(ierr); } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ if (normtype == SNES_NORM_ALWAYS) {ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,snorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);} if (snes->reason) break; /* Call general purpose update function */ if (snes->ops->update) {ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);} } if (normtype == SNES_NORM_ALWAYS) { 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; } } else if (!snes->reason) snes->reason = SNES_CONVERGED_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; PetscInt i; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr); snes->reason = SNES_CONVERGED_ITERATING; ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)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);CHKERRQ(ierr); } if (ms->norms) { ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ if (PetscIsInfOrNanReal(fnorm)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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); } 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)) { snes->reason = SNES_DIVERGED_FNORM_NAN; PetscFunctionReturn(0); } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr); 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); }
PetscErrorCode KSPSolve_QCG(KSP ksp) { /* Correpondence with documentation above: B = g = gradient, X = s = step Note: This is not coded correctly for complex arithmetic! */ KSP_QCG *pcgP = (KSP_QCG*)ksp->data; Mat Amat,Pmat; Vec W,WA,WA2,R,P,ASP,BS,X,B; PetscScalar scal,beta,rntrn,step; PetscReal q1,q2,xnorm,step1,step2,rnrm,btx,xtax; PetscReal ptasp,rtr,wtasp,bstp; PetscReal dzero = 0.0,bsnrm; PetscErrorCode ierr; PetscInt i,maxit; PC pc = ksp->pc; PCSide side; PetscBool diagonalscale; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); if (ksp->transpose_solve) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Currently does not support transpose solve"); ksp->its = 0; maxit = ksp->max_it; WA = ksp->work[0]; R = ksp->work[1]; P = ksp->work[2]; ASP = ksp->work[3]; BS = ksp->work[4]; W = ksp->work[5]; WA2 = ksp->work[6]; X = ksp->vec_sol; B = ksp->vec_rhs; if (pcgP->delta <= dzero) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_OUTOFRANGE,"Input error: delta <= 0"); ierr = KSPGetPCSide(ksp,&side);CHKERRQ(ierr); if (side != PC_SYMMETRIC) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_OUTOFRANGE,"Requires symmetric preconditioner!"); /* Initialize variables */ ierr = VecSet(W,0.0);CHKERRQ(ierr); /* W = 0 */ ierr = VecSet(X,0.0);CHKERRQ(ierr); /* X = 0 */ ierr = PCGetOperators(pc,&Amat,&Pmat);CHKERRQ(ierr); /* Compute: BS = D^{-1} B */ ierr = PCApplySymmetricLeft(pc,B,BS);CHKERRQ(ierr); ierr = VecNorm(BS,NORM_2,&bsnrm);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = bsnrm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,bsnrm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,0,bsnrm);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,0,bsnrm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); /* Compute the initial scaled direction and scaled residual */ ierr = VecCopy(BS,R);CHKERRQ(ierr); ierr = VecScale(R,-1.0);CHKERRQ(ierr); ierr = VecCopy(R,P);CHKERRQ(ierr); ierr = VecDotRealPart(R,R,&rtr);CHKERRQ(ierr); for (i=0; i<=maxit; i++) { ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); /* Compute: asp = D^{-T}*A*D^{-1}*p */ ierr = PCApplySymmetricRight(pc,P,WA);CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,WA,WA2);CHKERRQ(ierr); ierr = PCApplySymmetricLeft(pc,WA2,ASP);CHKERRQ(ierr); /* Check for negative curvature */ ierr = VecDotRealPart(P,ASP,&ptasp);CHKERRQ(ierr); if (ptasp <= dzero) { /* Scaled negative curvature direction: Compute a step so that ||w + step*p|| = delta and QS(w + step*p) is least */ if (!i) { ierr = VecCopy(P,X);CHKERRQ(ierr); ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); scal = pcgP->delta / xnorm; ierr = VecScale(X,scal);CHKERRQ(ierr); } else { /* Compute roots of quadratic */ ierr = KSPQCGQuadraticRoots(W,P,pcgP->delta,&step1,&step2);CHKERRQ(ierr); ierr = VecDotRealPart(W,ASP,&wtasp);CHKERRQ(ierr); ierr = VecDotRealPart(BS,P,&bstp);CHKERRQ(ierr); ierr = VecCopy(W,X);CHKERRQ(ierr); q1 = step1*(bstp + wtasp + .5*step1*ptasp); q2 = step2*(bstp + wtasp + .5*step2*ptasp); if (q1 <= q2) { ierr = VecAXPY(X,step1,P);CHKERRQ(ierr); } else { ierr = VecAXPY(X,step2,P);CHKERRQ(ierr); } } pcgP->ltsnrm = pcgP->delta; /* convergence in direction of */ ksp->reason = KSP_CONVERGED_CG_NEG_CURVE; /* negative curvature */ if (!i) { ierr = PetscInfo1(ksp,"negative curvature: delta=%g\n",(double)pcgP->delta);CHKERRQ(ierr); } else { ierr = PetscInfo3(ksp,"negative curvature: step1=%g, step2=%g, delta=%g\n",(double)step1,(double)step2,(double)pcgP->delta);CHKERRQ(ierr); } } else { /* Compute step along p */ step = rtr/ptasp; ierr = VecCopy(W,X);CHKERRQ(ierr); /* x = w */ ierr = VecAXPY(X,step,P);CHKERRQ(ierr); /* x <- step*p + x */ ierr = VecNorm(X,NORM_2,&pcgP->ltsnrm);CHKERRQ(ierr); if (pcgP->ltsnrm > pcgP->delta) { /* Since the trial iterate is outside the trust region, evaluate a constrained step along p so that ||w + step*p|| = delta The positive step is always better in this case. */ if (!i) { scal = pcgP->delta / pcgP->ltsnrm; ierr = VecScale(X,scal);CHKERRQ(ierr); } else { /* Compute roots of quadratic */ ierr = KSPQCGQuadraticRoots(W,P,pcgP->delta,&step1,&step2);CHKERRQ(ierr); ierr = VecCopy(W,X);CHKERRQ(ierr); ierr = VecAXPY(X,step1,P);CHKERRQ(ierr); /* x <- step1*p + x */ } pcgP->ltsnrm = pcgP->delta; ksp->reason = KSP_CONVERGED_CG_CONSTRAINED; /* convergence along constrained step */ if (!i) { ierr = PetscInfo1(ksp,"constrained step: delta=%g\n",(double)pcgP->delta);CHKERRQ(ierr); } else { ierr = PetscInfo3(ksp,"constrained step: step1=%g, step2=%g, delta=%g\n",(double)step1,(double)step2,(double)pcgP->delta);CHKERRQ(ierr); } } else { /* Evaluate the current step */ ierr = VecCopy(X,W);CHKERRQ(ierr); /* update interior iterate */ ierr = VecAXPY(R,-step,ASP);CHKERRQ(ierr); /* r <- -step*asp + r */ ierr = VecNorm(R,NORM_2,&rnrm);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->rnorm = rnrm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rnrm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,i+1,rnrm);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i+1,rnrm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) { /* convergence for */ ierr = PetscInfo3(ksp,"truncated step: step=%g, rnrm=%g, delta=%g\n",(double)PetscRealPart(step),(double)rnrm,(double)pcgP->delta);CHKERRQ(ierr); } } } if (ksp->reason) break; /* Convergence has been attained */ else { /* Compute a new AS-orthogonal direction */ ierr = VecDot(R,R,&rntrn);CHKERRQ(ierr); beta = rntrn/rtr; ierr = VecAYPX(P,beta,R);CHKERRQ(ierr); /* p <- r + beta*p */ rtr = PetscRealPart(rntrn); } } if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS; /* Unscale x */ ierr = VecCopy(X,WA2);CHKERRQ(ierr); ierr = PCApplySymmetricRight(pc,WA2,X);CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,X,WA);CHKERRQ(ierr); ierr = VecDotRealPart(B,X,&btx);CHKERRQ(ierr); ierr = VecDotRealPart(X,WA,&xtax);CHKERRQ(ierr); pcgP->quadratic = btx + .5*xtax; PetscFunctionReturn(0); }
static PetscErrorCode KSPSolve_LSQR(KSP ksp) { PetscErrorCode ierr; PetscInt i,size1,size2; PetscScalar rho,rhobar,phi,phibar,theta,c,s,tmp,tau; PetscReal beta,alpha,rnorm; Vec X,B,V,V1,U,U1,TMP,W,W2,SE,Z = NULL; Mat Amat,Pmat; MatStructure pflag; KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data; PetscBool diagonalscale,nopreconditioner; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),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 = PetscObjectTypeCompare((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); /* mark norm of matrix with negative number to indicate it has not yet been computed */ lsqr->anorm = -1.0; /* 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_COMM_SELF,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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its = 0; ksp->rnorm = rnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rnorm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,0,rnorm);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,0,rnorm,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) PetscFunctionReturn(0); beta = rnorm; 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 = VecDotRealPart(V,Z,&alpha);CHKERRQ(ierr); if (alpha <= 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; PetscFunctionReturn(0); } alpha = PetscSqrtReal(alpha); 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); } lsqr->arnorm = alpha * beta; phibar = beta; rhobar = alpha; 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 = VecDotRealPart(V1,Z,&alpha);CHKERRQ(ierr); if (alpha <= 0.0) { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } alpha = PetscSqrtReal(alpha); 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = rnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,rnorm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,i+1,rnorm);CHKERRQ(ierr); 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 = VecSqrtAbs(SE);CHKERRQ(ierr); ierr = VecScale(SE,tmp);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; ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); /* 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) { ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res_norm);CHKERRQ(ierr); } fgmres->it = (loc_it - 1); /* 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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = res_norm; ierr = PetscObjectSAWsGrantAccess((PetscObject)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) { if (ksp->errorifnotconverged) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_NOT_CONVERGED,"You reached the happy break down, but convergence was not indicated. Residual norm = %G",res_norm); else { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } } } } /* END OF ITERATION LOOP */ ierr = KSPLogResidualHistory(ksp,res_norm);CHKERRQ(ierr); /* Monitor if we know that we will not return for a restart */ if (loc_it && (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 KSPPGMRESCycle(PetscInt *itcount,KSP ksp) { KSP_PGMRES *pgmres = (KSP_PGMRES*)(ksp->data); PetscReal res_norm,res,newnorm; PetscErrorCode ierr; PetscInt it = 0,j,k; PetscBool hapend = PETSC_FALSE; PetscFunctionBegin; if (itcount) *itcount = 0; ierr = VecNormalize(VEC_VV(0),&res_norm);CHKERRQ(ierr); KSPCheckNorm(ksp,res_norm); res = res_norm; *RS(0) = res_norm; /* check for the convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->rnorm = res; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); pgmres->it = it-2; ierr = KSPLogResidualHistory(ksp,res);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res);CHKERRQ(ierr); if (!res) { ksp->reason = KSP_CONVERGED_ATOL; ierr = PetscInfo(ksp,"Converged due to zero residual norm on entry\n");CHKERRQ(ierr); PetscFunctionReturn(0); } ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); for (; !ksp->reason; it++) { Vec Zcur,Znext; if (pgmres->vv_allocated <= it + VEC_OFFSET + 1) { ierr = KSPGMRESGetNewVectors(ksp,it+1);CHKERRQ(ierr); } /* VEC_VV(it-1) is orthogonal, it will be normalized once the VecNorm arrives. */ Zcur = VEC_VV(it); /* Zcur is not yet orthogonal, but the VecMDot to orthogonalize it has been started. */ Znext = VEC_VV(it+1); /* This iteration will compute Znext, update with a deferred correction once we know how * Zcur relates to the previous vectors, and start the reduction to orthogonalize it. */ if (it < pgmres->max_k+1 && ksp->its+1 < PetscMax(2,ksp->max_it)) { /* We don't know whether what we have computed is enough, so apply the matrix. */ ierr = KSP_PCApplyBAorAB(ksp,Zcur,Znext,VEC_TEMP_MATOP);CHKERRQ(ierr); } if (it > 1) { /* Complete the pending reduction */ ierr = VecNormEnd(VEC_VV(it-1),NORM_2,&newnorm);CHKERRQ(ierr); *HH(it-1,it-2) = newnorm; } if (it > 0) { /* Finish the reduction computing the latest column of H */ ierr = VecMDotEnd(Zcur,it,&(VEC_VV(0)),HH(0,it-1));CHKERRQ(ierr); } if (it > 1) { /* normalize the base vector from two iterations ago, basis is complete up to here */ ierr = VecScale(VEC_VV(it-1),1./ *HH(it-1,it-2));CHKERRQ(ierr); ierr = KSPPGMRESUpdateHessenberg(ksp,it-2,&hapend,&res);CHKERRQ(ierr); pgmres->it = it-2; ksp->its++; ksp->rnorm = res; ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (it < pgmres->max_k+1 || ksp->reason || ksp->its == ksp->max_it) { /* Monitor if we are done or still iterating, but not before a restart. */ ierr = KSPLogResidualHistory(ksp,res);CHKERRQ(ierr); ierr = KSPMonitor(ksp,ksp->its,res);CHKERRQ(ierr); } if (ksp->reason) break; /* Catch error in happy breakdown and signal convergence and break from loop */ if (hapend) { if (ksp->errorifnotconverged) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_NOT_CONVERGED,"You reached the happy break down, but convergence was not indicated. Residual norm = %g",(double)res); else { ksp->reason = KSP_DIVERGED_BREAKDOWN; break; } } if (!(it < pgmres->max_k+1 && ksp->its < ksp->max_it)) break; /* The it-2 column of H was not scaled when we computed Zcur, apply correction */ ierr = VecScale(Zcur,1./ *HH(it-1,it-2));CHKERRQ(ierr); /* And Znext computed in this iteration was computed using the under-scaled Zcur */ ierr = VecScale(Znext,1./ *HH(it-1,it-2));CHKERRQ(ierr); /* In the previous iteration, we projected an unnormalized Zcur against the Krylov basis, so we need to fix the column of H resulting from that projection. */ for (k=0; k<it; k++) *HH(k,it-1) /= *HH(it-1,it-2); /* When Zcur was projected against the Krylov basis, VV(it-1) was still not normalized, so fix that too. This * column is complete except for HH(it,it-1) which we won't know until the next iteration. */ *HH(it-1,it-1) /= *HH(it-1,it-2); } if (it > 0) { PetscScalar *work; if (!pgmres->orthogwork) {ierr = PetscMalloc1(pgmres->max_k + 2,&pgmres->orthogwork);CHKERRQ(ierr);} work = pgmres->orthogwork; /* Apply correction computed by the VecMDot in the last iteration to Znext. The original form is * * Znext -= sum_{j=0}^{i-1} Z[j+1] * H[j,i-1] * * where * * Z[j] = sum_{k=0}^j V[k] * H[k,j-1] * * substituting * * Znext -= sum_{j=0}^{i-1} sum_{k=0}^{j+1} V[k] * H[k,j] * H[j,i-1] * * rearranging the iteration space from row-column to column-row * * Znext -= sum_{k=0}^i sum_{j=k-1}^{i-1} V[k] * H[k,j] * H[j,i-1] * * Note that column it-1 of HH is correct. For all previous columns, we must look at HES because HH has already * been transformed to upper triangular form. */ for (k=0; k<it+1; k++) { work[k] = 0; for (j=PetscMax(0,k-1); j<it-1; j++) work[k] -= *HES(k,j) * *HH(j,it-1); } ierr = VecMAXPY(Znext,it+1,work,&VEC_VV(0));CHKERRQ(ierr); ierr = VecAXPY(Znext,-*HH(it-1,it-1),Zcur);CHKERRQ(ierr); /* Orthogonalize Zcur against existing basis vectors. */ for (k=0; k<it; k++) work[k] = -*HH(k,it-1); ierr = VecMAXPY(Zcur,it,work,&VEC_VV(0));CHKERRQ(ierr); /* Zcur is now orthogonal, and will be referred to as VEC_VV(it) again, though it is still not normalized. */ /* Begin computing the norm of the new vector, will be normalized after the MatMult in the next iteration. */ ierr = VecNormBegin(VEC_VV(it),NORM_2,&newnorm);CHKERRQ(ierr); } /* Compute column of H (to the diagonal, but not the subdiagonal) to be able to orthogonalize the newest vector. */ ierr = VecMDotBegin(Znext,it+1,&VEC_VV(0),HH(0,it));CHKERRQ(ierr); /* Start an asynchronous split-mode reduction, the result of the MDot and Norm will be collected on the next iteration. */ ierr = PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)Znext));CHKERRQ(ierr); } if (itcount) *itcount = it-1; /* Number of iterations actually completed. */ /* 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) */ ierr = KSPPGMRESBuildSoln(RS(0),ksp->vec_sol,ksp->vec_sol,ksp,it-2);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_NRichardson(SNES snes) { Vec X, Y, F; PetscReal xnorm, fnorm, ynorm; PetscInt maxits, i; PetscErrorCode ierr; SNESLineSearchReason lsresult; SNESConvergedReason reason; PetscFunctionBegin; if (snes->xl || snes->xu || snes->ops->computevariablebounds) { SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name); } 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 = PetscObjectSAWsTakeAccess((PetscObject)snes); CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes); CHKERRQ(ierr); if (snes->pc && snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,F); 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 = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); } else { if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); } else snes->vec_func_init_set = PETSC_FALSE; ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); SNESCheckFunctionNorm(snes,fnorm); } if (snes->pc && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) { ierr = SNESApplyNPC(snes,X,F,Y); CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason); CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } } else { ierr = VecCopy(F,Y); CHKERRQ(ierr); } ierr = PetscObjectSAWsTakeAccess((PetscObject)snes); CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes); CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,fnorm,0); CHKERRQ(ierr); ierr = SNESMonitor(snes,0,fnorm); CHKERRQ(ierr); /* 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); } /* 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 = 1; i < maxits+1; i++) { ierr = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y); CHKERRQ(ierr); ierr = SNESLineSearchGetReason(snes->linesearch, &lsresult); CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm); CHKERRQ(ierr); if (lsresult) { if (++snes->numFailures >= snes->maxFailures) { snes->reason = SNES_DIVERGED_LINE_SEARCH; break; } } if (snes->nfuncs >= snes->max_funcs) { snes->reason = SNES_DIVERGED_FUNCTION_COUNT; break; } /* Monitor convergence */ ierr = PetscObjectSAWsTakeAccess((PetscObject)snes); CHKERRQ(ierr); snes->iter = i; snes->norm = fnorm; ierr = PetscObjectSAWsGrantAccess((PetscObject)snes); CHKERRQ(ierr); ierr = SNESLogConvergenceHistory(snes,snes->norm,0); CHKERRQ(ierr); 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; /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter); CHKERRQ(ierr); } if (snes->pc) { if (snes->functype == SNES_FUNCTION_PRECONDITIONED) { ierr = SNESApplyNPC(snes,X,NULL,Y); CHKERRQ(ierr); ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); ierr = VecCopy(Y,F); CHKERRQ(ierr); } else { ierr = SNESApplyNPC(snes,X,F,Y); CHKERRQ(ierr); } ierr = SNESGetConvergedReason(snes->pc,&reason); CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } } else { ierr = VecCopy(F,Y); CHKERRQ(ierr); } } if (i == maxits+1) { 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 = PetscSqrtReal(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; ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ierr = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); 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 (PetscRealPart(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 = PetscSqrtReal(PetscAbsScalar(btop)); /* dp = sqrt(R,AR) */ } else if (ksp->normtype == KSP_NORM_NONE) { 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(PetscObjectComm((PetscObject)ksp),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 = PetscObjectSAWsTakeAccess((PetscObject)ksp);CHKERRQ(ierr); ksp->its++; ksp->rnorm = dp; ierr = PetscObjectSAWsGrantAccess((PetscObject)ksp);CHKERRQ(ierr); ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); 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; 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); }