PetscErrorCode SetInitialGuess(Vec X,Userctx *user) { PetscErrorCode ierr; Vec Xgen,Xnet; PetscScalar *xgen,*xnet; PetscInt i,idx=0; PetscScalar Vr,Vi,IGr,IGi,Vm,Vm2; PetscScalar Eqp,Edp,delta; PetscScalar Efd,RF,VR; /* Exciter variables */ PetscScalar Id,Iq; /* Generator dq axis currents */ PetscScalar theta,Vd,Vq,SE; PetscFunctionBegin; M[0] = 2*H[0]/w_s; M[1] = 2*H[1]/w_s; M[2] = 2*H[2]/w_s; D[0] = 0.1*M[0]; D[1] = 0.1*M[1]; D[2] = 0.1*M[2]; ierr = DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet);CHKERRQ(ierr); /* Network subsystem initialization */ ierr = VecCopy(user->V0,Xnet);CHKERRQ(ierr); /* Generator subsystem initialization */ ierr = VecGetArray(Xgen,&xgen);CHKERRQ(ierr); ierr = VecGetArray(Xnet,&xnet);CHKERRQ(ierr); for (i=0; i < ngen; i++) { Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm; IGr = (Vr*PG[i] + Vi*QG[i])/Vm2; IGi = (Vi*PG[i] - Vr*QG[i])/Vm2; delta = atan2(Vi+Xq[i]*IGr,Vr-Xq[i]*IGi); /* Machine angle */ theta = PETSC_PI/2.0 - delta; Id = IGr*PetscCosScalar(theta) - IGi*PetscSinScalar(theta); /* d-axis stator current */ Iq = IGr*PetscSinScalar(theta) + IGi*PetscCosScalar(theta); /* q-axis stator current */ Vd = Vr*PetscCosScalar(theta) - Vi*PetscSinScalar(theta); Vq = Vr*PetscSinScalar(theta) + Vi*PetscCosScalar(theta); Edp = Vd + Rs[i]*Id - Xqp[i]*Iq; /* d-axis transient EMF */ Eqp = Vq + Rs[i]*Iq + Xdp[i]*Id; /* q-axis transient EMF */ TM[i] = PG[i]; /* The generator variables are ordered as [Eqp,Edp,delta,w,Id,Iq] */ xgen[idx] = Eqp; xgen[idx+1] = Edp; xgen[idx+2] = delta; xgen[idx+3] = w_s; idx = idx + 4; xgen[idx] = Id; xgen[idx+1] = Iq; idx = idx + 2; /* Exciter */ Efd = Eqp + (Xd[i] - Xdp[i])*Id; SE = k1[i]*PetscExpScalar(k2[i]*Efd); VR = KE[i]*Efd + SE; RF = KF[i]*Efd/TF[i]; xgen[idx] = Efd; xgen[idx+1] = RF; xgen[idx+2] = VR; Vref[i] = Vm + (VR/KA[i]); idx = idx + 3; } ierr = VecRestoreArray(Xgen,&xgen);CHKERRQ(ierr); ierr = VecRestoreArray(Xnet,&xnet);CHKERRQ(ierr); /* ierr = VecView(Xgen,0);CHKERRQ(ierr); */ ierr = DMCompositeGather(user->dmpgrid,X,INSERT_VALUES,Xgen,Xnet);CHKERRQ(ierr); ierr = DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D) { PetscErrorCode ierr; SNES_QN *qn = (SNES_QN*)snes->data; Vec W = snes->work[3]; Vec *U = qn->U; PetscInt m = qn->m; PetscInt k,i,j,lits,l = m; PetscReal unorm,a,b; PetscReal *lambda=qn->lambda; PetscScalar gdot; PetscReal udot; PetscFunctionBegin; if (it < m) l = it; if (it > 0) { k = (it-1)%l; ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr); ierr = VecCopy(Xold,U[k]);CHKERRQ(ierr); ierr = VecAXPY(U[k],-1.0,X);CHKERRQ(ierr); if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } } if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr); SNESCheckKSPSolve(snes); ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = VecCopy(W,Y);CHKERRQ(ierr); } else { ierr = VecCopy(D,Y);CHKERRQ(ierr); ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr); } /* inward recursion starting at the first update and working forward */ for (i = 0; i < l-1; i++) { j = (it+i-l)%l; k = (it+i-l+1)%l; ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr); ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr); unorm *= unorm; udot = PetscRealPart(gdot); a = (lambda[j]/lambda[k]); b = -(1.-lambda[j]); a *= udot/unorm; b *= udot/unorm; ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr); if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,PetscRealPart(gdot));CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } } if (l > 0) { k = (it-1)%l; ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr); ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr); unorm *= unorm; udot = PetscRealPart(gdot); a = unorm/(unorm-lambda[k]*udot); b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot); if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: a: %14.12e b: %14.12e \n",k,a,b);CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr); } l = m; if (it+1<m)l=it+1; k = it%l; if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } PetscFunctionReturn(0); }
PetscErrorCode SNESSolve_NEWTONLS(SNES snes) { PetscErrorCode ierr; PetscInt maxits,i,lits; PetscBool lssucceed; MatStructure flg = DIFFERENT_NONZERO_PATTERN; PetscReal fnorm,gnorm,xnorm,ynorm; Vec Y,X,F,G,W,FPC; KSPConvergedReason kspreason; PetscBool domainerror; SNESLineSearch linesearch; SNESConvergedReason reason; PetscFunctionBegin; snes->numFailures = 0; snes->numLinearSolveFailures = 0; snes->reason = SNES_CONVERGED_ITERATING; maxits = snes->max_its; /* maximum number of iterations */ X = snes->vec_sol; /* solution vector */ F = snes->vec_func; /* residual vector */ Y = snes->vec_sol_update; /* newton step */ G = snes->work[0]; W = snes->work[1]; ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = 0; snes->norm = 0.0; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); ierr = SNESGetSNESLineSearch(snes, &linesearch);CHKERRQ(ierr); if (!snes->vec_func_init_set) { ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } } else { snes->vec_func_init_set = PETSC_FALSE; } if (!snes->norm_init_set) { ierr = VecNormBegin(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ ierr = VecNormEnd(F,NORM_2,&fnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); } else { fnorm = snes->norm_init; snes->norm_init_set = PETSC_FALSE; } ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,fnorm,0); ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); /* set parameter for default relative tolerance convergence test */ snes->ttol = fnorm*snes->rtol; /* test convergence */ ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) PetscFunctionReturn(0); for (i=0; i<maxits; i++) { /* Call general purpose update function */ if (snes->ops->update) { ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); } /* apply the nonlinear preconditioner if it's right preconditioned */ if (snes->pc && snes->pcside == PC_RIGHT) { ierr = SNESSetInitialFunction(snes->pc, F);CHKERRQ(ierr); ierr = SNESSetInitialFunctionNorm(snes->pc, fnorm);CHKERRQ(ierr); ierr = SNESSolve(snes->pc, snes->vec_rhs, X);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr); if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) { snes->reason = SNES_DIVERGED_INNER; PetscFunctionReturn(0); } ierr = SNESGetFunction(snes->pc, &FPC, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); ierr = VecCopy(FPC, F);CHKERRQ(ierr); ierr = SNESGetFunctionNorm(snes->pc, &fnorm);CHKERRQ(ierr); } /* Solve J Y = F, where J is Jacobian matrix */ ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr); ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); if (kspreason < 0) { if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); snes->reason = SNES_DIVERGED_LINEAR_SOLVE; break; } } ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); if (PetscLogPrintInfo){ ierr = SNESNEWTONLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); } /* Compute a (scaled) negative update in the line search routine: X <- X - lambda*Y and evaluate F = function(X) (depends on the line search). */ gnorm = fnorm; ierr = SNESLineSearchApply(linesearch, X, F, &fnorm, Y);CHKERRQ(ierr); ierr = SNESLineSearchGetSuccess(linesearch, &lssucceed);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr); ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)gnorm,(double)fnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; PetscFunctionReturn(0); } if (!lssucceed) { if (snes->stol*xnorm > ynorm) { snes->reason = SNES_CONVERGED_SNORM_RELATIVE; PetscFunctionReturn(0); } if (++snes->numFailures >= snes->maxFailures) { PetscBool ismin; snes->reason = SNES_DIVERGED_LINE_SEARCH; ierr = SNESNEWTONLSCheckLocalMin_Private(snes,snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; break; } } /* Monitor convergence */ ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); snes->iter = i+1; snes->norm = fnorm; ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); SNESLogConvHistory(snes,snes->norm,lits); ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); /* Test for convergence */ ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); if (snes->reason) break; } if (i == maxits) { ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; } PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_NASH(KSP ksp) { #if defined(PETSC_USE_COMPLEX) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP, "NASH is not available for complex systems"); #else KSP_NASH *cg = (KSP_NASH*)ksp->data; PetscErrorCode ierr; MatStructure pflag; Mat Qmat, Mmat; Vec r, z, p, d; PC pc; PetscReal norm_r, norm_d, norm_dp1, norm_p, dMp; PetscReal alpha, beta, kappa, rz, rzm1; PetscReal rr, r2, step; PetscInt max_cg_its; PetscBool diagonalscale; PetscFunctionBegin; /***************************************************************************/ /* Check the arguments and parameters. */ /***************************************************************************/ 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 (cg->radius < 0.0) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_OUTOFRANGE, "Input error: radius < 0"); /***************************************************************************/ /* Get the workspace vectors and initialize variables */ /***************************************************************************/ r2 = cg->radius * cg->radius; r = ksp->work[0]; z = ksp->work[1]; p = ksp->work[2]; d = ksp->vec_sol; pc = ksp->pc; ierr = PCGetOperators(pc, &Qmat, &Mmat, &pflag); CHKERRQ(ierr); ierr = VecGetSize(d, &max_cg_its); CHKERRQ(ierr); max_cg_its = PetscMin(max_cg_its, ksp->max_it); ksp->its = 0; /***************************************************************************/ /* Initialize objective function and direction. */ /***************************************************************************/ cg->o_fcn = 0.0; ierr = VecSet(d, 0.0); CHKERRQ(ierr); /* d = 0 */ cg->norm_d = 0.0; /***************************************************************************/ /* Begin the conjugate gradient method. Check the right-hand side for */ /* numerical problems. The check for not-a-number and infinite values */ /* need be performed only once. */ /***************************************************************************/ ierr = VecCopy(ksp->vec_rhs, r); CHKERRQ(ierr); /* r = -grad */ ierr = VecDot(r, r, &rr); CHKERRQ(ierr); /* rr = r^T r */ if (PetscIsInfOrNanScalar(rr)) { /*************************************************************************/ /* The right-hand side contains not-a-number or an infinite value. */ /* The gradient step does not work; return a zero value for the step. */ /*************************************************************************/ ksp->reason = KSP_DIVERGED_NANORINF; ierr = PetscInfo1(ksp, "KSPSolve_NASH: bad right-hand side: rr=%g\n", rr); CHKERRQ(ierr); PetscFunctionReturn(0); } /***************************************************************************/ /* Check the preconditioner for numerical problems and for positive */ /* definiteness. The check for not-a-number and infinite values need be */ /* performed only once. */ /***************************************************************************/ ierr = KSP_PCApply(ksp, r, z); CHKERRQ(ierr); /* z = inv(M) r */ ierr = VecDot(r, z, &rz); CHKERRQ(ierr); /* rz = r^T inv(M) r */ if (PetscIsInfOrNanScalar(rz)) { /*************************************************************************/ /* The preconditioner contains not-a-number or an infinite value. */ /* Return the gradient direction intersected with the trust region. */ /*************************************************************************/ ksp->reason = KSP_DIVERGED_NANORINF; ierr = PetscInfo1(ksp, "KSPSolve_NASH: bad preconditioner: rz=%g\n", rz); CHKERRQ(ierr); if (cg->radius) { if (r2 >= rr) { alpha = 1.0; cg->norm_d = PetscSqrtReal(rr); } else { alpha = PetscSqrtReal(r2 / rr); cg->norm_d = cg->radius; } ierr = VecAXPY(d, alpha, r); CHKERRQ(ierr); /* d = d + alpha r */ /***********************************************************************/ /* Compute objective function. */ /***********************************************************************/ ierr = KSP_MatMult(ksp, Qmat, d, z); CHKERRQ(ierr); ierr = VecAYPX(z, -0.5, ksp->vec_rhs); CHKERRQ(ierr); ierr = VecDot(d, z, &cg->o_fcn); CHKERRQ(ierr); cg->o_fcn = -cg->o_fcn; ++ksp->its; } PetscFunctionReturn(0); } if (rz < 0.0) { /*************************************************************************/ /* The preconditioner is indefinite. Because this is the first */ /* and we do not have a direction yet, we use the gradient step. Note */ /* that we cannot use the preconditioned norm when computing the step */ /* because the matrix is indefinite. */ /*************************************************************************/ ksp->reason = KSP_DIVERGED_INDEFINITE_PC; ierr = PetscInfo1(ksp, "KSPSolve_NASH: indefinite preconditioner: rz=%g\n", rz); CHKERRQ(ierr); if (cg->radius) { if (r2 >= rr) { alpha = 1.0; cg->norm_d = PetscSqrtReal(rr); } else { alpha = PetscSqrtReal(r2 / rr); cg->norm_d = cg->radius; } ierr = VecAXPY(d, alpha, r); CHKERRQ(ierr); /* d = d + alpha r */ /***********************************************************************/ /* Compute objective function. */ /***********************************************************************/ ierr = KSP_MatMult(ksp, Qmat, d, z); CHKERRQ(ierr); ierr = VecAYPX(z, -0.5, ksp->vec_rhs); CHKERRQ(ierr); ierr = VecDot(d, z, &cg->o_fcn); CHKERRQ(ierr); cg->o_fcn = -cg->o_fcn; ++ksp->its; } PetscFunctionReturn(0); } /***************************************************************************/ /* As far as we know, the preconditioner is positive semidefinite. */ /* Compute and log the residual. Check convergence because this */ /* initializes things, but do not terminate until at least one conjugate */ /* gradient iteration has been performed. */ /***************************************************************************/ switch (ksp->normtype) { case KSP_NORM_PRECONDITIONED: ierr = VecNorm(z, NORM_2, &norm_r); CHKERRQ(ierr); /* norm_r = |z| */ break; case KSP_NORM_UNPRECONDITIONED: norm_r = PetscSqrtReal(rr); /* norm_r = |r| */ break; case KSP_NORM_NATURAL: norm_r = PetscSqrtReal(rz); /* norm_r = |r|_M */ break; default: norm_r = 0.0; break; } ierr = KSPLogResidualHistory(ksp, norm_r); CHKERRQ(ierr); ierr = KSPMonitor(ksp, ksp->its, norm_r); CHKERRQ(ierr); ksp->rnorm = norm_r; ierr = (*ksp->converged)(ksp, ksp->its, norm_r, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); /***************************************************************************/ /* Compute the first direction and update the iteration. */ /***************************************************************************/ ierr = VecCopy(z, p); CHKERRQ(ierr); /* p = z */ ierr = KSP_MatMult(ksp, Qmat, p, z); CHKERRQ(ierr); /* z = Q * p */ ++ksp->its; /***************************************************************************/ /* Check the matrix for numerical problems. */ /***************************************************************************/ ierr = VecDot(p, z, &kappa); CHKERRQ(ierr); /* kappa = p^T Q p */ if (PetscIsInfOrNanScalar(kappa)) { /*************************************************************************/ /* The matrix produced not-a-number or an infinite value. In this case, */ /* we must stop and use the gradient direction. This condition need */ /* only be checked once. */ /*************************************************************************/ ksp->reason = KSP_DIVERGED_NANORINF; ierr = PetscInfo1(ksp, "KSPSolve_NASH: bad matrix: kappa=%g\n", kappa); CHKERRQ(ierr); if (cg->radius) { if (r2 >= rr) { alpha = 1.0; cg->norm_d = PetscSqrtReal(rr); } else { alpha = PetscSqrtReal(r2 / rr); cg->norm_d = cg->radius; } ierr = VecAXPY(d, alpha, r); CHKERRQ(ierr); /* d = d + alpha r */ /***********************************************************************/ /* Compute objective function. */ /***********************************************************************/ ierr = KSP_MatMult(ksp, Qmat, d, z); CHKERRQ(ierr); ierr = VecAYPX(z, -0.5, ksp->vec_rhs); CHKERRQ(ierr); ierr = VecDot(d, z, &cg->o_fcn); CHKERRQ(ierr); cg->o_fcn = -cg->o_fcn; ++ksp->its; } PetscFunctionReturn(0); } /***************************************************************************/ /* Initialize variables for calculating the norm of the direction. */ /***************************************************************************/ dMp = 0.0; norm_d = 0.0; switch (cg->dtype) { case NASH_PRECONDITIONED_DIRECTION: norm_p = rz; break; default: ierr = VecDot(p, p, &norm_p); CHKERRQ(ierr); break; } /***************************************************************************/ /* Check for negative curvature. */ /***************************************************************************/ if (kappa <= 0.0) { /*************************************************************************/ /* In this case, the matrix is indefinite and we have encountered a */ /* direction of negative curvature. Because negative curvature occurs */ /* during the first step, we must follow a direction. */ /*************************************************************************/ ksp->reason = KSP_CONVERGED_CG_NEG_CURVE; ierr = PetscInfo1(ksp, "KSPSolve_NASH: negative curvature: kappa=%g\n", kappa); CHKERRQ(ierr); if (cg->radius && norm_p > 0.0) { /***********************************************************************/ /* Follow direction of negative curvature to the boundary of the */ /* trust region. */ /***********************************************************************/ step = PetscSqrtReal(r2 / norm_p); cg->norm_d = cg->radius; ierr = VecAXPY(d, step, p); CHKERRQ(ierr); /* d = d + step p */ /***********************************************************************/ /* Update objective function. */ /***********************************************************************/ cg->o_fcn += step * (0.5 * step * kappa - rz); } else if (cg->radius) { /***********************************************************************/ /* The norm of the preconditioned direction is zero; use the gradient */ /* step. */ /***********************************************************************/ if (r2 >= rr) { alpha = 1.0; cg->norm_d = PetscSqrtReal(rr); } else { alpha = PetscSqrtReal(r2 / rr); cg->norm_d = cg->radius; } ierr = VecAXPY(d, alpha, r); CHKERRQ(ierr); /* d = d + alpha r */ /***********************************************************************/ /* Compute objective function. */ /***********************************************************************/ ierr = KSP_MatMult(ksp, Qmat, d, z); CHKERRQ(ierr); ierr = VecAYPX(z, -0.5, ksp->vec_rhs); CHKERRQ(ierr); ierr = VecDot(d, z, &cg->o_fcn); CHKERRQ(ierr); cg->o_fcn = -cg->o_fcn; ++ksp->its; } PetscFunctionReturn(0); } /***************************************************************************/ /* Run the conjugate gradient method until either the problem is solved, */ /* we encounter the boundary of the trust region, or the conjugate */ /* gradient method breaks down. */ /***************************************************************************/ while (1) { /*************************************************************************/ /* Know that kappa is nonzero, because we have not broken down, so we */ /* can compute the steplength. */ /*************************************************************************/ alpha = rz / kappa; /*************************************************************************/ /* Compute the steplength and check for intersection with the trust */ /* region. */ /*************************************************************************/ norm_dp1 = norm_d + alpha*(2.0*dMp + alpha*norm_p); if (cg->radius && norm_dp1 >= r2) { /***********************************************************************/ /* In this case, the matrix is positive definite as far as we know. */ /* However, the full step goes beyond the trust region. */ /***********************************************************************/ ksp->reason = KSP_CONVERGED_CG_CONSTRAINED; ierr = PetscInfo1(ksp, "KSPSolve_NASH: constrained step: radius=%g\n", cg->radius); CHKERRQ(ierr); if (norm_p > 0.0) { /*********************************************************************/ /* Follow the direction to the boundary of the trust region. */ /*********************************************************************/ step = (PetscSqrtReal(dMp*dMp+norm_p*(r2-norm_d))-dMp)/norm_p; cg->norm_d = cg->radius; ierr = VecAXPY(d, step, p); CHKERRQ(ierr); /* d = d + step p */ /*********************************************************************/ /* Update objective function. */ /*********************************************************************/ cg->o_fcn += step * (0.5 * step * kappa - rz); } else { /*********************************************************************/ /* The norm of the direction is zero; there is nothing to follow. */ /*********************************************************************/ } break; } /*************************************************************************/ /* Now we can update the direction and residual. */ /*************************************************************************/ ierr = VecAXPY(d, alpha, p); CHKERRQ(ierr); /* d = d + alpha p */ ierr = VecAXPY(r, -alpha, z); CHKERRQ(ierr); /* r = r - alpha Q p */ ierr = KSP_PCApply(ksp, r, z); CHKERRQ(ierr); /* z = inv(M) r */ switch (cg->dtype) { case NASH_PRECONDITIONED_DIRECTION: norm_d = norm_dp1; break; default: ierr = VecDot(d, d, &norm_d); CHKERRQ(ierr); break; } cg->norm_d = PetscSqrtReal(norm_d); /*************************************************************************/ /* Update objective function. */ /*************************************************************************/ cg->o_fcn -= 0.5 * alpha * rz; /*************************************************************************/ /* Check that the preconditioner appears positive semidefinite. */ /*************************************************************************/ rzm1 = rz; ierr = VecDot(r, z, &rz); CHKERRQ(ierr); /* rz = r^T z */ if (rz < 0.0) { /***********************************************************************/ /* The preconditioner is indefinite. */ /***********************************************************************/ ksp->reason = KSP_DIVERGED_INDEFINITE_PC; ierr = PetscInfo1(ksp, "KSPSolve_NASH: cg indefinite preconditioner: rz=%g\n", rz); CHKERRQ(ierr); break; } /*************************************************************************/ /* As far as we know, the preconditioner is positive semidefinite. */ /* Compute the residual and check for convergence. */ /*************************************************************************/ switch (ksp->normtype) { case KSP_NORM_PRECONDITIONED: ierr = VecNorm(z, NORM_2, &norm_r); CHKERRQ(ierr); /* norm_r = |z| */ break; case KSP_NORM_UNPRECONDITIONED: ierr = VecNorm(r, NORM_2, &norm_r); CHKERRQ(ierr); /* norm_r = |r| */ break; case KSP_NORM_NATURAL: norm_r = PetscSqrtReal(rz); /* norm_r = |r|_M */ break; default: norm_r = 0.; break; } ierr = KSPLogResidualHistory(ksp, norm_r); CHKERRQ(ierr); ierr = KSPMonitor(ksp, ksp->its, norm_r); CHKERRQ(ierr); ksp->rnorm = norm_r; ierr = (*ksp->converged)(ksp, ksp->its, norm_r, &ksp->reason, ksp->cnvP); CHKERRQ(ierr); if (ksp->reason) { /***********************************************************************/ /* The method has converged. */ /***********************************************************************/ ierr = PetscInfo2(ksp, "KSPSolve_NASH: truncated step: rnorm=%g, radius=%g\n", norm_r, cg->radius); CHKERRQ(ierr); break; } /*************************************************************************/ /* We have not converged yet. Check for breakdown. */ /*************************************************************************/ beta = rz / rzm1; if (fabs(beta) <= 0.0) { /***********************************************************************/ /* Conjugate gradients has broken down. */ /***********************************************************************/ ksp->reason = KSP_DIVERGED_BREAKDOWN; ierr = PetscInfo1(ksp, "KSPSolve_NASH: breakdown: beta=%g\n", beta); CHKERRQ(ierr); break; } /*************************************************************************/ /* Check iteration limit. */ /*************************************************************************/ if (ksp->its >= max_cg_its) { ksp->reason = KSP_DIVERGED_ITS; ierr = PetscInfo1(ksp, "KSPSolve_NASH: iterlim: its=%d\n", ksp->its); CHKERRQ(ierr); break; } /*************************************************************************/ /* Update p and the norms. */ /*************************************************************************/ ierr = VecAYPX(p, beta, z); CHKERRQ(ierr); /* p = z + beta p */ switch (cg->dtype) { case NASH_PRECONDITIONED_DIRECTION: dMp = beta*(dMp + alpha*norm_p); norm_p = beta*(rzm1 + beta*norm_p); break; default: ierr = VecDot(d, p, &dMp); CHKERRQ(ierr); ierr = VecDot(p, p, &norm_p); CHKERRQ(ierr); break; } /*************************************************************************/ /* Compute the new direction and update the iteration. */ /*************************************************************************/ ierr = KSP_MatMult(ksp, Qmat, p, z); CHKERRQ(ierr); /* z = Q * p */ ierr = VecDot(p, z, &kappa); CHKERRQ(ierr); /* kappa = p^T Q p */ ++ksp->its; /*************************************************************************/ /* Check for negative curvature. */ /*************************************************************************/ if (kappa <= 0.0) { /***********************************************************************/ /* In this case, the matrix is indefinite and we have encountered */ /* a direction of negative curvature. Stop at the base. */ /***********************************************************************/ ksp->reason = KSP_CONVERGED_CG_NEG_CURVE; ierr = PetscInfo1(ksp, "KSPSolve_NASH: negative curvature: kappa=%g\n", kappa); CHKERRQ(ierr); break; } } PetscFunctionReturn(0); #endif }
PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold) { PetscErrorCode ierr; SNES_QN *qn = (SNES_QN*)snes->data; Vec W = snes->work[3]; Vec *dX = qn->U; Vec *dF = qn->V; PetscScalar *alpha = qn->alpha; PetscScalar *beta = qn->beta; PetscScalar *dXtdF = qn->dXtdF; PetscScalar *dFtdX = qn->dFtdX; PetscScalar *YtdX = qn->YtdX; /* ksp thing for Jacobian scaling */ PetscInt k,i,j,g,lits; PetscInt m = qn->m; PetscScalar t; PetscInt l = m; PetscFunctionBegin; if (it < m) l = it; ierr = VecCopy(D,Y);CHKERRQ(ierr); if (it > 0) { k = (it - 1) % l; ierr = VecCopy(D,dF[k]);CHKERRQ(ierr); ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr); ierr = VecCopy(X, dX[k]);CHKERRQ(ierr); ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr); if (qn->singlereduction) { ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr); ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr); ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr); ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr); ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr); ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr); for (j = 0; j < l; j++) { H(k, j) = dFtdX[j]; H(j, k) = dXtdF[j]; } /* copy back over to make the computation of alpha and beta easier */ for (j = 0; j < l; j++) dXtdF[j] = H(j, j); } else { ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr); } if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) { ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr); } } /* outward recursion starting at iteration k's update and working back */ for (i=0; i<l; i++) { k = (it-i-1)%l; if (qn->singlereduction) { /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */ t = YtdX[k]; for (j=0; j<i; j++) { g = (it-j-1)%l; t -= alpha[g]*H(k, g); } alpha[k] = t/H(k,k); } else { ierr = VecDot(dX[k],Y,&t);CHKERRQ(ierr); alpha[k] = t/dXtdF[k]; } if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha: %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr); } if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) { ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr); SNESCheckKSPSolve(snes); ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); snes->linear_its += lits; ierr = VecCopy(W, Y);CHKERRQ(ierr); } else { ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr); } if (qn->singlereduction) { ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr); } /* inward recursion starting at the first update and working forward */ for (i = 0; i < l; i++) { k = (it + i - l) % l; if (qn->singlereduction) { t = YtdX[k]; for (j = 0; j < i; j++) { g = (it + j - l) % l; t += (alpha[g] - beta[g])*H(g, k); } beta[k] = t / H(k, k); } else { ierr = VecDot(dF[k], Y, &t);CHKERRQ(ierr); beta[k] = t / dXtdF[k]; } ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr); if (qn->monitor) { ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr); } } PetscFunctionReturn(0); }
int main(int argc, char **argv) { MPI_Comm comm; PetscMPIInt rank; PetscErrorCode ierr; User user; PetscLogDouble v1, v2; PetscInt nplot = 0; char fileName[2048]; ierr = PetscInitialize(&argc, &argv, (char*) 0, help);CHKERRQ(ierr); comm = PETSC_COMM_WORLD; ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = PetscNew(&user);CHKERRQ(ierr); ierr = PetscNew(&user->algebra);CHKERRQ(ierr); ierr = PetscNew(&user->model);CHKERRQ(ierr); ierr = PetscNew(&user->model->physics);CHKERRQ(ierr); Algebra algebra = user->algebra; ierr = LoadOptions(comm, user);CHKERRQ(ierr); ierr = PetscTime(&v1);CHKERRQ(ierr); ierr = CreateMesh(comm, user);CHKERRQ(ierr); ierr = PetscTime(&v2);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Read and Distribute mesh takes %f sec \n", v2 - v1);CHKERRQ(ierr); ierr = SetUpLocalSpace(user);CHKERRQ(ierr); //Set up the dofs of each element ierr = ConstructGeometryFVM(&user->facegeom, &user->cellgeom, user);CHKERRQ(ierr); ierr = LimiterSetup(user);CHKERRQ(ierr); if (user->TimeIntegralMethod == EXPLICITMETHOD) { // explicit method if(user->myownexplicitmethod){// Using the fully explicit method based on my own routing ierr = PetscPrintf(PETSC_COMM_WORLD,"Using the fully explicit method based on my own routing\n");CHKERRQ(ierr); user->current_time = user->initial_time; user->current_step = 1; ierr = DMCreateGlobalVector(user->dm, &algebra->solution);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) algebra->solution, "solution");CHKERRQ(ierr); ierr = VecSet(algebra->solution, 0);CHKERRQ(ierr); ierr = SetInitialCondition(user->dm, algebra->solution, user);CHKERRQ(ierr); if(1){ PetscViewer viewer; ierr = OutputVTK(user->dm, "intialcondition.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->solution, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Outputing the initial condition intialcondition.vtk!!! \n");CHKERRQ(ierr); } ierr = VecDuplicate(algebra->solution, &algebra->fn);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &algebra->oldsolution);CHKERRQ(ierr); if(user->Explicit_RK2||user->Explicit_RK4){ ierr = PetscPrintf(PETSC_COMM_WORLD,"Use the second order Runge Kutta method \n");CHKERRQ(ierr); }else{ ierr = PetscPrintf(PETSC_COMM_WORLD,"Use the first order forward Euler method \n");CHKERRQ(ierr); } nplot = 0; //the plot step while(user->current_time < (user->final_time - 0.05 * user->dt)){ user->current_time = user->current_time + user->dt; ierr = FormTimeStepFunction(user, algebra, algebra->solution, algebra->fn);CHKERRQ(ierr); if(0){ PetscViewer viewer; ierr = OutputVTK(user->dm, "function.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->fn, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } if(user->Explicit_RK2){ /* U^n_1 = U^n + 0.5*dt*f(U^n) U^{n+1} = U^n + dt*f(U^n_1) */ ierr = VecCopy(algebra->solution, algebra->oldsolution);CHKERRQ(ierr); //note that algebra->oldsolution and algebra->solution are both U^n ierr = VecAXPY(algebra->solution, 0.5*user->dt, algebra->fn);CHKERRQ(ierr); //U^n_1 = U^n + 0.5*dt*f(U^n), now algebra->solution is U^n_1, and algebra->fn is f(U^n) ierr = FormTimeStepFunction(user, algebra, algebra->solution, algebra->fn);CHKERRQ(ierr); //algebra->fn is f(U^n_1) // reset the algebra->solution to U^n ierr = VecCopy(algebra->oldsolution, algebra->solution);CHKERRQ(ierr); ierr = VecAXPY(algebra->solution, user->dt, algebra->fn);CHKERRQ(ierr); // now algebra->solution is U^{n+1} = U^n + dt*f(U^n_1) }else if(user->Explicit_RK4){ /* refer to https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods k_1 = f(U^n) U^n_1 = U^n + 0.5*dt*k_1 k_2 = f(U^n_1) U^n_2 = U^n + 0.5*dt*k_2 k_3 = f(U^n_2) U^n_3 = U^n + 0.5*dt*k_3 k_4 = f(U^n_3) U^{n+1} = U^n + dt/6*(k_1 + 2*k_2 + 2*k_3 + k_4) */ Vec VecTemp; // store the U^n_1 Vec k1, k2, k3, k4; ierr = VecDuplicate(algebra->solution, &k1);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &k2);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &k3);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &k4);CHKERRQ(ierr); ierr = VecCopy(algebra->solution, algebra->oldsolution);CHKERRQ(ierr); ierr = VecCopy(algebra->fn, k1);CHKERRQ(ierr); //note that algebra->oldsolution and algebra->solution are both U^n ierr = VecAXPY(algebra->solution, 0.5*user->dt, k1);CHKERRQ(ierr); //U^n_1 = U^n + 0.5*dt*k1, now algebra->solution is U^n_1, and algebra->fn is f(U^n) ierr = FormTimeStepFunction(user, algebra, algebra->solution, algebra->fn);CHKERRQ(ierr); //algebra->fn is f(U^n_1) ierr = VecCopy(algebra->fn, k2);CHKERRQ(ierr); // reset the algebra->solution to U^n ierr = VecCopy(algebra->oldsolution, algebra->solution);CHKERRQ(ierr); ierr = VecAXPY(algebra->solution, 0.5*user->dt, k2);CHKERRQ(ierr); //U^n_2 = U^n + 0.5*dt*k2, now algebra->solution is U^n_2, and algebra->fn is f(U^n_1) ierr = FormTimeStepFunction(user, algebra, algebra->solution, algebra->fn);CHKERRQ(ierr); //algebra->fn is f(U^n_2) ierr = VecCopy(algebra->fn, k3);CHKERRQ(ierr); // reset the algebra->solution to U^n ierr = VecCopy(algebra->oldsolution, algebra->solution);CHKERRQ(ierr); ierr = VecAXPY(algebra->solution, 0.5*user->dt, k3);CHKERRQ(ierr); //U^n_3 = U^n + 0.5*dt*k3, now algebra->solution is U^n_3, and algebra->fn is f(U^n_2) ierr = FormTimeStepFunction(user, algebra, algebra->solution, algebra->fn);CHKERRQ(ierr); //algebra->fn is f(U^n_3) ierr = VecCopy(algebra->fn, k4);CHKERRQ(ierr); //U^{n+1} = U^n + dt/6*(k_1 + 2*k_2 + 2*k_3 + k_4) PetscReal temp; temp = user->dt/6; // reset the algebra->solution to U^n ierr = VecCopy(algebra->oldsolution, algebra->solution);CHKERRQ(ierr); ierr = VecAXPY(algebra->solution, temp, k1);CHKERRQ(ierr); // now algebra->solution is U^n + dt/6*k_1 ierr = VecAXPY(algebra->solution, 2*temp, k2);CHKERRQ(ierr); // now algebra->solution is U^n + dt/6*k_1 + 2*dt/6*k_2 ierr = VecAXPY(algebra->solution, 2*temp, k3);CHKERRQ(ierr); // now algebra->solution is U^n + dt/6*k_1 + 2*dt/6*k_2 + 2*dt/6*k_3 ierr = VecAXPY(algebra->solution, temp, k4);CHKERRQ(ierr); // now algebra->solution is U^n + dt/6*k_1 + 2*dt/6*k_2 + 2*dt/6*k_3 + dt/6*k_4 ierr = VecDestroy(&k1);CHKERRQ(ierr); ierr = VecDestroy(&k2);CHKERRQ(ierr); ierr = VecDestroy(&k3);CHKERRQ(ierr); ierr = VecDestroy(&k4);CHKERRQ(ierr); }else{ ierr = VecCopy(algebra->solution, algebra->oldsolution);CHKERRQ(ierr); ierr = VecAXPY(algebra->solution, user->dt, algebra->fn);CHKERRQ(ierr); } {// Monitor the solution and function norms PetscReal norm; PetscLogDouble space =0; PetscInt size; PetscReal fnnorm; ierr = VecNorm(algebra->fn,NORM_2,&fnnorm);CHKERRQ(ierr); //ierr = VecView(algebra->fn, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecNorm(algebra->solution,NORM_2,&norm);CHKERRQ(ierr); ierr = VecGetSize(algebra->solution, &size);CHKERRQ(ierr); norm = norm/size; fnnorm = fnnorm/size; if (norm>1.e5) { SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_LIB, "The norm of the solution is: %f (current time: %f). The explicit method is going to DIVERGE!!!", norm, user->current_time); } if (user->current_step%10==0) { ierr = PetscPrintf(PETSC_COMM_WORLD,"Step %D at time %g with solution norm = %g and founction norm = %g \n", user->current_step, user->current_time, norm, fnnorm);CHKERRQ(ierr); } // ierr = PetscMallocGetCurrentUsage(&space);CHKERRQ(ierr); // if (user->current_step%10==0) { // ierr = PetscPrintf(PETSC_COMM_WORLD,"Current space PetscMalloc()ed %g M\n", // space/(1024*1024));CHKERRQ(ierr); // } } { // Monitor the difference of two steps' solution PetscReal norm; ierr = VecAXPY(algebra->oldsolution, -1, algebra->solution);CHKERRQ(ierr); ierr = VecNorm(algebra->oldsolution,NORM_2,&norm);CHKERRQ(ierr); if (user->current_step%10==0) { ierr = PetscPrintf(PETSC_COMM_WORLD,"Step %D at time %g with ||u_k-u_{k-1}|| = %g \n", user->current_step, user->current_time, norm);CHKERRQ(ierr); } if((norm<1.e-6)||(user->current_step > user->max_time_its)){ if(norm<1.e-6) ierr = PetscPrintf(PETSC_COMM_WORLD,"\n Convergence with ||u_k-u_{k-1}|| = %g < 1.e-6\n\n", norm);CHKERRQ(ierr); if(user->current_step > user->max_time_its) ierr = PetscPrintf(PETSC_COMM_WORLD,"\n Convergence with reaching the max time its\n\n");CHKERRQ(ierr); break; } } // output the solution if (user->output_solution && (user->current_step%user->steps_output==0)){ PetscViewer viewer; Vec solution_unscaled; // Note the the algebra->solution is scaled by the density, so this is for the unscaled solution nplot = user->current_step/user->steps_output; // update file name for the current time step ierr = VecDuplicate(algebra->solution, &solution_unscaled);CHKERRQ(ierr); ierr = ReformatSolution(algebra->solution, solution_unscaled, user);CHKERRQ(ierr); ierr = PetscSNPrintf(fileName, sizeof(fileName),"%s_%d.vtk",user->solutionfile, nplot);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Outputing solution %s (current time %f)\n", fileName, user->current_time);CHKERRQ(ierr); ierr = OutputVTK(user->dm, fileName, &viewer);CHKERRQ(ierr); ierr = VecView(solution_unscaled, viewer);CHKERRQ(ierr); ierr = VecDestroy(&solution_unscaled);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } user->current_step++; } ierr = VecDestroy(&algebra->fn);CHKERRQ(ierr); }else{ // Using the fully explicit method based on the PETSC TS routing PetscReal ftime; TS ts; TSConvergedReason reason; PetscInt nsteps; //PetscReal minRadius; //ierr = DMPlexTSGetGeometry(user->dm, NULL, NULL, &minRadius);CHKERRQ(ierr); //user->dt = 0.9*4 * minRadius / 1.0; ierr = PetscPrintf(PETSC_COMM_WORLD,"Using the fully explicit method based on the PETSC TS routing\n");CHKERRQ(ierr); ierr = DMCreateGlobalVector(user->dm, &algebra->solution);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) algebra->solution, "solution");CHKERRQ(ierr); ierr = VecSet(algebra->solution, 0.0);CHKERRQ(ierr); ierr = SetInitialCondition(user->dm, algebra->solution, user);CHKERRQ(ierr); ierr = TSCreate(comm, &ts);CHKERRQ(ierr); ierr = TSSetType(ts, TSEULER);CHKERRQ(ierr); ierr = TSSetDM(ts, user->dm);CHKERRQ(ierr); ierr = TSMonitorSet(ts,TSMonitorFunctionError,(void*)user,NULL);CHKERRQ(ierr); ierr = TSSetRHSFunction(ts, NULL, MyRHSFunction, user);CHKERRQ(ierr); ierr = TSSetDuration(ts, 1000, user->final_time);CHKERRQ(ierr); ierr = TSSetInitialTimeStep(ts, user->initial_time, user->dt);CHKERRQ(ierr); ierr = TSSetFromOptions(ts);CHKERRQ(ierr); ierr = TSSolve(ts, algebra->solution);CHKERRQ(ierr); ierr = TSGetSolveTime(ts, &ftime);CHKERRQ(ierr); ierr = TSGetTimeStepNumber(ts, &nsteps);CHKERRQ(ierr); ierr = TSGetConvergedReason(ts, &reason);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"%s at time %g after %D steps\n",TSConvergedReasons[reason],ftime,nsteps);CHKERRQ(ierr); ierr = TSDestroy(&ts);CHKERRQ(ierr); } if(user->benchmark_couette) { ierr = DMCreateGlobalVector(user->dm, &algebra->exactsolution);CHKERRQ(ierr); ierr = ComputeExactSolution(user->dm, user->current_time, algebra->exactsolution, user);CHKERRQ(ierr); } if(user->benchmark_couette) { PetscViewer viewer; PetscReal norm; ierr = OutputVTK(user->dm, "exact_solution.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->exactsolution, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecAXPY(algebra->exactsolution, -1, algebra->solution);CHKERRQ(ierr); ierr = VecNorm(algebra->exactsolution,NORM_INFINITY,&norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Final time at %f, Error: ||u_k-u|| = %g \n", user->current_time, norm);CHKERRQ(ierr); ierr = OutputVTK(user->dm, "Error.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->exactsolution, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } ierr = VecDestroy(&algebra->solution);CHKERRQ(ierr); if(user->myownexplicitmethod){ierr = VecDestroy(&algebra->oldsolution);CHKERRQ(ierr);} ierr = VecDestroy(&algebra->exactsolution);CHKERRQ(ierr); ierr = DMDestroy(&user->dm);CHKERRQ(ierr); } else if (user->TimeIntegralMethod == IMPLICITMETHOD) { // Using the fully implicit method ierr = PetscPrintf(PETSC_COMM_WORLD,"Using the fully implicit method\n");CHKERRQ(ierr); ierr = SNESCreate(comm,&user->snes);CHKERRQ(ierr); ierr = SNESSetDM(user->snes,user->dm);CHKERRQ(ierr); ierr = DMCreateGlobalVector(user->dm, &algebra->solution);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &algebra->oldsolution);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &algebra->f);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &algebra->fn);CHKERRQ(ierr); ierr = VecDuplicate(algebra->solution, &algebra->oldfn);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) algebra->solution, "solution");CHKERRQ(ierr); ierr = SetInitialCondition(user->dm, algebra->solution, user);CHKERRQ(ierr); ierr = DMSetMatType(user->dm, MATAIJ);CHKERRQ(ierr); // ierr = DMCreateMatrix(user->dm, &algebra->A);CHKERRQ(ierr); ierr = DMCreateMatrix(user->dm, &algebra->J);CHKERRQ(ierr); if (user->JdiffP) { /*Set up the preconditioner matrix*/ ierr = DMCreateMatrix(user->dm, &algebra->P);CHKERRQ(ierr); }else{ algebra->P = algebra->J; } ierr = MatSetOption(algebra->J, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);CHKERRQ(ierr); /*set nonlinear function */ ierr = SNESSetFunction(user->snes, algebra->f, FormFunction, (void*)user);CHKERRQ(ierr); /* compute Jacobian */ ierr = SNESSetJacobian(user->snes, algebra->J, algebra->P, FormJacobian, (void*)user);CHKERRQ(ierr); ierr = SNESSetFromOptions(user->snes);CHKERRQ(ierr); /* do the solve */ if (user->timestep == TIMESTEP_STEADY_STATE) { ierr = SolveSteadyState(user);CHKERRQ(ierr); } else { ierr = SolveTimeDependent(user);CHKERRQ(ierr); } if (user->output_solution){ PetscViewer viewer; Vec solution_unscaled; // Note the the algebra->solution is scaled by the density, so this is for the unscaled solution ierr = VecDuplicate(algebra->solution, &solution_unscaled);CHKERRQ(ierr); ierr = ReformatSolution(algebra->solution, solution_unscaled, user);CHKERRQ(ierr); ierr = OutputVTK(user->dm, "solution.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(solution_unscaled, viewer);CHKERRQ(ierr); ierr = VecDestroy(&solution_unscaled);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } if(user->benchmark_couette) { PetscViewer viewer; PetscReal norm; ierr = OutputVTK(user->dm, "exact_solution.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->exactsolution, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecAXPY(algebra->exactsolution, -1, algebra->solution);CHKERRQ(ierr); ierr = VecNorm(algebra->exactsolution,NORM_INFINITY,&norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Error: ||u_k-u|| = %g \n", norm);CHKERRQ(ierr); ierr = OutputVTK(user->dm, "Error.vtk", &viewer);CHKERRQ(ierr); ierr = VecView(algebra->exactsolution, viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } ierr = VecDestroy(&algebra->solution);CHKERRQ(ierr); ierr = VecDestroy(&algebra->f);CHKERRQ(ierr); ierr = VecDestroy(&algebra->oldsolution);CHKERRQ(ierr); ierr = VecDestroy(&algebra->fn);CHKERRQ(ierr); ierr = VecDestroy(&algebra->oldfn);CHKERRQ(ierr); ierr = SNESDestroy(&user->snes);CHKERRQ(ierr); ierr = DMDestroy(&user->dm);CHKERRQ(ierr); } else { SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"WRONG option for the time integral method. Using the option '-time_integral_method 0 or 1'"); } ierr = VecDestroy(&user->cellgeom);CHKERRQ(ierr); ierr = VecDestroy(&user->facegeom);CHKERRQ(ierr); ierr = DMDestroy(&user->dmGrad);CHKERRQ(ierr); ierr = PetscFunctionListDestroy(&LimitList);CHKERRQ(ierr); ierr = PetscFree(user->model->physics);CHKERRQ(ierr); ierr = PetscFree(user->algebra);CHKERRQ(ierr); ierr = PetscFree(user->model);CHKERRQ(ierr); ierr = PetscFree(user);CHKERRQ(ierr); { PetscLogDouble space =0; ierr = PetscMallocGetCurrentUsage(&space);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"Unfreed space at the End %g M\n", space/(1024*1024));CHKERRQ(ierr); } ierr = PetscFinalize(); return(0); }
void CellBasedPdeHandler<DIM>::SolvePdeAndWriteResultsToFile(unsigned samplingTimestepMultiple) { // Record whether we are solving PDEs on a coarse mesh bool using_coarse_pde_mesh = (mpCoarsePdeMesh != NULL); // If solving PDEs on a coarse mesh, each PDE should have an averaged source term; otherwise none should assert(!mPdeAndBcCollection.empty()); for (unsigned pde_index=0; pde_index<mPdeAndBcCollection.size(); pde_index++) { assert(mPdeAndBcCollection[pde_index]); assert(mPdeAndBcCollection[pde_index]->HasAveragedSourcePde() == using_coarse_pde_mesh || dynamic_cast<MultipleCaBasedCellPopulation<DIM>*>(mpCellPopulation)); } // Make sure the cell population is in a nice state mpCellPopulation->Update(); // Store a pointer to the (population-level or coarse) mesh TetrahedralMesh<DIM,DIM>* p_mesh; if (using_coarse_pde_mesh) { p_mesh = mpCoarsePdeMesh; } else { // If not using a coarse PDE mesh, we must be using a MeshBasedCellPopulation p_mesh = &(static_cast<MeshBasedCellPopulation<DIM>*>(mpCellPopulation)->rGetMesh()); } // Loop over elements of mPdeAndBcCollection for (unsigned pde_index=0; pde_index<mPdeAndBcCollection.size(); pde_index++) { // Get pointer to this PdeAndBoundaryConditions object PdeAndBoundaryConditions<DIM>* p_pde_and_bc = mPdeAndBcCollection[pde_index]; // Set up boundary conditions std::auto_ptr<BoundaryConditionsContainer<DIM,DIM,1> > p_bcc = ConstructBoundaryConditionsContainer(p_pde_and_bc, p_mesh); // If the solution at the previous timestep exists... PetscInt previous_solution_size = 0; if (p_pde_and_bc->GetSolution()) { VecGetSize(p_pde_and_bc->GetSolution(), &previous_solution_size); } // ...then record whether it is the correct size... bool is_previous_solution_size_correct = (previous_solution_size == (int)p_mesh->GetNumNodes()); // ...and if it is, store it as an initial guess for the PDE solver Vec initial_guess; if (is_previous_solution_size_correct) { // This Vec is copied by the solver's Solve() method, so must be deleted here too VecDuplicate(p_pde_and_bc->GetSolution(), &initial_guess); VecCopy(p_pde_and_bc->GetSolution(), initial_guess); p_pde_and_bc->DestroySolution(); } else { ///\todo enable the coarse PDE mesh to change size, e.g. for a growing domain (#630/#1891) if (!using_coarse_pde_mesh && p_pde_and_bc->GetSolution()) { assert(previous_solution_size != 0); p_pde_and_bc->DestroySolution(); } } // Create a PDE solver and solve the PDE on the (population-level or coarse) mesh if (p_pde_and_bc->HasAveragedSourcePde()) { // When using a coarse PDE mesh, we must set up the source terms before solving the PDE. // Pass in mCellPdeElementMap to speed up finding cells. this->UpdateCellPdeElementMap(); p_pde_and_bc->SetUpSourceTermsForAveragedSourcePde(p_mesh, &mCellPdeElementMap); SimpleLinearEllipticSolver<DIM,DIM> solver(p_mesh, p_pde_and_bc->GetPde(), p_bcc.get()); // If we have an initial guess, use this when solving the system... if (is_previous_solution_size_correct) { p_pde_and_bc->SetSolution(solver.Solve(initial_guess)); PetscTools::Destroy(initial_guess); } else // ...otherwise do not supply one { p_pde_and_bc->SetSolution(solver.Solve()); } } else { CellBasedPdeSolver<DIM> solver(p_mesh, p_pde_and_bc->GetPde(), p_bcc.get()); // If we have an initial guess, use this... if (is_previous_solution_size_correct) { p_pde_and_bc->SetSolution(solver.Solve(initial_guess)); PetscTools::Destroy(initial_guess); } else // ...otherwise do not supply one { p_pde_and_bc->SetSolution(solver.Solve()); } } // Store the PDE solution in an accessible form ReplicatableVector solution_repl(p_pde_and_bc->GetSolution()); // Having solved the PDE, now update CellData for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = mpCellPopulation->Begin(); cell_iter != mpCellPopulation->End(); ++cell_iter) { unsigned node_index = mpCellPopulation->GetLocationIndexUsingCell(*cell_iter); double solution_at_node = 0.0; if (using_coarse_pde_mesh) { // When using a coarse PDE mesh, the cells are not nodes of the mesh, so we must interpolate // Find the element in the coarse mesh that contains this cell. CellElementMap has been updated so use this. unsigned elem_index = mCellPdeElementMap[*cell_iter]; Element<DIM,DIM>* p_element = mpCoarsePdeMesh->GetElement(elem_index); const ChastePoint<DIM>& node_location = mpCellPopulation->GetLocationOfCellCentre(*cell_iter); c_vector<double,DIM+1> weights = p_element->CalculateInterpolationWeights(node_location); for (unsigned i=0; i<DIM+1; i++) { double nodal_value = solution_repl[p_element->GetNodeGlobalIndex(i)]; solution_at_node += nodal_value * weights(i); } } else { solution_at_node = solution_repl[node_index]; } cell_iter->GetCellData()->SetItem(mPdeAndBcCollection[pde_index]->rGetDependentVariableName(), solution_at_node); } } // Write results to file if required SimulationTime* p_time = SimulationTime::Instance(); if ((p_time->GetTimeStepsElapsed())%samplingTimestepMultiple == 0) { WritePdeSolution(p_time->GetTime()); } #define COVERAGE_IGNORE ///\todo enable this in the case where a coarse PDE mesh is used if (!using_coarse_pde_mesh) { if (mWriteDailyAverageRadialPdeSolution) { ///\todo Worry about round-off errors (#1891) p_time = SimulationTime::Instance(); unsigned num_timesteps_per_day = (unsigned) (DBL_EPSILON + 24/SimulationTime::Instance()->GetTimeStep()); if ((p_time->GetTimeStepsElapsed()) % num_timesteps_per_day == 0) { WriteAverageRadialPdeSolution(p_time->GetTime()); } } } #undef COVERAGE_IGNORE }
int main(int argc,char **argv) { Vec x1, x2, y1, y2, y3, y4; PetscViewer viewer; PetscMPIInt rank; PetscInt i, nlocal, n = 6; PetscScalar *array; PetscBool equal; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscInitialize(&argc, &argv, (char *) 0, help);CHKERRQ(ierr); ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank);CHKERRQ(ierr); ierr = PetscOptionsGetInt(PETSC_NULL, "-n", &n, PETSC_NULL);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD, &x1);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) x1, "TestVec");CHKERRQ(ierr); ierr = VecSetSizes(x1, PETSC_DECIDE, n);CHKERRQ(ierr); ierr = VecSetFromOptions(x1);CHKERRQ(ierr); ierr = VecGetLocalSize(x1, &nlocal);CHKERRQ(ierr); ierr = VecGetArray(x1, &array);CHKERRQ(ierr); for(i = 0; i < nlocal; i++) { array[i] = rank + 1; } ierr = VecRestoreArray(x1, &array);CHKERRQ(ierr); ierr = VecAssemblyBegin(x1);CHKERRQ(ierr); ierr = VecAssemblyEnd(x1);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD, &x2);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) x2, "TestVec2");CHKERRQ(ierr); ierr = VecSetSizes(x2, PETSC_DECIDE, n);CHKERRQ(ierr); ierr = VecSetBlockSize(x2, 2);CHKERRQ(ierr); ierr = VecSetFromOptions(x2);CHKERRQ(ierr); ierr = VecCopy(x1, x2);CHKERRQ(ierr); ierr = PetscViewerHDF5Open(PETSC_COMM_WORLD, "ex19.h5", FILE_MODE_WRITE, &viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/");CHKERRQ(ierr); ierr = VecView(x1, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/testBlockSize");CHKERRQ(ierr); ierr = VecView(x2, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/testTimestep");CHKERRQ(ierr); ierr = PetscViewerHDF5SetTimestep(viewer, 0);CHKERRQ(ierr); ierr = VecView(x2, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5SetTimestep(viewer, 1);CHKERRQ(ierr); ierr = VecView(x2, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD, &y1);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) y1, "TestVec");CHKERRQ(ierr); ierr = VecSetSizes(y1, PETSC_DECIDE, n);CHKERRQ(ierr); ierr = VecSetFromOptions(y1);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD,&y2);CHKERRQ(ierr); ierr = VecSetBlockSize(y2, 2);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) y2, "TestVec2");CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD,&y3);CHKERRQ(ierr); ierr = VecSetBlockSize(y3, 2);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) y3, "TestVec2");CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD,&y4);CHKERRQ(ierr); ierr = VecSetBlockSize(y4, 2);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) y4, "TestVec2");CHKERRQ(ierr); ierr = PetscViewerHDF5Open(PETSC_COMM_WORLD, "ex19.h5", FILE_MODE_READ, &viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/");CHKERRQ(ierr); ierr = VecLoad(y1, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/testBlockSize");CHKERRQ(ierr); ierr = VecLoad(y2, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PushGroup(viewer, "/testTimestep");CHKERRQ(ierr); ierr = PetscViewerHDF5SetTimestep(viewer, 0);CHKERRQ(ierr); ierr = VecLoad(y3, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5SetTimestep(viewer, 1);CHKERRQ(ierr); ierr = VecLoad(y4, viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerHDF5PopGroup(viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecEqual(x1, y1, &equal);CHKERRQ(ierr); if (!equal) { ierr = VecView(x1, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecView(y1, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Error in HDF5 viewer"); } ierr = VecEqual(x2, y2, &equal);CHKERRQ(ierr); if (!equal) { ierr = VecView(x2, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecView(y2, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Error in HDF5 viewer"); } ierr = VecDestroy(&x1);CHKERRQ(ierr); ierr = VecDestroy(&x2);CHKERRQ(ierr); ierr = VecDestroy(&y1);CHKERRQ(ierr); ierr = VecDestroy(&y2);CHKERRQ(ierr); ierr = VecDestroy(&y3);CHKERRQ(ierr); ierr = VecDestroy(&y4);CHKERRQ(ierr); ierr = PetscFinalize(); PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_GROPPCG(KSP ksp) { PetscErrorCode ierr; PetscInt i; PetscScalar alpha,beta = 0.0,gamma,gammaNew,t; PetscReal dp = 0.0; Vec x,b,r,p,s,S,z,Z; 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); x = ksp->vec_sol; b = ksp->vec_rhs; r = ksp->work[0]; p = ksp->work[1]; s = ksp->work[2]; S = ksp->work[3]; z = ksp->work[4]; Z = ksp->work[5]; ierr = PCGetOperators(ksp->pc,&Amat,&Pmat);CHKERRQ(ierr); ksp->its = 0; if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,x,r);CHKERRQ(ierr); /* r <- b - Ax */ ierr = VecAYPX(r,-1.0,b);CHKERRQ(ierr); } else { ierr = VecCopy(b,r);CHKERRQ(ierr); /* r <- b (x is 0) */ } ierr = KSP_PCApply(ksp,r,z);CHKERRQ(ierr); /* z <- Br */ ierr = VecCopy(z,p);CHKERRQ(ierr); /* p <- z */ ierr = VecDotBegin(r,z,&gamma);CHKERRQ(ierr); /* gamma <- z'*r */ ierr = PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)r));CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,p,s);CHKERRQ(ierr); /* s <- Ap */ ierr = VecDotEnd(r,z,&gamma);CHKERRQ(ierr); /* gamma <- z'*r */ switch (ksp->normtype) { case KSP_NORM_PRECONDITIONED: /* This could be merged with the computation of gamma above */ ierr = VecNorm(z,NORM_2,&dp);CHKERRQ(ierr); /* dp <- z'*z = e'*A'*B'*B*A'*e' */ break; case KSP_NORM_UNPRECONDITIONED: /* This could be merged with the computation of gamma above */ ierr = VecNorm(r,NORM_2,&dp);CHKERRQ(ierr); /* dp <- r'*r = e'*A'*A*e */ break; case KSP_NORM_NATURAL: if (PetscIsInfOrNanScalar(gamma)) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); dp = PetscSqrtReal(PetscAbsScalar(gamma)); /* dp <- r'*z = r'*B*r = e'*A'*B*A*e */ break; case KSP_NORM_NONE: dp = 0.0; break; default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]); } ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ksp->rnorm = dp; ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); /* test for convergence */ if (ksp->reason) PetscFunctionReturn(0); i = 0; do { ksp->its = i+1; i++; ierr = VecDotBegin(p,s,&t);CHKERRQ(ierr); ierr = PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)p));CHKERRQ(ierr); ierr = KSP_PCApply(ksp,s,S);CHKERRQ(ierr); /* S <- Bs */ ierr = VecDotEnd(p,s,&t);CHKERRQ(ierr); alpha = gamma / t; ierr = VecAXPY(x, alpha,p);CHKERRQ(ierr); /* x <- x + alpha * p */ ierr = VecAXPY(r,-alpha,s);CHKERRQ(ierr); /* r <- r - alpha * s */ ierr = VecAXPY(z,-alpha,S);CHKERRQ(ierr); /* z <- z - alpha * S */ if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = VecNormBegin(r,NORM_2,&dp);CHKERRQ(ierr); } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = VecNormBegin(z,NORM_2,&dp);CHKERRQ(ierr); } ierr = VecDotBegin(r,z,&gammaNew);CHKERRQ(ierr); ierr = PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)r));CHKERRQ(ierr); ierr = KSP_MatMult(ksp,Amat,z,Z);CHKERRQ(ierr); /* Z <- Az */ if (ksp->normtype == KSP_NORM_UNPRECONDITIONED) { ierr = VecNormEnd(r,NORM_2,&dp);CHKERRQ(ierr); } else if (ksp->normtype == KSP_NORM_PRECONDITIONED) { ierr = VecNormEnd(z,NORM_2,&dp);CHKERRQ(ierr); } ierr = VecDotEnd(r,z,&gammaNew);CHKERRQ(ierr); if (ksp->normtype == KSP_NORM_NATURAL) { if (PetscIsInfOrNanScalar(gammaNew)) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); dp = PetscSqrtReal(PetscAbsScalar(gammaNew)); /* dp <- r'*z = r'*B*r = e'*A'*B*A*e */ } else if (ksp->normtype == KSP_NORM_NONE) { dp = 0.0; } ksp->rnorm = dp; ierr = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr); ierr = KSPMonitor(ksp,i,dp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; beta = gammaNew / gamma; gamma = gammaNew; ierr = VecAYPX(p,beta,z);CHKERRQ(ierr); /* p <- z + beta * p */ ierr = VecAYPX(s,beta,Z);CHKERRQ(ierr); /* s <- Z + beta * s */ } while (i<ksp->max_it); if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS; PetscFunctionReturn(0); }
static PetscErrorCode KSPLGMRESBuildSoln(PetscScalar *nrs,Vec vguess,Vec vdest,KSP ksp,PetscInt it) { PetscScalar tt; PetscErrorCode ierr; PetscInt ii,k,j; KSP_LGMRES *lgmres = (KSP_LGMRES*)(ksp->data); /*LGMRES_MOD */ PetscInt it_arnoldi, it_aug; PetscInt jj, spot = 0; PetscFunctionBegin; /* Solve for solution vector that minimizes the residual */ /* If it is < 0, no lgmres steps have been performed */ if (it < 0) { ierr = VecCopy(vguess,vdest);CHKERRQ(ierr); /* VecCopy() is smart, exists immediately if vguess == vdest */ PetscFunctionReturn(0); } /* so (it+1) lgmres steps HAVE been performed */ /* LGMRES_MOD - determine if we need to use augvecs for the soln - do not assume that this is called after the total its allowed for an approx space */ if (lgmres->approx_constant) { it_arnoldi = lgmres->max_k - lgmres->aug_ct; } else { it_arnoldi = lgmres->max_k - lgmres->aug_dim; } if (it_arnoldi >= it +1) { it_aug = 0; it_arnoldi = it+1; } else { it_aug = (it + 1) - it_arnoldi; } /* now it_arnoldi indicates the number of matvecs that took place */ lgmres->matvecs += it_arnoldi; /* solve the upper triangular system - GRS is the right side and HH is the upper triangular matrix - put soln in nrs */ if (*HH(it,it) == 0.0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_CONV_FAILED,"HH(it,it) is identically zero; it = %D GRS(it) = %G",it,PetscAbsScalar(*GRS(it))); if (*HH(it,it) != 0.0) { nrs[it] = *GRS(it) / *HH(it,it); } else { nrs[it] = 0.0; } for (ii=1; ii<=it; ii++) { k = it - ii; tt = *GRS(k); for (j=k+1; j<=it; j++) tt = tt - *HH(k,j) * nrs[j]; nrs[k] = tt / *HH(k,k); } /* Accumulate the correction to the soln of the preconditioned prob. in VEC_TEMP */ ierr = VecSet(VEC_TEMP,0.0);CHKERRQ(ierr); /* set VEC_TEMP components to 0 */ /*LGMRES_MOD - if augmenting has happened we need to form the solution using the augvecs */ if (!it_aug) { /* all its are from arnoldi */ ierr = VecMAXPY(VEC_TEMP,it+1,nrs,&VEC_VV(0));CHKERRQ(ierr); } else { /*use aug vecs */ /*first do regular krylov directions */ ierr = VecMAXPY(VEC_TEMP,it_arnoldi,nrs,&VEC_VV(0));CHKERRQ(ierr); /*now add augmented portions - add contribution of aug vectors one at a time*/ for (ii=0; ii<it_aug; ii++) { for (jj=0; jj<lgmres->aug_dim; jj++) { if (lgmres->aug_order[jj] == (ii+1)) { spot = jj; break; /* must have this because there will be duplicates before aug_ct = aug_dim */ } } ierr = VecAXPY(VEC_TEMP,nrs[it_arnoldi+ii],AUGVEC(spot));CHKERRQ(ierr); } } /* now VEC_TEMP is what we want to keep for augmenting purposes - grab before the preconditioner is "unwound" from right-precondtioning*/ ierr = VecCopy(VEC_TEMP, AUG_TEMP);CHKERRQ(ierr); ierr = KSPUnwindPreconditioner(ksp,VEC_TEMP,VEC_TEMP_MATOP);CHKERRQ(ierr); /* add solution to previous solution */ /* put updated solution into vdest.*/ ierr = VecCopy(vguess,vdest);CHKERRQ(ierr); ierr = VecAXPY(vdest,1.0,VEC_TEMP);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode MatMultAdd_SeqSBSTRM_5(Mat A,Vec xx,Vec yy,Vec zz) { Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data; Mat_SeqSBSTRM *sbstrm = (Mat_SeqSBSTRM*)A->spptr; PetscScalar *x,*xb, *z; MatScalar *v1, *v2, *v3, *v4, *v5; PetscScalar x1, x2, x3, x4, x5; PetscScalar xr1, xr2, xr3, xr4, xr5; PetscScalar sum1, sum2, sum3, sum4, sum5; PetscErrorCode ierr; PetscInt mbs =a->mbs,i,*aj=a->j,*ai=a->i,n,*ib,cval,j,jmin; PetscInt nonzerorow=0; PetscInt slen; PetscFunctionBegin; ierr = VecCopy(yy,zz);CHKERRQ(ierr); ierr = VecGetArray(xx,&x);CHKERRQ(ierr); ierr = VecGetArray(zz,&z);CHKERRQ(ierr); slen = 5*(ai[mbs]-ai[0]); v1 = sbstrm->as; v2 = v1 + slen; v3 = v2 + slen; v4 = v3 + slen; v5 = v4 + slen; xb = x; for (i=0; i<mbs; i++) { n = ai[i+1] - ai[i]; x1 = xb[0]; x2 = xb[1]; x3 = xb[2]; x4 = xb[3]; x5 = xb[4]; xb += 5; sum1 = z[5*i]; sum2 = z[5*i+1]; sum3 = z[5*i+2]; sum4 = z[5*i+3]; sum5 = z[5*i+4]; nonzerorow += (n>0); jmin = 0; ib = aj + ai[i]; if (*ib == i) { /* (diag of A)*x, only upper triangular part is used */ sum1 += v1[0]*x1 + v1[1]*x2 + v1[2]*x3 + v1[3]*x4 + v1[4]*x5; sum2 += v1[1]*x1 + v2[1]*x2 + v2[2]*x3 + v2[3]*x4 + v2[4]*x5; sum3 += v1[2]*x1 + v2[2]*x2 + v3[2]*x3 + v3[3]*x4 + v3[4]*x5; sum4 += v1[3]*x1 + v2[3]*x2 + v3[3]*x3 + v4[3]*x4 + v4[4]*x5; sum5 += v1[4]*x1 + v2[4]*x2 + v3[4]*x3 + v4[4]*x4 + v5[4]*x5; v1 += 5; v2 += 5; v3 += 5; v4 += 5; v5 += 5; jmin++; } for (j=jmin; j<n; j++) { cval = ib[j]*5; z[cval] += v1[0]*x1 + v2[0]*x2 + v3[0]*x3 + v4[0]*x4 + v5[0]*x5; z[cval+1] += v1[1]*x1 + v2[1]*x2 + v3[1]*x3 + v4[1]*x4 + v5[1]*x5; z[cval+2] += v1[2]*x1 + v2[2]*x2 + v3[2]*x3 + v4[2]*x4 + v5[2]*x5; z[cval+3] += v1[3]*x1 + v2[3]*x2 + v3[3]*x3 + v4[3]*x4 + v5[3]*x5; z[cval+4] += v1[4]*x1 + v2[4]*x2 + v3[4]*x3 + v4[4]*x4 + v5[4]*x5; xr1 = x[cval]; xr2 = x[cval+1]; xr3 = x[cval+2]; xr4 = x[cval+3]; xr5 = x[cval+4]; sum1 += v1[0]*xr1 + v1[1]*xr2 + v1[2]*xr3 + v1[3]*xr4 + v1[4]*xr5; sum2 += v2[0]*xr1 + v2[1]*xr2 + v2[2]*xr3 + v2[3]*xr4 + v2[4]*xr5; sum3 += v3[0]*xr1 + v3[1]*xr2 + v3[2]*xr3 + v3[3]*xr4 + v3[4]*xr5; sum4 += v4[0]*xr1 + v4[1]*xr2 + v4[2]*xr3 + v4[3]*xr4 + v4[4]*xr5; sum5 += v5[0]*xr1 + v5[1]*xr2 + v5[2]*xr3 + v5[3]*xr4 + v5[4]*xr5; v1 += 5; v2 += 5; v3 += 5; v4 += 5; v5 += 5; } z[5*i] = sum1; z[5*i+1] = sum2; z[5*i+2] = sum3; z[5*i+3] = sum4; z[5*i+4] = sum5; } ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); ierr = VecRestoreArray(zz,&z);CHKERRQ(ierr); ierr = PetscLogFlops(50.0*(a->nz*2.0 - nonzerorow));CHKERRQ(ierr); 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); }
static PetscErrorCode SNESLineSearchApply_CP(SNESLineSearch linesearch) { PetscBool changed_y, changed_w; PetscErrorCode ierr; Vec X, Y, F, W; SNES snes; PetscReal xnorm, ynorm, gnorm, steptol, atol, rtol, ltol, maxstep; PetscReal lambda, lambda_old, lambda_update, delLambda; PetscScalar fty, fty_init, fty_old, fty_mid1, fty_mid2, s; PetscInt i, max_its; PetscViewer monitor; PetscFunctionBegin; ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, NULL);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr); ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr); ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr); ierr = SNESLineSearchGetTolerances(linesearch, &steptol, &maxstep, &rtol, &atol, <ol, &max_its);CHKERRQ(ierr); ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr); ierr = SNESLineSearchGetDefaultMonitor(linesearch, &monitor);CHKERRQ(ierr); /* precheck */ ierr = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr); lambda_old = 0.0; ierr = VecDot(F,Y,&fty_old);CHKERRQ(ierr); fty_init = fty_old; for (i = 0; i < max_its; i++) { /* compute the norm at lambda */ ierr = VecCopy(X, W);CHKERRQ(ierr); ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr); ierr = VecDot(F,Y,&fty);CHKERRQ(ierr); delLambda = lambda - lambda_old; /* check for convergence */ if (PetscAbsReal(delLambda) < steptol*lambda) break; if (PetscAbsScalar(fty) / PetscAbsScalar(fty_init) < rtol) break; if (PetscAbsScalar(fty) < atol && i > 0) break; if (monitor) { ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(monitor," Line search: lambdas = [%g, %g], ftys = [%g, %g]\n",(double)lambda, (double)lambda_old, (double)PetscRealPart(fty), (double)PetscRealPart(fty_old));CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); } /* compute the search direction */ if (linesearch->order == SNES_LINESEARCH_ORDER_LINEAR) { s = (fty - fty_old) / delLambda; } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { ierr = VecCopy(X, W);CHKERRQ(ierr); ierr = VecAXPY(W, -0.5*(lambda + lambda_old), Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr); ierr = VecDot(F, Y, &fty_mid1);CHKERRQ(ierr); s = (3.*fty - 4.*fty_mid1 + fty_old) / delLambda; } else { ierr = VecCopy(X, W);CHKERRQ(ierr); ierr = VecAXPY(W, -0.5*(lambda + lambda_old), Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr); ierr = VecDot(F, Y, &fty_mid1);CHKERRQ(ierr); ierr = VecCopy(X, W);CHKERRQ(ierr); ierr = VecAXPY(W, -(lambda + 0.5*(lambda - lambda_old)), Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } ierr = (*linesearch->ops->snesfunc)(snes, W, F);CHKERRQ(ierr); ierr = VecDot(F, Y, &fty_mid2);CHKERRQ(ierr); s = (2.*fty_mid2 + 3.*fty - 6.*fty_mid1 + fty_old) / (3.*delLambda); } /* if the solve is going in the wrong direction, fix it */ if (PetscRealPart(s) > 0.) s = -s; lambda_update = lambda - PetscRealPart(fty / s); /* switch directions if we stepped out of bounds */ if (lambda_update < steptol) lambda_update = lambda + PetscRealPart(fty / s); if (PetscIsInfOrNanReal(lambda_update)) break; if (lambda_update > maxstep) break; /* compute the new state of the line search */ lambda_old = lambda; lambda = lambda_update; fty_old = fty; } /* construct the solution */ ierr = VecCopy(X, W);CHKERRQ(ierr); ierr = VecAXPY(W, -lambda, Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } /* postcheck */ ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr); if (changed_y) { ierr = VecAXPY(X, -lambda, Y);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, X);CHKERRQ(ierr); } } else { ierr = VecCopy(W, X);CHKERRQ(ierr); } ierr = (*linesearch->ops->snesfunc)(snes,X,F);CHKERRQ(ierr); ierr = SNESLineSearchComputeNorms(linesearch);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr); ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr); if (monitor) { ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(monitor," Line search terminated: lambda = %g, fnorms = %g\n", (double)lambda, (double)gnorm);CHKERRQ(ierr); ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); } if (lambda <= steptol) { ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr); } PetscFunctionReturn(0); }
static PetscErrorCode TaoSolve_SQPCON(Tao tao) { TAO_SQPCON *sqpconP = (TAO_SQPCON*)tao->data; PetscInt iter=0; TaoConvergedReason reason = TAO_CONTINUE_ITERATING; TaoLineSearchConvergedReason ls_reason = TAOLINESEARCH_CONTINUE_ITERATING; PetscReal step=1.0,f,fm, fold; PetscReal cnorm, mnorm; PetscBool use_update=PETSC_TRUE; /* don't update Q if line search failed */ PetscErrorCode ierr; PetscFunctionBegin; /* Scatter to U,V */ ierr = VecScatterBegin(sqpconP->state_scatter, tao->solution, sqpconP->U, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->state_scatter, tao->solution, sqpconP->U, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(sqpconP->design_scatter, tao->solution, sqpconP->V, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->design_scatter, tao->solution, sqpconP->V, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); /* Evaluate Function, Gradient, Constraints, and Jacobian */ ierr = TaoComputeObjectiveAndGradient(tao,tao->solution,&f,tao->gradient);CHKERRQ(ierr); ierr = TaoComputeConstraints(tao,tao->solution, tao->constraints);CHKERRQ(ierr); ierr = TaoComputeJacobianState(tao,tao->solution, &tao->jacobian_state, &tao->jacobian_state_pre, &tao->jacobian_state_inv, &sqpconP->statematflag);CHKERRQ(ierr); ierr = TaoComputeJacobianDesign(tao,tao->solution, &tao->jacobian_design, &tao->jacobian_design_pre, &sqpconP->statematflag);CHKERRQ(ierr); /* Scatter gradient to GU,GV */ ierr = VecScatterBegin(sqpconP->state_scatter, tao->gradient, sqpconP->GU, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->state_scatter, tao->gradient, sqpconP->GU, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(sqpconP->design_scatter, tao->gradient, sqpconP->GV, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->design_scatter, tao->gradient, sqpconP->GV, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecNorm(tao->gradient, NORM_2, &mnorm);CHKERRQ(ierr); /* Evaluate constraint norm */ ierr = VecNorm(tao->constraints, NORM_2, &cnorm);CHKERRQ(ierr); /* Monitor convergence */ ierr = TaoMonitor(tao, iter,f,mnorm,cnorm,step,&reason);CHKERRQ(ierr); while (reason == TAO_CONTINUE_ITERATING) { /* Solve tbar = -A\t (t is constraints vector) */ ierr = MatMult(tao->jacobian_state_inv, tao->constraints, sqpconP->Tbar);CHKERRQ(ierr); ierr = VecScale(sqpconP->Tbar, -1.0);CHKERRQ(ierr); /* aqwac = A'\(Q*Tbar + c) */ if (iter > 0) { ierr = MatMult(sqpconP->Q,sqpconP->Tbar,sqpconP->WV);CHKERRQ(ierr); } else { ierr = VecCopy(sqpconP->Tbar, sqpconP->WV);CHKERRQ(ierr); } ierr = VecAXPY(sqpconP->WV,1.0,sqpconP->GU);CHKERRQ(ierr); ierr = MatMultTranspose(tao->jacobian_state_inv, sqpconP->WV, sqpconP->aqwac);CHKERRQ(ierr); /* Reduced Gradient dbar = d - B^t * aqwac */ ierr = MatMultTranspose(tao->jacobian_design,sqpconP->aqwac, sqpconP->dbar);CHKERRQ(ierr); ierr = VecScale(sqpconP->dbar, -1.0);CHKERRQ(ierr); ierr = VecAXPY(sqpconP->dbar,1.0,sqpconP->GV);CHKERRQ(ierr); /* update reduced hessian */ ierr = MatLMVMUpdate(sqpconP->R, sqpconP->V, sqpconP->dbar);CHKERRQ(ierr); /* Solve R*dv = -dbar using approx. hessian */ ierr = MatLMVMSolve(sqpconP->R, sqpconP->dbar, sqpconP->DV);CHKERRQ(ierr); ierr = VecScale(sqpconP->DV, -1.0);CHKERRQ(ierr); /* Backsolve for u = A\(g - B*dv) = tbar - A\(B*dv)*/ ierr = MatMult(tao->jacobian_design, sqpconP->DV, sqpconP->WL);CHKERRQ(ierr); ierr = MatMult(tao->jacobian_state_inv, sqpconP->WL, sqpconP->DU);CHKERRQ(ierr); ierr = VecScale(sqpconP->DU, -1.0);CHKERRQ(ierr); ierr = VecAXPY(sqpconP->DU, 1.0, sqpconP->Tbar);CHKERRQ(ierr); /* Assemble Big D */ ierr = VecScatterBegin(sqpconP->state_scatter, sqpconP->DU, tao->stepdirection, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->state_scatter, sqpconP->DU, tao->stepdirection, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterBegin(sqpconP->design_scatter, sqpconP->DV, tao->stepdirection, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->design_scatter, sqpconP->DV, tao->stepdirection, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); /* Perform Line Search */ ierr = VecCopy(tao->solution, sqpconP->Xold);CHKERRQ(ierr); ierr = VecCopy(tao->gradient, sqpconP->Gold);CHKERRQ(ierr); fold = f; ierr = TaoLineSearchComputeObjectiveAndGradient(tao->linesearch,tao->solution,&fm,sqpconP->GL);CHKERRQ(ierr); ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,1.0); ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &fm, sqpconP->GL, tao->stepdirection,&step, &ls_reason);CHKERRQ(ierr); ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); if (ls_reason < 0) { ierr = VecCopy(sqpconP->Xold, tao->solution); ierr = VecCopy(sqpconP->Gold, tao->gradient); f = fold; ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr); ierr = PetscInfo(tao,"Line Search Failed, using full step.");CHKERRQ(ierr); use_update=PETSC_FALSE; } else { use_update = PETSC_TRUE; } /* Scatter X to U,V */ ierr = VecScatterBegin(sqpconP->state_scatter, tao->solution, sqpconP->U, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->state_scatter, tao->solution, sqpconP->U, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(sqpconP->design_scatter, tao->solution, sqpconP->V, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->design_scatter, tao->solution, sqpconP->V, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); /* Evaluate Function, Gradient, Constraints, and Jacobian */ ierr = TaoComputeObjectiveAndGradient(tao,tao->solution,&f,tao->gradient);CHKERRQ(ierr); ierr = TaoComputeConstraints(tao,tao->solution, tao->constraints);CHKERRQ(ierr); ierr = TaoComputeJacobianState(tao,tao->solution, &tao->jacobian_state, &tao->jacobian_state_pre, &tao->jacobian_state_inv, &sqpconP->statematflag);CHKERRQ(ierr); ierr = TaoComputeJacobianDesign(tao,tao->solution, &tao->jacobian_design, &tao->jacobian_design_pre, &sqpconP->designmatflag);CHKERRQ(ierr); /* Scatter gradient to GU,GV */ ierr = VecScatterBegin(sqpconP->state_scatter, tao->gradient, sqpconP->GU, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->state_scatter, tao->gradient, sqpconP->GU, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterBegin(sqpconP->design_scatter, tao->gradient, sqpconP->GV, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(sqpconP->design_scatter, tao->gradient, sqpconP->GV, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); /* Update approx to hessian of the Lagrangian wrt state (Q) with u_k+1, gu_k+1 */ if (use_update) { ierr = MatApproxUpdate(sqpconP->Q,sqpconP->U,sqpconP->GU);CHKERRQ(ierr); } ierr = VecNorm(sqpconP->GL, NORM_2, &mnorm);CHKERRQ(ierr); /* Evaluate constraint norm */ ierr = VecNorm(tao->constraints, NORM_2, &cnorm);CHKERRQ(ierr); /* Monitor convergence */ iter++; ierr = TaoMonitor(tao, iter,f,mnorm,cnorm,step,&reason);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/* Shared by both sequential and parallel versions of CRL matrix: MATMPICRL and MATSEQCRL - the scatter is used only in the parallel version */ PetscErrorCode MatMult_CRL(Mat A,Vec xx,Vec yy) { Mat_CRL *crl = (Mat_CRL*) A->spptr; PetscInt m = crl->m; /* Number of rows in the matrix. */ PetscInt rmax = crl->rmax,*icols = crl->icols; PetscScalar *acols = crl->acols; PetscErrorCode ierr; PetscScalar *x,*y; #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTCRL) PetscInt i,j,ii; #endif #if defined(PETSC_HAVE_PRAGMA_DISJOINT) #pragma disjoint(*x,*y,*aa) #endif PetscFunctionBegin; if (crl->xscat) { ierr = VecCopy(xx,crl->xwork);CHKERRQ(ierr); /* get remote values needed for local part of multiply */ ierr = VecScatterBegin(crl->xscat,xx,crl->fwork,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(crl->xscat,xx,crl->fwork,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); xx = crl->xwork; }; ierr = VecGetArray(xx,&x);CHKERRQ(ierr); ierr = VecGetArray(yy,&y);CHKERRQ(ierr); #if defined(PETSC_USE_FORTRAN_KERNEL_MULTCRL) fortranmultcrl_(&m,&rmax,x,y,icols,acols); #else /* first column */ for (j=0; j<m; j++) { y[j] = acols[j]*x[icols[j]]; } /* other columns */ #if defined(PETSC_HAVE_CRAYC) #pragma _CRI preferstream #endif for (i=1; i<rmax; i++) { ii = i*m; #if defined(PETSC_HAVE_CRAYC) #pragma _CRI prefervector #endif for (j=0; j<m; j++) { y[j] = y[j] + acols[ii+j]*x[icols[ii+j]]; } } #if defined(PETSC_HAVE_CRAYC) #pragma _CRI ivdep #endif #endif ierr = PetscLogFlops(2.0*crl->nz - m);CHKERRQ(ierr); ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode TaoSolve_NTR(Tao tao) { TAO_NTR *tr = (TAO_NTR *)tao->data; PC pc; KSPConvergedReason ksp_reason; TaoConvergedReason reason; PetscReal fmin, ftrial, prered, actred, kappa, sigma, beta; PetscReal tau, tau_1, tau_2, tau_max, tau_min, max_radius; PetscReal f, gnorm; PetscReal delta; PetscReal norm_d; PetscErrorCode ierr; PetscInt iter = 0; PetscInt bfgsUpdates = 0; PetscInt needH; PetscInt i_max = 5; PetscInt j_max = 1; PetscInt i, j, N, n, its; PetscFunctionBegin; if (tao->XL || tao->XU || tao->ops->computebounds) { ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by ntr algorithm\n");CHKERRQ(ierr); } tao->trust = tao->trust0; /* Modify the radius if it is too large or small */ tao->trust = PetscMax(tao->trust, tr->min_radius); tao->trust = PetscMin(tao->trust, tr->max_radius); if (NTR_PC_BFGS == tr->pc_type && !tr->M) { ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr); ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr); ierr = MatCreateLMVM(((PetscObject)tao)->comm,n,N,&tr->M);CHKERRQ(ierr); ierr = MatLMVMAllocateVectors(tr->M,tao->solution);CHKERRQ(ierr); } /* Check convergence criteria */ ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);CHKERRQ(ierr); ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); needH = 1; ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr); if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); /* Create vectors for the limited memory preconditioner */ if ((NTR_PC_BFGS == tr->pc_type) && (BFGS_SCALE_BFGS != tr->bfgs_scale_type)) { if (!tr->Diag) { ierr = VecDuplicate(tao->solution, &tr->Diag);CHKERRQ(ierr); } } switch(tr->ksp_type) { case NTR_KSP_NASH: ierr = KSPSetType(tao->ksp, KSPNASH);CHKERRQ(ierr); if (tao->ksp->ops->setfromoptions) { (*tao->ksp->ops->setfromoptions)(tao->ksp); } break; case NTR_KSP_STCG: ierr = KSPSetType(tao->ksp, KSPSTCG);CHKERRQ(ierr); if (tao->ksp->ops->setfromoptions) { (*tao->ksp->ops->setfromoptions)(tao->ksp); } break; default: ierr = KSPSetType(tao->ksp, KSPGLTR);CHKERRQ(ierr); if (tao->ksp->ops->setfromoptions) { (*tao->ksp->ops->setfromoptions)(tao->ksp); } break; } /* Modify the preconditioner to use the bfgs approximation */ ierr = KSPGetPC(tao->ksp, &pc);CHKERRQ(ierr); switch(tr->pc_type) { case NTR_PC_NONE: ierr = PCSetType(pc, PCNONE);CHKERRQ(ierr); if (pc->ops->setfromoptions) { (*pc->ops->setfromoptions)(pc); } break; case NTR_PC_AHESS: ierr = PCSetType(pc, PCJACOBI);CHKERRQ(ierr); if (pc->ops->setfromoptions) { (*pc->ops->setfromoptions)(pc); } ierr = PCJacobiSetUseAbs(pc);CHKERRQ(ierr); break; case NTR_PC_BFGS: ierr = PCSetType(pc, PCSHELL);CHKERRQ(ierr); if (pc->ops->setfromoptions) { (*pc->ops->setfromoptions)(pc); } ierr = PCShellSetName(pc, "bfgs");CHKERRQ(ierr); ierr = PCShellSetContext(pc, tr->M);CHKERRQ(ierr); ierr = PCShellSetApply(pc, MatLMVMSolveShell);CHKERRQ(ierr); break; default: /* Use the pc method set by pc_type */ break; } /* Initialize trust-region radius */ switch(tr->init_type) { case NTR_INIT_CONSTANT: /* Use the initial radius specified */ break; case NTR_INIT_INTERPOLATION: /* Use the initial radius specified */ max_radius = 0.0; for (j = 0; j < j_max; ++j) { fmin = f; sigma = 0.0; if (needH) { ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); needH = 0; } for (i = 0; i < i_max; ++i) { ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr); ierr = VecAXPY(tr->W, -tao->trust/gnorm, tao->gradient);CHKERRQ(ierr); ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); if (PetscIsInfOrNanReal(ftrial)) { tau = tr->gamma1_i; } else { if (ftrial < fmin) { fmin = ftrial; sigma = -tao->trust / gnorm; } ierr = MatMult(tao->hessian, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = VecDot(tao->gradient, tao->stepdirection, &prered);CHKERRQ(ierr); prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm)); actred = f - ftrial; if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) { kappa = 1.0; } else { kappa = actred / prered; } tau_1 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust + (1.0 - tr->theta_i) * prered - actred); tau_2 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust - (1.0 + tr->theta_i) * prered + actred); tau_min = PetscMin(tau_1, tau_2); tau_max = PetscMax(tau_1, tau_2); if (PetscAbsScalar(kappa - 1.0) <= tr->mu1_i) { /* Great agreement */ max_radius = PetscMax(max_radius, tao->trust); if (tau_max < 1.0) { tau = tr->gamma3_i; } else if (tau_max > tr->gamma4_i) { tau = tr->gamma4_i; } else { tau = tau_max; } } else if (PetscAbsScalar(kappa - 1.0) <= tr->mu2_i) { /* Good agreement */ max_radius = PetscMax(max_radius, tao->trust); if (tau_max < tr->gamma2_i) { tau = tr->gamma2_i; } else if (tau_max > tr->gamma3_i) { tau = tr->gamma3_i; } else { tau = tau_max; } } else { /* Not good agreement */ if (tau_min > 1.0) { tau = tr->gamma2_i; } else if (tau_max < tr->gamma1_i) { tau = tr->gamma1_i; } else if ((tau_min < tr->gamma1_i) && (tau_max >= 1.0)) { tau = tr->gamma1_i; } else if ((tau_1 >= tr->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < tr->gamma1_i) || (tau_2 >= 1.0))) { tau = tau_1; } else if ((tau_2 >= tr->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < tr->gamma1_i) || (tau_2 >= 1.0))) { tau = tau_2; } else { tau = tau_max; } } } tao->trust = tau * tao->trust; } if (fmin < f) { f = fmin; ierr = VecAXPY(tao->solution, sigma, tao->gradient);CHKERRQ(ierr); ierr = TaoComputeGradient(tao,tao->solution, tao->gradient);CHKERRQ(ierr); ierr = VecNorm(tao->gradient, NORM_2, &gnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); needH = 1; ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr); if (reason != TAO_CONTINUE_ITERATING) { PetscFunctionReturn(0); } } } tao->trust = PetscMax(tao->trust, max_radius); /* Modify the radius if it is too large or small */ tao->trust = PetscMax(tao->trust, tr->min_radius); tao->trust = PetscMin(tao->trust, tr->max_radius); break; default: /* Norm of the first direction will initialize radius */ tao->trust = 0.0; break; } /* Set initial scaling for the BFGS preconditioner This step is done after computing the initial trust-region radius since the function value may have decreased */ if (NTR_PC_BFGS == tr->pc_type) { if (f != 0.0) { delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm); } else { delta = 2.0 / (gnorm*gnorm); } ierr = MatLMVMSetDelta(tr->M,delta);CHKERRQ(ierr); } /* Have not converged; continue with Newton method */ while (reason == TAO_CONTINUE_ITERATING) { ++iter; tao->ksp_its=0; /* Compute the Hessian */ if (needH) { ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); needH = 0; } if (NTR_PC_BFGS == tr->pc_type) { if (BFGS_SCALE_AHESS == tr->bfgs_scale_type) { /* Obtain diagonal for the bfgs preconditioner */ ierr = MatGetDiagonal(tao->hessian, tr->Diag);CHKERRQ(ierr); ierr = VecAbs(tr->Diag);CHKERRQ(ierr); ierr = VecReciprocal(tr->Diag);CHKERRQ(ierr); ierr = MatLMVMSetScale(tr->M,tr->Diag);CHKERRQ(ierr); } /* Update the limited memory preconditioner */ ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr); ++bfgsUpdates; } while (reason == TAO_CONTINUE_ITERATING) { ierr = KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre);CHKERRQ(ierr); /* Solve the trust region subproblem */ if (NTR_KSP_NASH == tr->ksp_type) { ierr = KSPNASHSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPNASHGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } else if (NTR_KSP_STCG == tr->ksp_type) { ierr = KSPSTCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPSTCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } else { /* NTR_KSP_GLTR */ ierr = KSPGLTRSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPGLTRGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } if (0.0 == tao->trust) { /* Radius was uninitialized; use the norm of the direction */ if (norm_d > 0.0) { tao->trust = norm_d; /* Modify the radius if it is too large or small */ tao->trust = PetscMax(tao->trust, tr->min_radius); tao->trust = PetscMin(tao->trust, tr->max_radius); } else { /* The direction was bad; set radius to default value and re-solve the trust-region subproblem to get a direction */ tao->trust = tao->trust0; /* Modify the radius if it is too large or small */ tao->trust = PetscMax(tao->trust, tr->min_radius); tao->trust = PetscMin(tao->trust, tr->max_radius); if (NTR_KSP_NASH == tr->ksp_type) { ierr = KSPNASHSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPNASHGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } else if (NTR_KSP_STCG == tr->ksp_type) { ierr = KSPSTCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPSTCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } else { /* NTR_KSP_GLTR */ ierr = KSPGLTRSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its+=its; tao->ksp_tot_its+=its; ierr = KSPGLTRGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); } if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero"); } } ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); ierr = KSPGetConvergedReason(tao->ksp, &ksp_reason);CHKERRQ(ierr); if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) && (NTR_PC_BFGS == tr->pc_type) && (bfgsUpdates > 1)) { /* Preconditioner is numerically indefinite; reset the approximate if using BFGS preconditioning. */ if (f != 0.0) { delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm); } else { delta = 2.0 / (gnorm*gnorm); } ierr = MatLMVMSetDelta(tr->M, delta);CHKERRQ(ierr); ierr = MatLMVMReset(tr->M);CHKERRQ(ierr); ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr); bfgsUpdates = 1; } if (NTR_UPDATE_REDUCTION == tr->update_type) { /* Get predicted reduction */ if (NTR_KSP_NASH == tr->ksp_type) { ierr = KSPNASHGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } else if (NTR_KSP_STCG == tr->ksp_type) { ierr = KSPSTCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } else { /* gltr */ ierr = KSPGLTRGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } if (prered >= 0.0) { /* The predicted reduction has the wrong sign. This cannot happen in infinite precision arithmetic. Step should be rejected! */ tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); } else { /* Compute trial step and function value */ ierr = VecCopy(tao->solution,tr->W);CHKERRQ(ierr); ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr); ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); if (PetscIsInfOrNanReal(ftrial)) { tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); } else { /* Compute and actual reduction */ actred = f - ftrial; prered = -prered; if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) { kappa = 1.0; } else { kappa = actred / prered; } /* Accept or reject the step and update radius */ if (kappa < tr->eta1) { /* Reject the step */ tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); } else { /* Accept the step */ if (kappa < tr->eta2) { /* Marginal bad step */ tao->trust = tr->alpha2 * PetscMin(tao->trust, norm_d); } else if (kappa < tr->eta3) { /* Reasonable step */ tao->trust = tr->alpha3 * tao->trust; } else if (kappa < tr->eta4) { /* Good step */ tao->trust = PetscMax(tr->alpha4 * norm_d, tao->trust); } else { /* Very good step */ tao->trust = PetscMax(tr->alpha5 * norm_d, tao->trust); } break; } } } } else { /* Get predicted reduction */ if (NTR_KSP_NASH == tr->ksp_type) { ierr = KSPNASHGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } else if (NTR_KSP_STCG == tr->ksp_type) { ierr = KSPSTCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } else { /* gltr */ ierr = KSPGLTRGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); } if (prered >= 0.0) { /* The predicted reduction has the wrong sign. This cannot happen in infinite precision arithmetic. Step should be rejected! */ tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); } else { ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr); ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr); ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); if (PetscIsInfOrNanReal(ftrial)) { tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); } else { ierr = VecDot(tao->gradient, tao->stepdirection, &beta);CHKERRQ(ierr); actred = f - ftrial; prered = -prered; if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) { kappa = 1.0; } else { kappa = actred / prered; } tau_1 = tr->theta * beta / (tr->theta * beta - (1.0 - tr->theta) * prered + actred); tau_2 = tr->theta * beta / (tr->theta * beta + (1.0 + tr->theta) * prered - actred); tau_min = PetscMin(tau_1, tau_2); tau_max = PetscMax(tau_1, tau_2); if (kappa >= 1.0 - tr->mu1) { /* Great agreement; accept step and update radius */ if (tau_max < 1.0) { tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d); } else if (tau_max > tr->gamma4) { tao->trust = PetscMax(tao->trust, tr->gamma4 * norm_d); } else { tao->trust = PetscMax(tao->trust, tau_max * norm_d); } break; } else if (kappa >= 1.0 - tr->mu2) { /* Good agreement */ if (tau_max < tr->gamma2) { tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d); } else if (tau_max > tr->gamma3) { tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d); } else if (tau_max < 1.0) { tao->trust = tau_max * PetscMin(tao->trust, norm_d); } else { tao->trust = PetscMax(tao->trust, tau_max * norm_d); } break; } else { /* Not good agreement */ if (tau_min > 1.0) { tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d); } else if (tau_max < tr->gamma1) { tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); } else if ((tau_min < tr->gamma1) && (tau_max >= 1.0)) { tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); } else if ((tau_1 >= tr->gamma1) && (tau_1 < 1.0) && ((tau_2 < tr->gamma1) || (tau_2 >= 1.0))) { tao->trust = tau_1 * PetscMin(tao->trust, norm_d); } else if ((tau_2 >= tr->gamma1) && (tau_2 < 1.0) && ((tau_1 < tr->gamma1) || (tau_2 >= 1.0))) { tao->trust = tau_2 * PetscMin(tao->trust, norm_d); } else { tao->trust = tau_max * PetscMin(tao->trust, norm_d); } } } } } /* The step computed was not good and the radius was decreased. Monitor the radius to terminate. */ ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr); } /* The radius may have been increased; modify if it is too large */ tao->trust = PetscMin(tao->trust, tr->max_radius); if (reason == TAO_CONTINUE_ITERATING) { ierr = VecCopy(tr->W, tao->solution);CHKERRQ(ierr); f = ftrial; ierr = TaoComputeGradient(tao, tao->solution, tao->gradient); ierr = VecNorm(tao->gradient, NORM_2, &gnorm);CHKERRQ(ierr); if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); needH = 1; ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr); } } PetscFunctionReturn(0); }
static PetscErrorCode TSStep_Theta(TS ts) { TS_Theta *th = (TS_Theta*)ts->data; PetscInt its,lits,reject,next_scheme; PetscReal next_time_step; TSAdapt adapt; PetscBool stageok,accept = PETSC_TRUE; PetscErrorCode ierr; PetscFunctionBegin; th->status = TS_STEP_INCOMPLETE; ierr = VecCopy(ts->vec_sol,th->X0);CHKERRQ(ierr); for (reject=0; !ts->reason && th->status != TS_STEP_COMPLETE; ts->reject++) { PetscReal shift = 1./(th->Theta*ts->time_step); th->stage_time = ts->ptime + (th->endpoint ? 1. : th->Theta)*ts->time_step; ierr = TSPreStep(ts);CHKERRQ(ierr); ierr = TSPreStage(ts,th->stage_time);CHKERRQ(ierr); if (th->endpoint) { /* This formulation assumes linear time-independent mass matrix */ ierr = VecZeroEntries(th->Xdot);CHKERRQ(ierr); if (!th->affine) {ierr = VecDuplicate(ts->vec_sol,&th->affine);CHKERRQ(ierr);} ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,th->Xdot,th->affine,PETSC_FALSE);CHKERRQ(ierr); ierr = VecScale(th->affine,(th->Theta-1.)/th->Theta);CHKERRQ(ierr); } if (th->extrapolate) { ierr = VecWAXPY(th->X,1./shift,th->Xdot,ts->vec_sol);CHKERRQ(ierr); } else { ierr = VecCopy(ts->vec_sol,th->X);CHKERRQ(ierr); } ierr = SNESSolve(ts->snes,th->affine,th->X);CHKERRQ(ierr); ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr); ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr); ts->snes_its += its; ts->ksp_its += lits; ierr = TSPostStage(ts,th->stage_time,0,&(th->X));CHKERRQ(ierr); ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); ierr = TSAdaptCheckStage(adapt,ts,&stageok);CHKERRQ(ierr); if (!stageok) {accept = PETSC_FALSE; goto reject_step;} ierr = TSEvaluateStep(ts,th->order,ts->vec_sol,NULL);CHKERRQ(ierr); th->status = TS_STEP_PENDING; /* Register only the current method as a candidate because we're not supporting multiple candidates yet. */ ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); ierr = TSAdaptCandidatesClear(adapt);CHKERRQ(ierr); ierr = TSAdaptCandidateAdd(adapt,NULL,th->order,1,th->ccfl,1.0,PETSC_TRUE);CHKERRQ(ierr); ierr = TSAdaptChoose(adapt,ts,ts->time_step,&next_scheme,&next_time_step,&accept);CHKERRQ(ierr); if (!accept) { /* Roll back the current step */ ts->ptime += next_time_step; /* This will be undone in rollback */ th->status = TS_STEP_INCOMPLETE; ierr = TSRollBack(ts);CHKERRQ(ierr); goto reject_step; } /* ignore next_scheme for now */ ts->ptime += ts->time_step; ts->time_step = next_time_step; ts->steps++; th->status = TS_STEP_COMPLETE; break; reject_step: if (!ts->reason && ++reject > ts->max_reject && ts->max_reject >= 0) { ts->reason = TS_DIVERGED_STEP_REJECTED; ierr = PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);CHKERRQ(ierr); } continue; } PetscFunctionReturn(0); }
static PetscErrorCode TaoSolve_IPM(Tao tao) { PetscErrorCode ierr; TAO_IPM *ipmP = (TAO_IPM*)tao->data; TaoConvergedReason reason = TAO_CONTINUE_ITERATING; PetscInt its,i; PetscScalar stepsize=1.0; PetscScalar step_s,step_l,alpha,tau,sigma,phi_target; PetscFunctionBegin; /* Push initial point away from bounds */ ierr = IPMInitializeBounds(tao);CHKERRQ(ierr); ierr = IPMPushInitialPoint(tao);CHKERRQ(ierr); ierr = VecCopy(tao->solution,ipmP->rhs_x);CHKERRQ(ierr); ierr = IPMEvaluate(tao);CHKERRQ(ierr); ierr = IPMComputeKKT(tao);CHKERRQ(ierr); ierr = TaoMonitor(tao,tao->niter++,ipmP->kkt_f,ipmP->phi,0.0,1.0,&reason);CHKERRQ(ierr); while (reason == TAO_CONTINUE_ITERATING) { tao->ksp_its=0; ierr = IPMUpdateK(tao);CHKERRQ(ierr); /* rhs.x = -rd rhs.lame = -rpe rhs.lami = -rpi rhs.com = -com */ ierr = VecCopy(ipmP->rd,ipmP->rhs_x);CHKERRQ(ierr); if (ipmP->me > 0) { ierr = VecCopy(ipmP->rpe,ipmP->rhs_lamdae);CHKERRQ(ierr); } if (ipmP->nb > 0) { ierr = VecCopy(ipmP->rpi,ipmP->rhs_lamdai);CHKERRQ(ierr); ierr = VecCopy(ipmP->complementarity,ipmP->rhs_s);CHKERRQ(ierr); } ierr = IPMGatherRHS(tao,ipmP->bigrhs,ipmP->rhs_x,ipmP->rhs_lamdae,ipmP->rhs_lamdai,ipmP->rhs_s);CHKERRQ(ierr); ierr = VecScale(ipmP->bigrhs,-1.0);CHKERRQ(ierr); /* solve K * step = rhs */ ierr = KSPSetOperators(tao->ksp,ipmP->K,ipmP->K);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp,ipmP->bigrhs,ipmP->bigstep);CHKERRQ(ierr); ierr = IPMScatterStep(tao,ipmP->bigstep,tao->stepdirection,ipmP->ds,ipmP->dlamdae,ipmP->dlamdai);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its += its; tao->ksp_tot_its+=its; /* Find distance along step direction to closest bound */ if (ipmP->nb > 0) { ierr = VecStepBoundInfo(ipmP->s,ipmP->ds,ipmP->Zero_nb,ipmP->Inf_nb,&step_s,NULL,NULL);CHKERRQ(ierr); ierr = VecStepBoundInfo(ipmP->lamdai,ipmP->dlamdai,ipmP->Zero_nb,ipmP->Inf_nb,&step_l,NULL,NULL);CHKERRQ(ierr); alpha = PetscMin(step_s,step_l); alpha = PetscMin(alpha,1.0); ipmP->alpha1 = alpha; } else { ipmP->alpha1 = alpha = 1.0; } /* x_aff = x + alpha*d */ ierr = VecCopy(tao->solution,ipmP->save_x);CHKERRQ(ierr); if (ipmP->me > 0) { ierr = VecCopy(ipmP->lamdae,ipmP->save_lamdae);CHKERRQ(ierr); } if (ipmP->nb > 0) { ierr = VecCopy(ipmP->lamdai,ipmP->save_lamdai);CHKERRQ(ierr); ierr = VecCopy(ipmP->s,ipmP->save_s);CHKERRQ(ierr); } ierr = VecAXPY(tao->solution,alpha,tao->stepdirection);CHKERRQ(ierr); if (ipmP->me > 0) { ierr = VecAXPY(ipmP->lamdae,alpha,ipmP->dlamdae);CHKERRQ(ierr); } if (ipmP->nb > 0) { ierr = VecAXPY(ipmP->lamdai,alpha,ipmP->dlamdai);CHKERRQ(ierr); ierr = VecAXPY(ipmP->s,alpha,ipmP->ds);CHKERRQ(ierr); } /* Recompute kkt to find centering parameter sigma = (new_mu/old_mu)^3 */ if (ipmP->mu == 0.0) { sigma = 0.0; } else { sigma = 1.0/ipmP->mu; } ierr = IPMComputeKKT(tao);CHKERRQ(ierr); sigma *= ipmP->mu; sigma*=sigma*sigma; /* revert kkt info */ ierr = VecCopy(ipmP->save_x,tao->solution);CHKERRQ(ierr); if (ipmP->me > 0) { ierr = VecCopy(ipmP->save_lamdae,ipmP->lamdae);CHKERRQ(ierr); } if (ipmP->nb > 0) { ierr = VecCopy(ipmP->save_lamdai,ipmP->lamdai);CHKERRQ(ierr); ierr = VecCopy(ipmP->save_s,ipmP->s);CHKERRQ(ierr); } ierr = IPMComputeKKT(tao);CHKERRQ(ierr); /* update rhs with new complementarity vector */ if (ipmP->nb > 0) { ierr = VecCopy(ipmP->complementarity,ipmP->rhs_s);CHKERRQ(ierr); ierr = VecScale(ipmP->rhs_s,-1.0);CHKERRQ(ierr); ierr = VecShift(ipmP->rhs_s,sigma*ipmP->mu);CHKERRQ(ierr); } ierr = IPMGatherRHS(tao,ipmP->bigrhs,NULL,NULL,NULL,ipmP->rhs_s);CHKERRQ(ierr); /* solve K * step = rhs */ ierr = KSPSetOperators(tao->ksp,ipmP->K,ipmP->K);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp,ipmP->bigrhs,ipmP->bigstep);CHKERRQ(ierr); ierr = IPMScatterStep(tao,ipmP->bigstep,tao->stepdirection,ipmP->ds,ipmP->dlamdae,ipmP->dlamdai);CHKERRQ(ierr); ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); tao->ksp_its += its; tao->ksp_tot_its+=its; if (ipmP->nb > 0) { /* Get max step size and apply frac-to-boundary */ tau = PetscMax(ipmP->taumin,1.0-ipmP->mu); tau = PetscMin(tau,1.0); if (tau != 1.0) { ierr = VecScale(ipmP->s,tau);CHKERRQ(ierr); ierr = VecScale(ipmP->lamdai,tau);CHKERRQ(ierr); } ierr = VecStepBoundInfo(ipmP->s,ipmP->ds,ipmP->Zero_nb,ipmP->Inf_nb,&step_s,NULL,NULL);CHKERRQ(ierr); ierr = VecStepBoundInfo(ipmP->lamdai,ipmP->dlamdai,ipmP->Zero_nb,ipmP->Inf_nb,&step_l,NULL,NULL);CHKERRQ(ierr); if (tau != 1.0) { ierr = VecCopy(ipmP->save_s,ipmP->s);CHKERRQ(ierr); ierr = VecCopy(ipmP->save_lamdai,ipmP->lamdai);CHKERRQ(ierr); } alpha = PetscMin(step_s,step_l); alpha = PetscMin(alpha,1.0); } else { alpha = 1.0; } ipmP->alpha2 = alpha; /* TODO make phi_target meaningful */ phi_target = ipmP->dec * ipmP->phi; for (i=0; i<11;i++) { ierr = VecAXPY(tao->solution,alpha,tao->stepdirection);CHKERRQ(ierr); if (ipmP->nb > 0) { ierr = VecAXPY(ipmP->s,alpha,ipmP->ds);CHKERRQ(ierr); ierr = VecAXPY(ipmP->lamdai,alpha,ipmP->dlamdai);CHKERRQ(ierr); } if (ipmP->me > 0) { ierr = VecAXPY(ipmP->lamdae,alpha,ipmP->dlamdae);CHKERRQ(ierr); } /* update dual variables */ if (ipmP->me > 0) { ierr = VecCopy(ipmP->lamdae,tao->DE);CHKERRQ(ierr); } ierr = IPMEvaluate(tao);CHKERRQ(ierr); ierr = IPMComputeKKT(tao);CHKERRQ(ierr); if (ipmP->phi <= phi_target) break; alpha /= 2.0; } ierr = TaoMonitor(tao,tao->niter,ipmP->kkt_f,ipmP->phi,0.0,stepsize,&reason);CHKERRQ(ierr); tao->niter++; } PetscFunctionReturn(0); }
PetscErrorCode PCBDDCScalingSetUp(PC pc) { PC_IS* pcis=(PC_IS*)pc->data; PC_BDDC* pcbddc=(PC_BDDC*)pc->data; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(pc,PC_CLASSID,1); /* create work vector for the operator */ ierr = VecDestroy(&pcbddc->work_scaling);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_B,&pcbddc->work_scaling);CHKERRQ(ierr); /* always rebuild pcis->D */ if (pcis->use_stiffness_scaling) { ierr = MatGetDiagonal(pcbddc->local_mat,pcis->vec1_N);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->N_to_B,pcis->vec1_N,pcis->D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->N_to_B,pcis->vec1_N,pcis->D,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); } ierr = VecCopy(pcis->D,pcis->vec1_B);CHKERRQ(ierr); ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_global,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_global,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecPointwiseDivide(pcis->D,pcis->D,pcis->vec1_B);CHKERRQ(ierr); /* now setup */ if (pcbddc->use_deluxe_scaling) { if (!pcbddc->deluxe_ctx) { ierr = PCBDDCScalingCreate_Deluxe(pc);CHKERRQ(ierr); } ierr = PCBDDCScalingSetUp_Deluxe(pc);CHKERRQ(ierr); ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCScalingRestriction_C",PCBDDCScalingRestriction_Deluxe);CHKERRQ(ierr); ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCScalingExtension_C",PCBDDCScalingExtension_Deluxe);CHKERRQ(ierr); } else { ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCScalingRestriction_C",PCBDDCScalingRestriction_Basic);CHKERRQ(ierr); ierr = PetscObjectComposeFunction((PetscObject)pc,"PCBDDCScalingExtension_C",PCBDDCScalingExtension_Basic);CHKERRQ(ierr); } /* test */ if (pcbddc->dbg_flag) { Vec vec2_global; PetscViewer viewer=pcbddc->dbg_viewer; PetscReal error; /* extension -> from local to parallel */ ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr); ierr = VecSetRandom(pcis->vec1_B,NULL);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecDuplicate(pcis->vec1_global,&vec2_global);CHKERRQ(ierr); ierr = VecCopy(pcis->vec1_global,vec2_global);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_global,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_global,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = PCBDDCScalingExtension(pc,pcis->vec1_B,pcis->vec1_global);CHKERRQ(ierr); ierr = VecAXPY(pcis->vec1_global,-1.0,vec2_global);CHKERRQ(ierr); ierr = VecNorm(pcis->vec1_global,NORM_INFINITY,&error);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"Error scaling extension %1.14e\n",error);CHKERRQ(ierr); if (error>1.e-8 && pcbddc->dbg_flag>1) { ierr = VecView(pcis->vec1_global,viewer);CHKERRQ(ierr); } ierr = VecDestroy(&vec2_global);CHKERRQ(ierr); /* restriction -> from parallel to local */ ierr = VecSet(pcis->vec1_global,0.0);CHKERRQ(ierr); ierr = VecSetRandom(pcis->vec1_B,NULL);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = PCBDDCScalingRestriction(pc,pcis->vec1_global,pcis->vec1_B);CHKERRQ(ierr); ierr = VecScale(pcis->vec1_B,-1.0);CHKERRQ(ierr); ierr = VecScatterBegin(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecScatterEnd(pcis->global_to_B,pcis->vec1_B,pcis->vec1_global,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); ierr = VecNorm(pcis->vec1_global,NORM_INFINITY,&error);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"Error scaling restriction %1.14e\n",error);CHKERRQ(ierr); if (error>1.e-8 && pcbddc->dbg_flag>1) { ierr = VecView(pcis->vec1_global,viewer);CHKERRQ(ierr); } } PetscFunctionReturn(0); }
PetscErrorCode IPMUpdateAi(Tao tao) { /* Ai = Ji I (w/lb) -I (w/ub) */ /* Ci = user->ci Xi - lb (w/lb) -Xi + ub (w/ub) */ TAO_IPM *ipmP = (TAO_IPM *)tao->data; MPI_Comm comm; PetscInt i; PetscScalar newval; PetscInt newrow,newcol,ncols; const PetscScalar *vals; const PetscInt *cols; PetscInt astart,aend,jstart,jend; PetscInt *nonzeros; PetscInt r2,r3,r4; PetscMPIInt size; PetscErrorCode ierr; PetscFunctionBegin; r2 = ipmP->mi; r3 = r2 + ipmP->nxlb; r4 = r3 + ipmP->nxub; if (!ipmP->nb) PetscFunctionReturn(0); /* Create Ai matrix if it doesn't exist yet */ if (!ipmP->Ai) { comm = ((PetscObject)(tao->solution))->comm; ierr = PetscMalloc1(ipmP->nb,&nonzeros);CHKERRQ(ierr); ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); if (size == 1) { for (i=0;i<ipmP->mi;i++) { ierr = MatGetRow(tao->jacobian_inequality,i,&ncols,NULL,NULL);CHKERRQ(ierr); nonzeros[i] = ncols; ierr = MatRestoreRow(tao->jacobian_inequality,i,&ncols,NULL,NULL);CHKERRQ(ierr); } for (i=r2;i<r4;i++) { nonzeros[i] = 1; } } ierr = MatCreate(comm,&ipmP->Ai);CHKERRQ(ierr); ierr = MatSetType(ipmP->Ai,MATAIJ);CHKERRQ(ierr); ierr = MatSetSizes(ipmP->Ai,PETSC_DECIDE,PETSC_DECIDE,ipmP->nb,ipmP->n);CHKERRQ(ierr); ierr = MatSetFromOptions(ipmP->Ai);CHKERRQ(ierr); ierr = MatMPIAIJSetPreallocation(ipmP->Ai,ipmP->nb,NULL,ipmP->nb,NULL);CHKERRQ(ierr); ierr = MatSeqAIJSetPreallocation(ipmP->Ai,PETSC_DEFAULT,nonzeros);CHKERRQ(ierr); if (size ==1) { ierr = PetscFree(nonzeros);CHKERRQ(ierr); } } /* Copy values from user jacobian to Ai */ ierr = MatGetOwnershipRange(ipmP->Ai,&astart,&aend);CHKERRQ(ierr); /* Ai w/lb */ if (ipmP->mi) { ierr = MatZeroEntries(ipmP->Ai);CHKERRQ(ierr); ierr = MatGetOwnershipRange(tao->jacobian_inequality,&jstart,&jend);CHKERRQ(ierr); for (i=jstart;i<jend;i++) { ierr = MatGetRow(tao->jacobian_inequality,i,&ncols,&cols,&vals);CHKERRQ(ierr); newrow = i; ierr = MatSetValues(ipmP->Ai,1,&newrow,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr); ierr = MatRestoreRow(tao->jacobian_inequality,i,&ncols,&cols,&vals);CHKERRQ(ierr); } } /* I w/ xlb */ if (ipmP->nxlb) { for (i=0;i<ipmP->nxlb;i++) { if (i>=astart && i<aend) { newrow = i+r2; newcol = i; newval = 1.0; ierr = MatSetValues(ipmP->Ai,1,&newrow,1,&newcol,&newval,INSERT_VALUES);CHKERRQ(ierr); } } } if (ipmP->nxub) { /* I w/ xub */ for (i=0;i<ipmP->nxub;i++) { if (i>=astart && i<aend) { newrow = i+r3; newcol = i; newval = -1.0; ierr = MatSetValues(ipmP->Ai,1,&newrow,1,&newcol,&newval,INSERT_VALUES);CHKERRQ(ierr); } } } ierr = MatAssemblyBegin(ipmP->Ai,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(ipmP->Ai,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); CHKMEMQ; ierr = VecSet(ipmP->ci,0.0);CHKERRQ(ierr); /* user ci */ if (ipmP->mi > 0) { ierr = VecScatterBegin(ipmP->ci_scat,tao->constraints_inequality,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(ipmP->ci_scat,tao->constraints_inequality,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); } if (!ipmP->work){ VecDuplicate(tao->solution,&ipmP->work); } ierr = VecCopy(tao->solution,ipmP->work);CHKERRQ(ierr); if (tao->XL) { ierr = VecAXPY(ipmP->work,-1.0,tao->XL);CHKERRQ(ierr); /* lower bounds on variables */ if (ipmP->nxlb > 0) { ierr = VecScatterBegin(ipmP->xl_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(ipmP->xl_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); } } if (tao->XU) { /* upper bounds on variables */ ierr = VecCopy(tao->solution,ipmP->work);CHKERRQ(ierr); ierr = VecScale(ipmP->work,-1.0);CHKERRQ(ierr); ierr = VecAXPY(ipmP->work,1.0,tao->XU);CHKERRQ(ierr); if (ipmP->nxub > 0) { ierr = VecScatterBegin(ipmP->xu_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(ipmP->xu_scat,ipmP->work,ipmP->ci,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); } } PetscFunctionReturn(0); }
int main(int argc,char **argv) { PetscErrorCode ierr; PetscViewer viewer; DM da; Vec global,local,global2; PetscMPIInt rank; PetscBool flg; /* Every PETSc routine should begin with the PetscInitialize() routine. argc, argv - These command line arguments are taken to extract the options supplied to PETSc and options supplied to MPI. help - When PETSc executable is invoked with the option -help, it prints the various options that can be applied at runtime. The user can use the "help" variable place additional help messages in this printout. */ ierr = PetscInitialize(&argc,&argv,(char *)0,help);CHKERRQ(ierr); /* Create a DMDA and an associated vector */ ierr = DMDACreate2d(PETSC_COMM_WORLD, DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_NONE,DMDA_STENCIL_BOX,100,90,PETSC_DECIDE,PETSC_DECIDE,2,1,PETSC_NULL,PETSC_NULL,&da);CHKERRQ(ierr); ierr = DMCreateGlobalVector(da,&global);CHKERRQ(ierr); ierr = DMCreateLocalVector(da,&local);CHKERRQ(ierr); ierr = VecSet(global,-1.0);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(da,global,INSERT_VALUES,local);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(da,global,INSERT_VALUES,local);CHKERRQ(ierr); ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr); ierr = VecScale(local,rank+1);CHKERRQ(ierr); ierr = DMLocalToGlobalBegin(da,local,ADD_VALUES,global);CHKERRQ(ierr); ierr = DMLocalToGlobalEnd(da,local,ADD_VALUES,global);CHKERRQ(ierr); /* Write output file with PetscViewerHDF5 viewer. */ ierr = PetscViewerHDF5Open(PETSC_COMM_WORLD,"hdf5output",FILE_MODE_WRITE,&viewer);CHKERRQ(ierr); ierr = VecView(global,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = MPI_Barrier(PETSC_COMM_WORLD);CHKERRQ(ierr); ierr = VecDuplicate(global,&global2);CHKERRQ(ierr); ierr = VecCopy(global,global2);CHKERRQ(ierr); ierr = PetscViewerHDF5Open(PETSC_COMM_WORLD,"hdf5output",FILE_MODE_READ,&viewer);CHKERRQ(ierr); ierr = VecLoad(global,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecEqual(global,global2,&flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(PETSC_COMM_WORLD,"Vectors are equal\n");CHKERRQ(ierr); } else { ierr = PetscPrintf(PETSC_COMM_WORLD,"Vectors are not equal\n");CHKERRQ(ierr); } /* clean up and exit */ ierr = DMDestroy(&da);CHKERRQ(ierr); ierr = VecDestroy(&local);CHKERRQ(ierr); ierr = VecDestroy(&global);CHKERRQ(ierr); ierr = VecDestroy(&global2);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }
int main(int argc,char **argv) { PetscErrorCode ierr; SNES snes; /* nonlinear solver */ Vec Hu,r; /* solution, residual vectors */ Mat J; /* Jacobian matrix */ AppCtx user; /* user-defined work context */ PetscInt its, i, tmpxs, tmpxm; /* iteration count, index, etc. */ PetscReal tmp1, tmp2, tmp3, tmp4, tmp5, errnorms[2], descaleNode[2]; PetscTruth eps_set = PETSC_FALSE, dump = PETSC_FALSE, exactinitial = PETSC_FALSE, snes_mf_set, snes_fd_set; MatFDColoring matfdcoloring = 0; ISColoring iscoloring; SNESConvergedReason reason; /* Check convergence */ PetscInitialize(&argc,&argv,(char *)0,help); ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &user.rank); CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "BODVARDSSON solves for thickness and velocity in 1D, steady ice stream\n" " [run with -help for info and options]\n");CHKERRQ(ierr); user.n = 3.0; /* Glen flow law exponent */ user.secpera = 31556926.0; user.rho = 910.0; /* kg m^-3 */ user.rhow = 1028.0; /* kg m^-3 */ user.g = 9.81; /* m s^-2 */ /* ask Test N for its parameters, but only those we need to solve */ ierr = params_exactN(&(user.H0), &tmp1, &(user.xc), &tmp2, &tmp3, &tmp4, &tmp5, &(user.Txc)); CHKERRQ(ierr); /* regularize using strain rate of 1/xc per year */ user.epsilon = (1.0 / user.secpera) / user.xc; /* tools for non-dimensionalizing to improve equation scaling */ user.scaleNode[0] = 1000.0; user.scaleNode[1] = 100.0 / user.secpera; ierr = PetscOptionsTruth("-snes_mf","","",PETSC_FALSE,&snes_mf_set,NULL);CHKERRQ(ierr); ierr = PetscOptionsTruth("-snes_fd","","",PETSC_FALSE,&snes_fd_set,NULL);CHKERRQ(ierr); if (!snes_mf_set && !snes_fd_set) { PetscPrintf(PETSC_COMM_WORLD, "\n***ERROR: bodvardsson needs one or zero of '-snes_mf', '-snes_fd'***\n\n" "USAGE FOLLOWS ...\n\n%s",help); PetscEnd(); } if (snes_fd_set) { ierr = PetscPrintf(PETSC_COMM_WORLD, " using approximate Jacobian; finite-differencing using coloring\n"); CHKERRQ(ierr); } else if (snes_mf_set) { ierr = PetscPrintf(PETSC_COMM_WORLD, " matrix free; no preconditioner\n"); CHKERRQ(ierr); } else { ierr = PetscPrintf(PETSC_COMM_WORLD, " true Jacobian\n"); CHKERRQ(ierr); } ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL, "bodvardsson program options",__FILE__);CHKERRQ(ierr); { ierr = PetscOptionsTruth("-bod_up_one","","",PETSC_FALSE,&user.upwind1,NULL);CHKERRQ(ierr); ierr = PetscOptionsTruth("-bod_exact_init","","",PETSC_FALSE,&exactinitial,NULL);CHKERRQ(ierr); ierr = PetscOptionsTruth("-bod_dump", "dump out exact and approximate solution and residual, as asci","", dump,&dump,NULL);CHKERRQ(ierr); ierr = PetscOptionsReal("-bod_epsilon","regularization (a strain rate in units of 1/a)","", user.epsilon * user.secpera,&user.epsilon,&eps_set);CHKERRQ(ierr); if (eps_set) user.epsilon *= 1.0 / user.secpera; } ierr = PetscOptionsEnd();CHKERRQ(ierr); /* Create machinery for parallel grid management (DA), nonlinear solver (SNES), and Vecs for fields (solution, RHS). Note default Mx=46 grid points means dx=10 km. Also degrees of freedom = 2 (thickness and velocity at each point) and stencil radius = ghost width = 2 for 2nd-order upwinding. */ user.solnghostwidth = 2; ierr = DACreate1d(PETSC_COMM_WORLD,DA_NONPERIODIC,-46,2,user.solnghostwidth,PETSC_NULL,&user.da); CHKERRQ(ierr); ierr = DASetUniformCoordinates(user.da,0.0,user.xc, PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); ierr = DASetFieldName(user.da,0,"ice thickness [non-dimensional]"); CHKERRQ(ierr); ierr = DASetFieldName(user.da,1,"ice velocity [non-dimensional]"); CHKERRQ(ierr); ierr = DAGetInfo(user.da,PETSC_IGNORE,&user.Mx,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE, PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE); ierr = DAGetCorners(user.da,&user.xs,PETSC_NULL,PETSC_NULL,&user.xm,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); user.dx = user.xc / (PetscReal)(user.Mx-1); /* another DA for scalar parameters, with same length */ ierr = DACreate1d(PETSC_COMM_WORLD,DA_NONPERIODIC,user.Mx,1,1,PETSC_NULL,&user.scalarda);CHKERRQ(ierr); ierr = DASetUniformCoordinates(user.scalarda,0.0,user.xc, PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); /* check that parallel layout of scalar DA is same as dof=2 DA */ ierr = DAGetCorners(user.scalarda,&tmpxs,PETSC_NULL,PETSC_NULL,&tmpxm,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); if ((tmpxs != user.xs) || (tmpxm != user.xm)) { PetscPrintf(PETSC_COMM_SELF, "\n***ERROR: rank %d gets different ownership range for the two DAs! ENDING ...***\n\n", user.rank); PetscEnd(); } ierr = PetscPrintf(PETSC_COMM_WORLD, " Mx = %D points, dx = %.3f m\n H0 = %.2f m, xc = %.2f km, Txc = %.5e Pa m\n", user.Mx, user.dx, user.H0, user.xc/1000.0, user.Txc);CHKERRQ(ierr); /* Extract/allocate global vectors from DAs and duplicate for remaining same types */ ierr = DACreateGlobalVector(user.da,&Hu);CHKERRQ(ierr); ierr = VecSetBlockSize(Hu,2);CHKERRQ(ierr); ierr = VecDuplicate(Hu,&r);CHKERRQ(ierr); /* inherits block size */ ierr = VecDuplicate(Hu,&user.Huexact);CHKERRQ(ierr); /* ditto */ ierr = DACreateGlobalVector(user.scalarda,&user.M);CHKERRQ(ierr); ierr = VecDuplicate(user.M,&user.Bstag);CHKERRQ(ierr); ierr = VecDuplicate(user.M,&user.beta);CHKERRQ(ierr); ierr = DASetLocalFunction(user.da,(DALocalFunction1)scshell);CHKERRQ(ierr); ierr = DASetLocalJacobian(user.da,(DALocalFunction1)BodJacobianMatrixLocal);CHKERRQ(ierr); ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr); ierr = SNESSetFunction(snes,r,SNESDAFormFunction,&user);CHKERRQ(ierr); /* setting up a matrix is only actually needed for -snes_fd case */ ierr = DAGetMatrix(user.da,MATAIJ,&J);CHKERRQ(ierr); if (snes_fd_set) { /* tools needed so DA can use sparse matrix for its F.D. Jacobian approx */ ierr = DAGetColoring(user.da,IS_COLORING_GLOBAL,MATAIJ,&iscoloring);CHKERRQ(ierr); ierr = MatFDColoringCreate(J,iscoloring,&matfdcoloring);CHKERRQ(ierr); ierr = ISColoringDestroy(iscoloring);CHKERRQ(ierr); ierr = MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode (*)(void))SNESDAFormFunction,&user);CHKERRQ(ierr); ierr = MatFDColoringSetFromOptions(matfdcoloring);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,J,J,SNESDefaultComputeJacobianColor,matfdcoloring);CHKERRQ(ierr); } else { ierr = SNESSetJacobian(snes,J,J,SNESDAComputeJacobian,&user);CHKERRQ(ierr); } ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); /* the the Bodvardsson (1955) exact solution allows setting M(x), B(x), beta(x), T(xc) */ ierr = FillDistributedParams(&user);CHKERRQ(ierr); /* the exact thickness and exact ice velocity (user.uHexact) are known from Bodvardsson (1955) */ ierr = FillExactSoln(&user); CHKERRQ(ierr); if (exactinitial) { ierr = PetscPrintf(PETSC_COMM_WORLD," using exact solution as initial guess\n"); CHKERRQ(ierr); /* the initial guess is the exact continuum solution */ ierr = VecCopy(user.Huexact,Hu); CHKERRQ(ierr); } else { ierr = FillInitial(&user, &Hu); CHKERRQ(ierr); } /************ SOLVE NONLINEAR SYSTEM ************/ /* recall that RHS r is used internally by KSP, and is set by the SNES */ for (i = 0; i < 2; i++) descaleNode[i] = 1.0 / user.scaleNode[i]; ierr = VecStrideScaleAll(Hu,descaleNode); CHKERRQ(ierr); /* de-dimensionalize initial guess */ ierr = SNESSolve(snes,PETSC_NULL,Hu);CHKERRQ(ierr); ierr = VecStrideScaleAll(Hu,user.scaleNode); CHKERRQ(ierr); /* put back in "real" scale */ ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr); ierr = SNESGetConvergedReason(snes,&reason);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, " %s Number of Newton iterations = %D\n", SNESConvergedReasons[reason],its);CHKERRQ(ierr); if (dump) { ierr = PetscPrintf(PETSC_COMM_WORLD, " viewing combined result Hu\n");CHKERRQ(ierr); ierr = VecView(Hu,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, " viewing combined exact result Huexact\n");CHKERRQ(ierr); ierr = VecView(user.Huexact,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, " viewing final combined residual at Hu\n");CHKERRQ(ierr); ierr = VecView(r,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr); } /* evaluate error relative to exact solution */ ierr = VecAXPY(Hu,-1.0,user.Huexact); CHKERRQ(ierr); /* Hu = - Huexact + Hu */ ierr = VecStrideNormAll(Hu,NORM_INFINITY,errnorms); CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "(dx,errHinf,erruinf) %.3f %.4e %.4e\n", user.dx,errnorms[0],errnorms[1]*user.secpera);CHKERRQ(ierr); ierr = VecDestroy(Hu);CHKERRQ(ierr); ierr = VecDestroy(r);CHKERRQ(ierr); ierr = VecDestroy(user.Huexact);CHKERRQ(ierr); ierr = VecDestroy(user.M);CHKERRQ(ierr); ierr = VecDestroy(user.Bstag);CHKERRQ(ierr); ierr = VecDestroy(user.beta);CHKERRQ(ierr); ierr = MatDestroy(J); CHKERRQ(ierr); ierr = SNESDestroy(snes);CHKERRQ(ierr); ierr = DADestroy(user.da);CHKERRQ(ierr); ierr = DADestroy(user.scalarda);CHKERRQ(ierr); ierr = PetscFinalize();CHKERRQ(ierr); return 0; }
/** Caculate the flux using the Monotonic Upstream-Centered Scheme for Conservation Laws (van Leer, 1979) */ PetscErrorCode CaculateLocalFunction_LS(DM dm,DM dmFace,DM dmCell,PetscReal time,Vec locX,Vec F,User user) { DM dmGrad = user->dmGrad; Model mod = user->model; Physics phys = mod->physics; const PetscInt dof = phys->dof; PetscErrorCode ierr; const PetscScalar *facegeom, *cellgeom, *x; PetscScalar *f; PetscInt fStart, fEnd, face, cStart, cell; Vec locGrad, locGradLimiter, Grad; /* Here the localGradLimiter refers to the gradient that has been multiplied by the limiter function. The locGradLimiter is used to construct the uL and uR, and the locGrad is used to caculate the diffusion term */ Vec TempVec; /*a temperal vec for the vector restore*/ PetscFunctionBeginUser; ierr = DMGetGlobalVector(dmGrad,&Grad);CHKERRQ(ierr); ierr = VecDuplicate(Grad, &TempVec);CHKERRQ(ierr); ierr = VecCopy(Grad, TempVec);CHKERRQ(ierr); /* Backup the original vector and use it to restore the value of dmGrad, because I do not want to change the values of the cell gradient. */ ierr = VecGetArrayRead(user->facegeom,&facegeom);CHKERRQ(ierr); ierr = VecGetArrayRead(user->cellgeom,&cellgeom);CHKERRQ(ierr); ierr = VecGetArrayRead(locX,&x);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr); { PetscScalar *grad; ierr = VecGetArray(Grad,&grad);CHKERRQ(ierr); const PetscInt *faces; PetscInt numFaces,f; PetscReal *cellPhi; // Scalar limiter applied to each component separately const PetscScalar *cx; const CellGeom *cg; PetscScalar *cgrad; PetscInt i; ierr = PetscMalloc(phys->dof*sizeof(PetscScalar),&cellPhi);CHKERRQ(ierr); // Limit interior gradients. Using cell-based loop because it generalizes better to vector limiters. for (cell=cStart; cell<user->cEndInterior; cell++) { ierr = DMPlexGetConeSize(dm,cell,&numFaces);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,cell,&faces);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dm,cell,x,&cx);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dmCell,cell,cellgeom,&cg);CHKERRQ(ierr); ierr = DMPlexPointGlobalRef(dmGrad,cell,grad,&cgrad);CHKERRQ(ierr); if (!cgrad) continue; // ghost cell, we don't compute // Limiter will be minimum value over all neighbors for (i=0; i<dof; i++) cellPhi[i] = PETSC_MAX_REAL; for (f=0; f<numFaces; f++) { const PetscScalar *ncx; const CellGeom *ncg; const PetscInt *fcells; PetscInt face = faces[f],ncell; PetscScalar v[DIM]; PetscBool ghost; ierr = IsExteriorGhostFace(dm,face,&ghost);CHKERRQ(ierr); if (ghost) continue; ierr = DMPlexGetSupport(dm,face,&fcells);CHKERRQ(ierr); ncell = cell == fcells[0] ? fcells[1] : fcells[0]; // The expression (x ? y : z) has the value of y if x is nonzero, z otherwise ierr = DMPlexPointLocalRead(dm,ncell,x,&ncx);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dmCell,ncell,cellgeom,&ncg);CHKERRQ(ierr); Waxpy2(-1, cg->centroid, ncg->centroid, v); for (i=0; i<dof; i++) { // We use the symmetric slope limited form of Berger, Aftosmis, and Murman 2005 PetscScalar phi,flim = 0.5 * (ncx[i] - cx[i]) / Dot2(&cgrad[i*DIM],v); phi = (*user->Limit)(flim); cellPhi[i] = PetscMin(cellPhi[i],phi); } } // Apply limiter to gradient for (i=0; i<dof; i++) Scale2(cellPhi[i],&cgrad[i*DIM],&cgrad[i*DIM]); } ierr = PetscFree(cellPhi);CHKERRQ(ierr); ierr = VecRestoreArray(Grad,&grad);CHKERRQ(ierr); } ierr = DMGetLocalVector(dmGrad,&locGradLimiter);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(dmGrad,Grad,INSERT_VALUES,locGradLimiter);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(dmGrad,Grad,INSERT_VALUES,locGradLimiter);CHKERRQ(ierr); ierr = VecCopy(TempVec, Grad);CHKERRQ(ierr);//Restore the vector ierr = DMGetLocalVector(dmGrad,&locGrad);CHKERRQ(ierr); ierr = DMGlobalToLocalBegin(dmGrad,Grad,INSERT_VALUES,locGrad);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(dmGrad,Grad,INSERT_VALUES,locGrad);CHKERRQ(ierr); ierr = DMRestoreGlobalVector(dmGrad,&Grad);CHKERRQ(ierr); ierr = VecDestroy(&TempVec);CHKERRQ(ierr); { const PetscScalar *grad, *gradlimiter; const PetscInt *cells; PetscInt ghost,i,j; PetscScalar *fluxcon, *fluxdiff, *fx[2],*cf[2]; const FaceGeom *fg; const CellGeom *cg[2]; const PetscScalar *cx[2],*cgrad[2], *cgradlimiter[2]; PetscScalar *uL, *uR; PetscReal FaceArea; ierr = VecGetArrayRead(locGrad,&grad);CHKERRQ(ierr); ierr = VecGetArrayRead(locGradLimiter,&gradlimiter);CHKERRQ(ierr); ierr = VecGetArray(F,&f);CHKERRQ(ierr); ierr = PetscMalloc(phys->dof * sizeof(PetscScalar), &fluxcon);CHKERRQ(ierr); // For the convection terms ierr = PetscMalloc(phys->dof * sizeof(PetscScalar), &fluxdiff);CHKERRQ(ierr); // For the diffusion terms ierr = PetscMalloc(phys->dof * sizeof(PetscScalar), &uL);CHKERRQ(ierr); ierr = PetscMalloc(phys->dof * sizeof(PetscScalar), &uR);CHKERRQ(ierr);// Please do not put the Malloc function into a for loop!!!! for (face=fStart; face<fEnd; face++) { fx[0] = uL; fx[1] = uR; ierr = DMPlexGetLabelValue(dm, "ghost", face, &ghost);CHKERRQ(ierr); if (ghost >= 0) continue; ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dmFace,face,facegeom,&fg);CHKERRQ(ierr); for (i=0; i<2; i++) { PetscScalar dx[DIM]; ierr = DMPlexPointLocalRead(dmCell,cells[i],cellgeom,&cg[i]);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dm,cells[i],x,&cx[i]);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dmGrad,cells[i],gradlimiter,&cgradlimiter[i]);CHKERRQ(ierr); ierr = DMPlexPointLocalRead(dmGrad,cells[i],grad,&cgrad[i]);CHKERRQ(ierr); ierr = DMPlexPointGlobalRef(dm,cells[i],f,&cf[i]);CHKERRQ(ierr); Waxpy2(-1,cg[i]->centroid,fg->centroid,dx); for (j=0; j<dof; j++) { fx[i][j] = cx[i][j] + Dot2(cgradlimiter[i],dx); } // fx[0] and fx[1] are the value of the variables on the left and right // side of the face, respectively, that is u_L and u_R. } ierr = RiemannSolver_Rusanov(user, cgrad[0], cgrad[1], fg->centroid, cg[0]->centroid, cg[1]->centroid, fg->normal, fx[0], fx[1], fluxcon, fluxdiff);CHKERRQ(ierr); ierr = DMPlexComputeCellGeometryFVM(dm, face, &FaceArea, NULL, NULL);CHKERRQ(ierr); // Compute the face area for (i=0; i<phys->dof; i++) { if (cf[0]) cf[0][i] -= FaceArea*(fluxcon[i] + fluxdiff[i])/cg[0]->volume; if (cf[1]) cf[1][i] += FaceArea*(fluxcon[i] + fluxdiff[i])/cg[1]->volume; // The flux on the interface, for the cell[0], it is an outcome flux and for the cell[1], it is // an income flux. } // ierr = PetscPrintf(PETSC_COMM_WORLD,"\n");CHKERRQ(ierr); } ierr = VecRestoreArrayRead(locGrad,&grad);CHKERRQ(ierr); ierr = VecRestoreArrayRead(locGradLimiter,&gradlimiter);CHKERRQ(ierr); ierr = VecRestoreArray(F,&f);CHKERRQ(ierr); ierr = PetscFree(fluxcon);CHKERRQ(ierr); ierr = PetscFree(fluxdiff);CHKERRQ(ierr); ierr = PetscFree(uL);CHKERRQ(ierr); ierr = PetscFree(uR);CHKERRQ(ierr); // VecView(F,PETSC_VIEWER_STDOUT_WORLD); } ierr = VecRestoreArrayRead(user->facegeom,&facegeom);CHKERRQ(ierr); ierr = VecRestoreArrayRead(user->cellgeom,&cellgeom);CHKERRQ(ierr); ierr = VecRestoreArrayRead(locX,&x);CHKERRQ(ierr); ierr = DMRestoreLocalVector(dmGrad,&locGradLimiter);CHKERRQ(ierr); ierr = DMRestoreLocalVector(dmGrad,&locGrad);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode KSPSolve_CG(KSP ksp) { PetscErrorCode ierr; PetscInt i,stored_max_it,eigs; PetscScalar dpi = 0.0,a = 1.0,beta,betaold = 1.0,b = 0,*e = 0,*d = 0,delta,dpiold; PetscReal dp = 0.0; Vec X,B,Z,R,P,S,W; KSP_CG *cg; Mat Amat,Pmat; MatStructure pflag; PetscBool diagonalscale; PetscFunctionBegin; ierr = PCGetDiagonalScale(ksp->pc,&diagonalscale);CHKERRQ(ierr); if (diagonalscale) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name); cg = (KSP_CG*)ksp->data; eigs = ksp->calc_sings; stored_max_it = ksp->max_it; X = ksp->vec_sol; B = ksp->vec_rhs; R = ksp->work[0]; Z = ksp->work[1]; P = ksp->work[2]; if (cg->singlereduction) { S = ksp->work[3]; W = ksp->work[4]; } else { S = 0; /* unused */ W = Z; } #define VecXDot(x,y,a) (((cg->type) == (KSP_CG_HERMITIAN)) ? VecDot(x,y,a) : VecTDot(x,y,a)) if (eigs) {e = cg->e; d = cg->d; e[0] = 0.0; } ierr = PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);CHKERRQ(ierr); ksp->its = 0; if (!ksp->guess_zero) { ierr = KSP_MatMult(ksp,Amat,X,R);CHKERRQ(ierr); /* r <- b - Ax */ ierr = VecAYPX(R,-1.0,B);CHKERRQ(ierr); } else { ierr = VecCopy(B,R);CHKERRQ(ierr); /* r <- b (x is 0) */ } switch (ksp->normtype) { case KSP_NORM_PRECONDITIONED: ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ ierr = VecNorm(Z,NORM_2,&dp);CHKERRQ(ierr); /* dp <- z'*z = e'*A'*B'*B*A'*e' */ break; case KSP_NORM_UNPRECONDITIONED: ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- r'*r = e'*A'*A*e */ break; case KSP_NORM_NATURAL: ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ if (cg->singlereduction) { ierr = KSP_MatMult(ksp,Amat,Z,S);CHKERRQ(ierr); ierr = VecXDot(Z,S,&delta);CHKERRQ(ierr); } ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); /* beta <- z'*r */ if (PetscIsInfOrNanScalar(beta)) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); dp = PetscSqrtReal(PetscAbsScalar(beta)); /* dp <- r'*z = r'*B*r = e'*A'*B*A*e */ break; case KSP_NORM_NONE: dp = 0.0; break; default: SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]); } KSPLogResidualHistory(ksp,dp); ierr = KSPMonitor(ksp,0,dp);CHKERRQ(ierr); ksp->rnorm = dp; ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); /* test for convergence */ if (ksp->reason) PetscFunctionReturn(0); if (ksp->normtype != KSP_NORM_PRECONDITIONED && (ksp->normtype != KSP_NORM_NATURAL)){ ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ } if (ksp->normtype != KSP_NORM_NATURAL){ if (cg->singlereduction) { ierr = KSP_MatMult(ksp,Amat,Z,S);CHKERRQ(ierr); ierr = VecXDot(Z,S,&delta);CHKERRQ(ierr); } ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); /* beta <- z'*r */ if (PetscIsInfOrNanScalar(beta)) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); } i = 0; do { ksp->its = i+1; if (beta == 0.0) { ksp->reason = KSP_CONVERGED_ATOL; ierr = PetscInfo(ksp,"converged due to beta = 0\n");CHKERRQ(ierr); break; #if !defined(PETSC_USE_COMPLEX) } else if ((i > 0) && (beta*betaold < 0.0)) { ksp->reason = KSP_DIVERGED_INDEFINITE_PC; ierr = PetscInfo(ksp,"diverging due to indefinite preconditioner\n");CHKERRQ(ierr); break; #endif } if (!i) { ierr = VecCopy(Z,P);CHKERRQ(ierr); /* p <- z */ b = 0.0; } else { b = beta/betaold; if (eigs) { if (ksp->max_it != stored_max_it) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_SUP,"Can not change maxit AND calculate eigenvalues"); e[i] = PetscSqrtReal(PetscAbsScalar(b))/a; } ierr = VecAYPX(P,b,Z);CHKERRQ(ierr); /* p <- z + b* p */ } dpiold = dpi; if (!cg->singlereduction || !i) { ierr = KSP_MatMult(ksp,Amat,P,W);CHKERRQ(ierr); /* w <- Ap */ ierr = VecXDot(P,W,&dpi);CHKERRQ(ierr); /* dpi <- p'w */ } else { ierr = VecAYPX(W,beta/betaold,S);CHKERRQ(ierr); /* w <- Ap */ dpi = delta - beta*beta*dpiold/(betaold*betaold); /* dpi <- p'w */ } betaold = beta; if (PetscIsInfOrNanScalar(dpi)) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); if ((dpi == 0.0) || ((i > 0) && (PetscRealPart(dpi*dpiold) <= 0.0))) { ksp->reason = KSP_DIVERGED_INDEFINITE_MAT; ierr = PetscInfo(ksp,"diverging due to indefinite or negative definite matrix\n");CHKERRQ(ierr); break; } a = beta/dpi; /* a = beta/p'w */ if (eigs) { d[i] = PetscSqrtReal(PetscAbsScalar(b))*e[i] + 1.0/a; } ierr = VecAXPY(X,a,P);CHKERRQ(ierr); /* x <- x + ap */ ierr = VecAXPY(R,-a,W);CHKERRQ(ierr); /* r <- r - aw */ if (ksp->normtype == KSP_NORM_PRECONDITIONED && ksp->chknorm < i+2) { ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ if (cg->singlereduction) { ierr = KSP_MatMult(ksp,Amat,Z,S);CHKERRQ(ierr); } ierr = VecNorm(Z,NORM_2,&dp);CHKERRQ(ierr); /* dp <- z'*z */ } else if (ksp->normtype == KSP_NORM_UNPRECONDITIONED && ksp->chknorm < i+2) { ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr); /* dp <- r'*r */ } else if (ksp->normtype == KSP_NORM_NATURAL) { ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ if (cg->singlereduction) { PetscScalar tmp[2]; Vec vecs[2]; vecs[0] = S; vecs[1] = R; ierr = KSP_MatMult(ksp,Amat,Z,S);CHKERRQ(ierr); /*ierr = VecXDot(Z,S,&delta);CHKERRQ(ierr); ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); */ /* beta <- r'*z */ ierr = VecMDot(Z,2,vecs,tmp);CHKERRQ(ierr); delta = tmp[0]; beta = tmp[1]; } else { ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); /* beta <- r'*z */ } if (PetscIsInfOrNanScalar(beta)) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); dp = PetscSqrtReal(PetscAbsScalar(beta)); } else { dp = 0.0; } ksp->rnorm = dp; KSPLogResidualHistory(ksp,dp); ierr = KSPMonitor(ksp,i+1,dp);CHKERRQ(ierr); ierr = (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr); if (ksp->reason) break; if ((ksp->normtype != KSP_NORM_PRECONDITIONED && (ksp->normtype != KSP_NORM_NATURAL)) || (ksp->chknorm >= i+2)){ ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr); /* z <- Br */ if (cg->singlereduction) { ierr = KSP_MatMult(ksp,Amat,Z,S);CHKERRQ(ierr); } } if ((ksp->normtype != KSP_NORM_NATURAL) || (ksp->chknorm >= i+2)){ if (cg->singlereduction) { PetscScalar tmp[2]; Vec vecs[2]; vecs[0] = S; vecs[1] = R; /* ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); */ /* beta <- z'*r */ /* ierr = VecXDot(Z,S,&delta);CHKERRQ(ierr);*/ ierr = VecMDot(Z,2,vecs,tmp);CHKERRQ(ierr); delta = tmp[0]; beta = tmp[1]; } else { ierr = VecXDot(Z,R,&beta);CHKERRQ(ierr); /* beta <- z'*r */ } if (PetscIsInfOrNanScalar(beta)) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_FP,"Infinite or not-a-number generated in dot product"); } i++; } while (i<ksp->max_it); if (i >= ksp->max_it) { ksp->reason = KSP_DIVERGED_ITS; } 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); }
/*@C TaoVecGetSubVec - Gets a subvector using the IS Input Parameters: + vfull - the full matrix . is - the index set for the subvector . reduced_type - the method TAO is using for subsetting (TAO_SUBSET_SUBVEC, TAO_SUBSET_MASK, TAO_SUBSET_MATRIXFREE) - maskvalue - the value to set the unused vector elements to (for TAO_SUBSET_MASK or TAO_SUBSET_MATRIXFREE) Output Parameters: . vreduced - the subvector Note: maskvalue should usually be 0.0, unless a pointwise divide will be used. @*/ PetscErrorCode TaoVecGetSubVec(Vec vfull, IS is, TaoSubsetType reduced_type, PetscReal maskvalue, Vec *vreduced) { PetscErrorCode ierr; PetscInt nfull,nreduced,nreduced_local,rlow,rhigh,flow,fhigh; PetscInt i,nlocal; PetscReal *fv,*rv; const PetscInt *s; IS ident; VecType vtype; VecScatter scatter; MPI_Comm comm; PetscFunctionBegin; PetscValidHeaderSpecific(vfull,VEC_CLASSID,1); PetscValidHeaderSpecific(is,IS_CLASSID,2); ierr = VecGetSize(vfull, &nfull);CHKERRQ(ierr); ierr = ISGetSize(is, &nreduced);CHKERRQ(ierr); if (nreduced == nfull) { ierr = VecDestroy(vreduced);CHKERRQ(ierr); ierr = VecDuplicate(vfull,vreduced);CHKERRQ(ierr); ierr = VecCopy(vfull,*vreduced);CHKERRQ(ierr); } else { switch (reduced_type) { case TAO_SUBSET_SUBVEC: ierr = VecGetType(vfull,&vtype);CHKERRQ(ierr); ierr = VecGetOwnershipRange(vfull,&flow,&fhigh);CHKERRQ(ierr); ierr = ISGetLocalSize(is,&nreduced_local);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)vfull,&comm);CHKERRQ(ierr); if (*vreduced) { ierr = VecDestroy(vreduced);CHKERRQ(ierr); } ierr = VecCreate(comm,vreduced);CHKERRQ(ierr); ierr = VecSetType(*vreduced,vtype);CHKERRQ(ierr); ierr = VecSetSizes(*vreduced,nreduced_local,nreduced);CHKERRQ(ierr); ierr = VecGetOwnershipRange(*vreduced,&rlow,&rhigh);CHKERRQ(ierr); ierr = ISCreateStride(comm,nreduced_local,rlow,1,&ident);CHKERRQ(ierr); ierr = VecScatterCreate(vfull,is,*vreduced,ident,&scatter);CHKERRQ(ierr); ierr = VecScatterBegin(scatter,vfull,*vreduced,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterEnd(scatter,vfull,*vreduced,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecScatterDestroy(&scatter);CHKERRQ(ierr); ierr = ISDestroy(&ident);CHKERRQ(ierr); break; case TAO_SUBSET_MASK: case TAO_SUBSET_MATRIXFREE: /* vr[i] = vf[i] if i in is vr[i] = 0 otherwise */ if (*vreduced == NULL) { ierr = VecDuplicate(vfull,vreduced);CHKERRQ(ierr); } ierr = VecSet(*vreduced,maskvalue);CHKERRQ(ierr); ierr = ISGetLocalSize(is,&nlocal);CHKERRQ(ierr); ierr = VecGetOwnershipRange(vfull,&flow,&fhigh);CHKERRQ(ierr); ierr = VecGetArray(vfull,&fv);CHKERRQ(ierr); ierr = VecGetArray(*vreduced,&rv);CHKERRQ(ierr); ierr = ISGetIndices(is,&s);CHKERRQ(ierr); if (nlocal > (fhigh-flow)) SETERRQ2(PETSC_COMM_WORLD,1,"IS local size %d > Vec local size %d",nlocal,fhigh-flow); for (i=0;i<nlocal;i++) { rv[s[i]-flow] = fv[s[i]-flow]; } ierr = ISRestoreIndices(is,&s);CHKERRQ(ierr); ierr = VecRestoreArray(vfull,&fv);CHKERRQ(ierr); ierr = VecRestoreArray(*vreduced,&rv);CHKERRQ(ierr); break; } } PetscFunctionReturn(0); }
static PetscErrorCode SNESLineSearchApply_Basic(SNESLineSearch linesearch) { PetscBool changed_y, changed_w; PetscErrorCode ierr; Vec X, F, Y, W; SNES snes; PetscReal gnorm, xnorm, ynorm, lambda; PetscBool domainerror; PetscFunctionBegin; ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, NULL);CHKERRQ(ierr); ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr); ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr); ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr); ierr = SNESLineSearchSetSuccess(linesearch, PETSC_TRUE);CHKERRQ(ierr); /* precheck */ ierr = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr); /* update */ ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } /* postcheck */ ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr); if (changed_y) { ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); if (linesearch->ops->viproject) { ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); } } if (linesearch->norms || snes->iter < snes->max_its-1) { ierr = (*linesearch->ops->snesfunc)(snes,W,F);CHKERRQ(ierr); ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); if (domainerror) { ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); PetscFunctionReturn(0); } } if (linesearch->norms) { if (!linesearch->ops->vinorm) VecNormBegin(F, NORM_2, &linesearch->fnorm); ierr = VecNormBegin(Y, NORM_2, &linesearch->ynorm);CHKERRQ(ierr); ierr = VecNormBegin(W, NORM_2, &linesearch->xnorm);CHKERRQ(ierr); if (!linesearch->ops->vinorm) VecNormEnd(F, NORM_2, &linesearch->fnorm); ierr = VecNormEnd(Y, NORM_2, &linesearch->ynorm);CHKERRQ(ierr); ierr = VecNormEnd(W, NORM_2, &linesearch->xnorm);CHKERRQ(ierr); if (linesearch->ops->vinorm) { linesearch->fnorm = gnorm; ierr = (*linesearch->ops->vinorm)(snes, F, W, &linesearch->fnorm);CHKERRQ(ierr); } else { ierr = VecNorm(F,NORM_2,&linesearch->fnorm);CHKERRQ(ierr); } } /* copy the solution over */ ierr = VecCopy(W, X);CHKERRQ(ierr); PetscFunctionReturn(0); }
int main(int argc,char **args) { Mat C; PetscInt i,j,m = 3,n = 3,Ii,J; PetscErrorCode ierr; PetscBool flg; PetscScalar v; IS perm,iperm; Vec x,u,b,y; PetscReal norm,tol=PETSC_SMALL; MatFactorInfo info; PetscMPIInt size; ierr = PetscInitialize(&argc,&args,(char*)0,help);if (ierr) return ierr; ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr); if (size != 1) SETERRQ(PETSC_COMM_WORLD,1,"This is a uniprocessor example only!"); ierr = MatCreate(PETSC_COMM_WORLD,&C);CHKERRQ(ierr); ierr = MatSetSizes(C,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n);CHKERRQ(ierr); ierr = MatSetFromOptions(C);CHKERRQ(ierr); ierr = MatSetUp(C);CHKERRQ(ierr); ierr = PetscOptionsHasName(NULL,NULL,"-symmetric",&flg);CHKERRQ(ierr); if (flg) { /* Treat matrix as symmetric only if we set this flag */ ierr = MatSetOption(C,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr); ierr = MatSetOption(C,MAT_SYMMETRY_ETERNAL,PETSC_TRUE);CHKERRQ(ierr); } /* Create the matrix for the five point stencil, YET AGAIN */ for (i=0; i<m; i++) { for (j=0; j<n; j++) { v = -1.0; Ii = j + n*i; if (i>0) {J = Ii - n; ierr = MatSetValues(C,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);} if (i<m-1) {J = Ii + n; ierr = MatSetValues(C,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);} if (j>0) {J = Ii - 1; ierr = MatSetValues(C,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);} if (j<n-1) {J = Ii + 1; ierr = MatSetValues(C,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);} v = 4.0; ierr = MatSetValues(C,1,&Ii,1,&Ii,&v,INSERT_VALUES);CHKERRQ(ierr); } } ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatGetOrdering(C,MATORDERINGRCM,&perm,&iperm);CHKERRQ(ierr); ierr = MatView(C,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = ISView(perm,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); ierr = VecCreateSeq(PETSC_COMM_SELF,m*n,&u);CHKERRQ(ierr); ierr = VecSet(u,1.0);CHKERRQ(ierr); ierr = VecDuplicate(u,&x);CHKERRQ(ierr); ierr = VecDuplicate(u,&b);CHKERRQ(ierr); ierr = VecDuplicate(u,&y);CHKERRQ(ierr); ierr = MatMult(C,u,b);CHKERRQ(ierr); ierr = VecCopy(b,y);CHKERRQ(ierr); ierr = VecScale(y,2.0);CHKERRQ(ierr); ierr = MatNorm(C,NORM_FROBENIUS,&norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_SELF,"Frobenius norm of matrix %g\n",(double)norm);CHKERRQ(ierr); ierr = MatNorm(C,NORM_1,&norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_SELF,"One norm of matrix %g\n",(double)norm);CHKERRQ(ierr); ierr = MatNorm(C,NORM_INFINITY,&norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_SELF,"Infinity norm of matrix %g\n",(double)norm);CHKERRQ(ierr); ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr); info.fill = 2.0; info.dtcol = 0.0; info.zeropivot = 1.e-14; info.pivotinblocks = 1.0; ierr = MatLUFactor(C,perm,iperm,&info);CHKERRQ(ierr); /* Test MatSolve */ ierr = MatSolve(C,b,x);CHKERRQ(ierr); ierr = VecView(b,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); ierr = VecView(x,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr); ierr = VecAXPY(x,-1.0,u);CHKERRQ(ierr); ierr = VecNorm(x,NORM_2,&norm);CHKERRQ(ierr); if (norm > tol) { ierr = PetscPrintf(PETSC_COMM_SELF,"MatSolve: Norm of error %g\n",(double)norm);CHKERRQ(ierr); } /* Test MatSolveAdd */ ierr = MatSolveAdd(C,b,y,x);CHKERRQ(ierr); ierr = VecAXPY(x,-1.0,y);CHKERRQ(ierr); ierr = VecAXPY(x,-1.0,u);CHKERRQ(ierr); ierr = VecNorm(x,NORM_2,&norm);CHKERRQ(ierr); if (norm > tol) { ierr = PetscPrintf(PETSC_COMM_SELF,"MatSolveAdd(): Norm of error %g\n",(double)norm);CHKERRQ(ierr); } ierr = ISDestroy(&perm);CHKERRQ(ierr); ierr = ISDestroy(&iperm);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&y);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = MatDestroy(&C);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; }
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); }
PetscErrorCode test_vec_ops(void) { Vec X,Y,a,b; Vec c,d,e,f,g,h; PetscScalar val; PetscErrorCode ierr; PetscInt tmp_ind[2]; Vec tmp_buf[2]; PetscFunctionBegin; ierr = PetscPrintf(PETSC_COMM_WORLD, "============== %s ==============\n",PETSC_FUNCTION_NAME);CHKERRQ(ierr); /* create 4 slave vectors */ ierr = VecCreate(PETSC_COMM_WORLD, &c);CHKERRQ(ierr); ierr = VecSetSizes(c, PETSC_DECIDE, 4);CHKERRQ(ierr); ierr = VecSetType(c, VECMPI);CHKERRQ(ierr); ierr = VecDuplicate(c, &d);CHKERRQ(ierr); ierr = VecDuplicate(c, &e);CHKERRQ(ierr); ierr = VecDuplicate(c, &f);CHKERRQ(ierr); /* create two more slaves of different sizes */ ierr = VecCreate(PETSC_COMM_WORLD, &g);CHKERRQ(ierr); ierr = VecSetSizes(g, PETSC_DECIDE, 6);CHKERRQ(ierr); ierr = VecSetType(g, VECMPI);CHKERRQ(ierr); ierr = VecCreate(PETSC_COMM_WORLD, &h);CHKERRQ(ierr); ierr = VecSetSizes(h, PETSC_DECIDE, 8);CHKERRQ(ierr); ierr = VecSetType(h, VECMPI);CHKERRQ(ierr); /* set the 6 vectors to some numbers */ ierr = VecSet(c, 1.0);CHKERRQ(ierr); ierr = VecSet(d, 2.0);CHKERRQ(ierr); ierr = VecSet(e, 3.0);CHKERRQ(ierr); ierr = VecSet(f, 4.0);CHKERRQ(ierr); ierr = VecSet(g, 5.0);CHKERRQ(ierr); ierr = VecSet(h, 6.0);CHKERRQ(ierr); /* assemble a */ ierr = PetscPrintf(PETSC_COMM_WORLD, "a = [c d] \n");CHKERRQ(ierr); tmp_buf[0] = c; tmp_buf[1] = d; ierr = VecCreateNest(PETSC_COMM_WORLD,2,NULL,tmp_buf,&a);CHKERRQ(ierr); ierr = VecView(a,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "a = [d c] \n");CHKERRQ(ierr); ierr = VecNestSetSubVec(a, 1, c);CHKERRQ(ierr); ierr = VecNestSetSubVec(a, 0, d);CHKERRQ(ierr); ierr = VecAssemblyBegin(a);CHKERRQ(ierr); ierr = VecAssemblyEnd(a);CHKERRQ(ierr); ierr = VecView(a,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); /* assemble b */ ierr = PetscPrintf(PETSC_COMM_WORLD, "b = [e f] \n");CHKERRQ(ierr); tmp_buf[0] = e; tmp_buf[1] = f; ierr = VecCreateNest(PETSC_COMM_WORLD,2,NULL,tmp_buf,&b);CHKERRQ(ierr); ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "b = [f e] \n");CHKERRQ(ierr); ierr = VecNestSetSubVec(b, 1, e);CHKERRQ(ierr); ierr = VecNestSetSubVec(b, 0, f);CHKERRQ(ierr); ierr = VecAssemblyBegin(b);CHKERRQ(ierr); ierr = VecAssemblyEnd(b);CHKERRQ(ierr); ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "X = [a b] \n");CHKERRQ(ierr); tmp_buf[0] = a; tmp_buf[1] = b; ierr = VecCreateNest(PETSC_COMM_WORLD,2,NULL,tmp_buf,&X);CHKERRQ(ierr); ierr = VecView(X,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecDot(X,X, &val);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "X.X = %g \n", (double)PetscRealPart(val));CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "X = [b a] \n");CHKERRQ(ierr); /* re-order components of X */ ierr = VecNestSetSubVec(X,1,a);CHKERRQ(ierr); ierr = VecNestSetSubVec(X,0,b);CHKERRQ(ierr); ierr = VecAssemblyBegin(X);CHKERRQ(ierr); ierr = VecAssemblyEnd(X);CHKERRQ(ierr); ierr = VecView(X,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecDot(X,X,&val);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "X.X = %g \n", (double)PetscRealPart(val));CHKERRQ(ierr); /* re-assemble X */ ierr = PetscPrintf(PETSC_COMM_WORLD, "X = [g h] \n");CHKERRQ(ierr); ierr = VecNestSetSubVec(X,1,g);CHKERRQ(ierr); ierr = VecNestSetSubVec(X,0,h);CHKERRQ(ierr); ierr = VecAssemblyBegin(X);CHKERRQ(ierr); ierr = VecAssemblyEnd(X);CHKERRQ(ierr); ierr = VecView(X,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecDot(X,X,&val);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "X.X = %g \n", (double)PetscRealPart(val));CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Y = X \n");CHKERRQ(ierr); ierr = VecDuplicate(X, &Y);CHKERRQ(ierr); ierr = VecCopy(X,Y);CHKERRQ(ierr); ierr = VecView(Y,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecDot(Y,Y,&val);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Y.Y = %g \n", (double)PetscRealPart(val));CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "Y = [a b] \n");CHKERRQ(ierr); tmp_buf[0] = a; tmp_buf[1] = b; tmp_ind[0] = 0; tmp_ind[1] = 1; ierr = VecNestSetSubVecs(Y,2,tmp_ind,tmp_buf);CHKERRQ(ierr); ierr = VecView(Y,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = VecDestroy(&c);CHKERRQ(ierr); ierr = VecDestroy(&d);CHKERRQ(ierr); ierr = VecDestroy(&e);CHKERRQ(ierr); ierr = VecDestroy(&f);CHKERRQ(ierr); ierr = VecDestroy(&g);CHKERRQ(ierr); ierr = VecDestroy(&h);CHKERRQ(ierr); ierr = VecDestroy(&a);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = VecDestroy(&X);CHKERRQ(ierr); ierr = VecDestroy(&Y);CHKERRQ(ierr); PetscFunctionReturn(0); }