138774f0aSPeter Brune #include <../src/snes/impls/ngmres/snesngmres.h> /*I "petscsnes.h" I*/ 238774f0aSPeter Brune #include <petscblaslapack.h> 338774f0aSPeter Brune 49371c9d4SSatish Balay PetscErrorCode SNESNGMRESUpdateSubspace_Private(SNES snes, PetscInt ivec, PetscInt l, Vec F, PetscReal fnorm, Vec X) { 538774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 638774f0aSPeter Brune Vec *Fdot = ngmres->Fdot; 738774f0aSPeter Brune Vec *Xdot = ngmres->Xdot; 838774f0aSPeter Brune 938774f0aSPeter Brune PetscFunctionBegin; 1063a3b9bcSJacob Faibussowitsch PetscCheck(ivec <= l, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot update vector %" PetscInt_FMT " with space size %" PetscInt_FMT "!", ivec, l); 119566063dSJacob Faibussowitsch PetscCall(VecCopy(F, Fdot[ivec])); 129566063dSJacob Faibussowitsch PetscCall(VecCopy(X, Xdot[ivec])); 131aa26658SKarl Rupp 1438774f0aSPeter Brune ngmres->fnorms[ivec] = fnorm; 1538774f0aSPeter Brune PetscFunctionReturn(0); 1638774f0aSPeter Brune } 1738774f0aSPeter Brune 189371c9d4SSatish Balay PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes, PetscInt ivec, PetscInt l, Vec XM, Vec FM, PetscReal fMnorm, Vec X, Vec XA, Vec FA) { 1938774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 2038774f0aSPeter Brune PetscInt i, j; 2138774f0aSPeter Brune Vec *Fdot = ngmres->Fdot; 2238774f0aSPeter Brune Vec *Xdot = ngmres->Xdot; 2338774f0aSPeter Brune PetscScalar *beta = ngmres->beta; 2438774f0aSPeter Brune PetscScalar *xi = ngmres->xi; 2538774f0aSPeter Brune PetscScalar alph_total = 0.; 2638774f0aSPeter Brune PetscReal nu; 2738774f0aSPeter Brune Vec Y = snes->work[2]; 2838774f0aSPeter Brune PetscBool changed_y, changed_w; 2938774f0aSPeter Brune 3038774f0aSPeter Brune PetscFunctionBegin; 3138774f0aSPeter Brune nu = fMnorm * fMnorm; 3238774f0aSPeter Brune 3338774f0aSPeter Brune /* construct the right hand side and xi factors */ 34b3c6a99cSPeter Brune if (l > 0) { 359566063dSJacob Faibussowitsch PetscCall(VecMDotBegin(FM, l, Fdot, xi)); 369566063dSJacob Faibussowitsch PetscCall(VecMDotBegin(Fdot[ivec], l, Fdot, beta)); 379566063dSJacob Faibussowitsch PetscCall(VecMDotEnd(FM, l, Fdot, xi)); 389566063dSJacob Faibussowitsch PetscCall(VecMDotEnd(Fdot[ivec], l, Fdot, beta)); 39b3c6a99cSPeter Brune for (i = 0; i < l; i++) { 40b3c6a99cSPeter Brune Q(i, ivec) = beta[i]; 41b3c6a99cSPeter Brune Q(ivec, i) = beta[i]; 42b3c6a99cSPeter Brune } 43b3c6a99cSPeter Brune } else { 44b3c6a99cSPeter Brune Q(0, 0) = ngmres->fnorms[ivec] * ngmres->fnorms[ivec]; 45b3c6a99cSPeter Brune } 46b3c6a99cSPeter Brune 471aa26658SKarl Rupp for (i = 0; i < l; i++) beta[i] = nu - xi[i]; 481aa26658SKarl Rupp 4938774f0aSPeter Brune /* construct h */ 5038774f0aSPeter Brune for (j = 0; j < l; j++) { 519371c9d4SSatish Balay for (i = 0; i < l; i++) { H(i, j) = Q(i, j) - xi[i] - xi[j] + nu; } 5238774f0aSPeter Brune } 5338774f0aSPeter Brune if (l == 1) { 5438774f0aSPeter Brune /* simply set alpha[0] = beta[0] / H[0, 0] */ 551aa26658SKarl Rupp if (H(0, 0) != 0.) beta[0] = beta[0] / H(0, 0); 561aa26658SKarl Rupp else beta[0] = 0.; 5738774f0aSPeter Brune } else { 589566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(l, &ngmres->m)); 599566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(l, &ngmres->n)); 6038774f0aSPeter Brune ngmres->info = 0; 6138774f0aSPeter Brune ngmres->rcond = -1.; 629566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 6338774f0aSPeter Brune #if defined(PETSC_USE_COMPLEX) 64792fecdfSBarry Smith PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&ngmres->m, &ngmres->n, &ngmres->nrhs, ngmres->h, &ngmres->lda, ngmres->beta, &ngmres->ldb, ngmres->s, &ngmres->rcond, &ngmres->rank, ngmres->work, &ngmres->lwork, ngmres->rwork, &ngmres->info)); 6538774f0aSPeter Brune #else 66792fecdfSBarry Smith PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&ngmres->m, &ngmres->n, &ngmres->nrhs, ngmres->h, &ngmres->lda, ngmres->beta, &ngmres->ldb, ngmres->s, &ngmres->rcond, &ngmres->rank, ngmres->work, &ngmres->lwork, &ngmres->info)); 6738774f0aSPeter Brune #endif 689566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 6908401ef6SPierre Jolivet PetscCheck(ngmres->info >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "Bad argument to GELSS"); 7008401ef6SPierre Jolivet PetscCheck(ngmres->info <= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD failed to converge"); 7138774f0aSPeter Brune } 729371c9d4SSatish Balay for (i = 0; i < l; i++) { PetscCheck(!PetscIsInfOrNanScalar(beta[i]), PetscObjectComm((PetscObject)snes), PETSC_ERR_LIB, "SVD generated inconsistent output"); } 7338774f0aSPeter Brune alph_total = 0.; 741aa26658SKarl Rupp for (i = 0; i < l; i++) alph_total += beta[i]; 751aa26658SKarl Rupp 769566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, XA)); 779566063dSJacob Faibussowitsch PetscCall(VecScale(XA, 1. - alph_total)); 789566063dSJacob Faibussowitsch PetscCall(VecMAXPY(XA, l, beta, Xdot)); 7938774f0aSPeter Brune /* check the validity of the step */ 809566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, Y)); 819566063dSJacob Faibussowitsch PetscCall(VecAXPY(Y, -1.0, X)); 829566063dSJacob Faibussowitsch PetscCall(SNESLineSearchPostCheck(snes->linesearch, X, Y, XA, &changed_y, &changed_w)); 8346159c86SPeter Brune if (!ngmres->approxfunc) { 84efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT) { 859566063dSJacob Faibussowitsch PetscCall(SNESApplyNPC(snes, XA, NULL, FA)); 8646159c86SPeter Brune } else { 879566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, XA, FA)); 8846159c86SPeter Brune } 8935f895b4SBarry Smith } else { 909566063dSJacob Faibussowitsch PetscCall(VecCopy(FM, FA)); 919566063dSJacob Faibussowitsch PetscCall(VecScale(FA, 1. - alph_total)); 929566063dSJacob Faibussowitsch PetscCall(VecMAXPY(FA, l, beta, Fdot)); 93077c4231SPeter Brune } 9438774f0aSPeter Brune PetscFunctionReturn(0); 9538774f0aSPeter Brune } 9638774f0aSPeter Brune 979371c9d4SSatish Balay PetscErrorCode SNESNGMRESNorms_Private(SNES snes, PetscInt l, Vec X, Vec F, Vec XM, Vec FM, Vec XA, Vec FA, Vec D, PetscReal *dnorm, PetscReal *dminnorm, PetscReal *xMnorm, PetscReal *fMnorm, PetscReal *yMnorm, PetscReal *xAnorm, PetscReal *fAnorm, PetscReal *yAnorm) { 9838774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 99b3c6a99cSPeter Brune PetscReal dcurnorm, dmin = -1.0; 10038774f0aSPeter Brune Vec *Xdot = ngmres->Xdot; 10138774f0aSPeter Brune PetscInt i; 10238774f0aSPeter Brune 10338774f0aSPeter Brune PetscFunctionBegin; 1041baa6e33SBarry Smith if (xMnorm) PetscCall(VecNormBegin(XM, NORM_2, xMnorm)); 1051baa6e33SBarry Smith if (fMnorm) PetscCall(VecNormBegin(FM, NORM_2, fMnorm)); 106b3c6a99cSPeter Brune if (yMnorm) { 1079566063dSJacob Faibussowitsch PetscCall(VecCopy(X, D)); 1089566063dSJacob Faibussowitsch PetscCall(VecAXPY(D, -1.0, XM)); 1099566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, yMnorm)); 110b3c6a99cSPeter Brune } 1111baa6e33SBarry Smith if (xAnorm) PetscCall(VecNormBegin(XA, NORM_2, xAnorm)); 1121baa6e33SBarry Smith if (fAnorm) PetscCall(VecNormBegin(FA, NORM_2, fAnorm)); 113b3c6a99cSPeter Brune if (yAnorm) { 1149566063dSJacob Faibussowitsch PetscCall(VecCopy(X, D)); 1159566063dSJacob Faibussowitsch PetscCall(VecAXPY(D, -1.0, XA)); 1169566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, yAnorm)); 117b3c6a99cSPeter Brune } 11838774f0aSPeter Brune if (dnorm) { 1199566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, D)); 1209566063dSJacob Faibussowitsch PetscCall(VecAXPY(D, -1.0, XM)); 1219566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, dnorm)); 12238774f0aSPeter Brune } 12338774f0aSPeter Brune if (dminnorm) { 12438774f0aSPeter Brune for (i = 0; i < l; i++) { 1259566063dSJacob Faibussowitsch PetscCall(VecCopy(Xdot[i], D)); 1269566063dSJacob Faibussowitsch PetscCall(VecAXPY(D, -1.0, XA)); 1279566063dSJacob Faibussowitsch PetscCall(VecNormBegin(D, NORM_2, &ngmres->xnorms[i])); 12838774f0aSPeter Brune } 12938774f0aSPeter Brune } 1309566063dSJacob Faibussowitsch if (xMnorm) PetscCall(VecNormEnd(XM, NORM_2, xMnorm)); 1319566063dSJacob Faibussowitsch if (fMnorm) PetscCall(VecNormEnd(FM, NORM_2, fMnorm)); 1329566063dSJacob Faibussowitsch if (yMnorm) PetscCall(VecNormEnd(D, NORM_2, yMnorm)); 1339566063dSJacob Faibussowitsch if (xAnorm) PetscCall(VecNormEnd(XA, NORM_2, xAnorm)); 1349566063dSJacob Faibussowitsch if (fAnorm) PetscCall(VecNormEnd(FA, NORM_2, fAnorm)); 1359566063dSJacob Faibussowitsch if (yAnorm) PetscCall(VecNormEnd(D, NORM_2, yAnorm)); 1369566063dSJacob Faibussowitsch if (dnorm) PetscCall(VecNormEnd(D, NORM_2, dnorm)); 13738774f0aSPeter Brune if (dminnorm) { 13838774f0aSPeter Brune for (i = 0; i < l; i++) { 1399566063dSJacob Faibussowitsch PetscCall(VecNormEnd(D, NORM_2, &ngmres->xnorms[i])); 14038774f0aSPeter Brune dcurnorm = ngmres->xnorms[i]; 141b3c6a99cSPeter Brune if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm; 14238774f0aSPeter Brune } 143b3c6a99cSPeter Brune *dminnorm = dmin; 14438774f0aSPeter Brune } 14538774f0aSPeter Brune PetscFunctionReturn(0); 14638774f0aSPeter Brune } 14738774f0aSPeter Brune 1489371c9d4SSatish Balay PetscErrorCode SNESNGMRESSelect_Private(SNES snes, PetscInt k_restart, Vec XM, Vec FM, PetscReal xMnorm, PetscReal fMnorm, PetscReal yMnorm, Vec XA, Vec FA, PetscReal xAnorm, PetscReal fAnorm, PetscReal yAnorm, PetscReal dnorm, PetscReal fminnorm, PetscReal dminnorm, Vec X, Vec F, Vec Y, PetscReal *xnorm, PetscReal *fnorm, PetscReal *ynorm) { 14938774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 150422a814eSBarry Smith SNESLineSearchReason lssucceed; 151422a814eSBarry Smith PetscBool selectA; 15238774f0aSPeter Brune 15338774f0aSPeter Brune PetscFunctionBegin; 15438774f0aSPeter Brune if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) { 15538774f0aSPeter Brune /* X = X + \lambda(XA - X) */ 156*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm)); 1579566063dSJacob Faibussowitsch PetscCall(VecCopy(FM, F)); 1589566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, X)); 1599566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, Y)); 1609566063dSJacob Faibussowitsch PetscCall(VecAYPX(Y, -1.0, X)); 16138774f0aSPeter Brune *fnorm = fMnorm; 1629566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(ngmres->additive_linesearch, X, F, fnorm, Y)); 1639566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(ngmres->additive_linesearch, &lssucceed)); 1649566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(ngmres->additive_linesearch, xnorm, fnorm, ynorm)); 165422a814eSBarry Smith if (lssucceed) { 16638774f0aSPeter Brune if (++snes->numFailures >= snes->maxFailures) { 16738774f0aSPeter Brune snes->reason = SNES_DIVERGED_LINE_SEARCH; 16838774f0aSPeter Brune PetscFunctionReturn(0); 16938774f0aSPeter Brune } 17038774f0aSPeter Brune } 171*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Additive solution: ||F||_2 = %e\n", (double)*fnorm)); 17238774f0aSPeter Brune } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) { 17338774f0aSPeter Brune selectA = PETSC_TRUE; 17438774f0aSPeter Brune /* Conditions for choosing the accelerated answer */ 17538774f0aSPeter Brune /* Criterion A -- the norm of the function isn't increased above the minimum by too much */ 1761aa26658SKarl Rupp if (fAnorm >= ngmres->gammaA * fminnorm) selectA = PETSC_FALSE; 1771aa26658SKarl Rupp 17838774f0aSPeter Brune /* Criterion B -- the choice of x^A isn't too close to some other choice */ 17938774f0aSPeter Brune if (ngmres->epsilonB * dnorm < dminnorm || PetscSqrtReal(*fnorm) < ngmres->deltaB * PetscSqrtReal(fminnorm)) { 1801aa26658SKarl Rupp } else selectA = PETSC_FALSE; 1811aa26658SKarl Rupp 18238774f0aSPeter Brune if (selectA) { 183*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm)); 18438774f0aSPeter Brune /* copy it over */ 185b3c6a99cSPeter Brune *xnorm = xAnorm; 18638774f0aSPeter Brune *fnorm = fAnorm; 187b3c6a99cSPeter Brune *ynorm = yAnorm; 1889566063dSJacob Faibussowitsch PetscCall(VecCopy(FA, F)); 1899566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, X)); 19038774f0aSPeter Brune } else { 191*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n", (double)fAnorm, (double)fMnorm)); 192b3c6a99cSPeter Brune *xnorm = xMnorm; 19338774f0aSPeter Brune *fnorm = fMnorm; 194b3c6a99cSPeter Brune *ynorm = yMnorm; 1959566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, Y)); 1969566063dSJacob Faibussowitsch PetscCall(VecAXPY(Y, -1.0, X)); 1979566063dSJacob Faibussowitsch PetscCall(VecCopy(FM, F)); 1989566063dSJacob Faibussowitsch PetscCall(VecCopy(XM, X)); 19938774f0aSPeter Brune } 20038774f0aSPeter Brune } else { /* none */ 201b3c6a99cSPeter Brune *xnorm = xAnorm; 20238774f0aSPeter Brune *fnorm = fAnorm; 203b3c6a99cSPeter Brune *ynorm = yAnorm; 2049566063dSJacob Faibussowitsch PetscCall(VecCopy(FA, F)); 2059566063dSJacob Faibussowitsch PetscCall(VecCopy(XA, X)); 20638774f0aSPeter Brune } 20738774f0aSPeter Brune PetscFunctionReturn(0); 20838774f0aSPeter Brune } 20938774f0aSPeter Brune 2109371c9d4SSatish Balay PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes, PetscInt l, PetscReal fMnorm, PetscReal fAnorm, PetscReal dnorm, PetscReal fminnorm, PetscReal dminnorm, PetscBool *selectRestart) { 21138774f0aSPeter Brune SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data; 21238774f0aSPeter Brune 21338774f0aSPeter Brune PetscFunctionBegin; 21438774f0aSPeter Brune *selectRestart = PETSC_FALSE; 21538774f0aSPeter Brune /* difference stagnation restart */ 21621687c63SPeter Brune if ((ngmres->epsilonB * dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB * PetscSqrtReal(fminnorm)) && l > 0) { 217*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "difference restart: %e > %e\n", (double)(ngmres->epsilonB * dnorm), (double)dminnorm)); 21838774f0aSPeter Brune *selectRestart = PETSC_TRUE; 21938774f0aSPeter Brune } 22038774f0aSPeter Brune /* residual stagnation restart */ 22138774f0aSPeter Brune if (PetscSqrtReal(fAnorm) > ngmres->gammaC * PetscSqrtReal(fminnorm)) { 222*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "residual restart: %e > %e\n", (double)PetscSqrtReal(fAnorm), (double)(ngmres->gammaC * PetscSqrtReal(fminnorm)))); 22338774f0aSPeter Brune *selectRestart = PETSC_TRUE; 22438774f0aSPeter Brune } 22523b3e82cSAsbjørn Nilsen Riseth 22623b3e82cSAsbjørn Nilsen Riseth /* F_M stagnation restart */ 22723b3e82cSAsbjørn Nilsen Riseth if (ngmres->restart_fm_rise && fMnorm > snes->norm) { 228*48a46eb9SPierre Jolivet if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "F_M rise restart: %e > %e\n", (double)fMnorm, (double)snes->norm)); 22923b3e82cSAsbjørn Nilsen Riseth *selectRestart = PETSC_TRUE; 23023b3e82cSAsbjørn Nilsen Riseth } 23123b3e82cSAsbjørn Nilsen Riseth 23238774f0aSPeter Brune PetscFunctionReturn(0); 23338774f0aSPeter Brune } 234