Actual source code: ngmresfunc.c
petsc-3.13.6 2020-09-29
1: #include <../src/snes/impls/ngmres/snesngmres.h>
2: #include <petscblaslapack.h>
4: PetscErrorCode SNESNGMRESUpdateSubspace_Private(SNES snes,PetscInt ivec,PetscInt l,Vec F,PetscReal fnorm,Vec X)
5: {
6: SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
7: Vec *Fdot = ngmres->Fdot;
8: Vec *Xdot = ngmres->Xdot;
12: if (ivec > l) SETERRQ2(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Cannot update vector %D with space size %D!",ivec,l);
13: VecCopy(F,Fdot[ivec]);
14: VecCopy(X,Xdot[ivec]);
16: ngmres->fnorms[ivec] = fnorm;
17: return(0);
18: }
20: PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes,PetscInt ivec,PetscInt l,Vec XM,Vec FM,PetscReal fMnorm,Vec X,Vec XA,Vec FA)
21: {
22: SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
23: PetscInt i,j;
24: Vec *Fdot = ngmres->Fdot;
25: Vec *Xdot = ngmres->Xdot;
26: PetscScalar *beta = ngmres->beta;
27: PetscScalar *xi = ngmres->xi;
28: PetscScalar alph_total = 0.;
30: PetscReal nu;
31: Vec Y = snes->work[2];
32: PetscBool changed_y,changed_w;
35: nu = fMnorm*fMnorm;
37: /* construct the right hand side and xi factors */
38: if (l > 0) {
39: VecMDotBegin(FM,l,Fdot,xi);
40: VecMDotBegin(Fdot[ivec],l,Fdot,beta);
41: VecMDotEnd(FM,l,Fdot,xi);
42: VecMDotEnd(Fdot[ivec],l,Fdot,beta);
43: for (i = 0; i < l; i++) {
44: Q(i,ivec) = beta[i];
45: Q(ivec,i) = beta[i];
46: }
47: } else {
48: Q(0,0) = ngmres->fnorms[ivec]*ngmres->fnorms[ivec];
49: }
51: for (i = 0; i < l; i++) beta[i] = nu - xi[i];
53: /* construct h */
54: for (j = 0; j < l; j++) {
55: for (i = 0; i < l; i++) {
56: H(i,j) = Q(i,j)-xi[i]-xi[j]+nu;
57: }
58: }
59: if (l == 1) {
60: /* simply set alpha[0] = beta[0] / H[0, 0] */
61: if (H(0,0) != 0.) beta[0] = beta[0]/H(0,0);
62: else beta[0] = 0.;
63: } else {
64: PetscBLASIntCast(l,&ngmres->m);
65: PetscBLASIntCast(l,&ngmres->n);
66: ngmres->info = 0;
67: ngmres->rcond = -1.;
68: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
69: #if defined(PETSC_USE_COMPLEX)
70: PetscStackCallBLAS("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));
71: #else
72: PetscStackCallBLAS("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));
73: #endif
74: PetscFPTrapPop();
75: if (ngmres->info < 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"Bad argument to GELSS");
76: if (ngmres->info > 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD failed to converge");
77: }
78: for (i=0; i<l; i++) {
79: if (PetscIsInfOrNanScalar(beta[i])) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD generated inconsistent output");
80: }
81: alph_total = 0.;
82: for (i = 0; i < l; i++) alph_total += beta[i];
84: VecCopy(XM,XA);
85: VecScale(XA,1.-alph_total);
86: VecMAXPY(XA,l,beta,Xdot);
87: /* check the validity of the step */
88: VecCopy(XA,Y);
89: VecAXPY(Y,-1.0,X);
90: SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);
91: if (!ngmres->approxfunc) {
92: if (snes->npc && snes->npcside== PC_LEFT) {
93: SNESApplyNPC(snes,XA,NULL,FA);
94: } else {
95: SNESComputeFunction(snes,XA,FA);
96: }
97: } else {
98: VecCopy(FM,FA);
99: VecScale(FA,1.-alph_total);
100: VecMAXPY(FA,l,beta,Fdot);
101: }
102: return(0);
103: }
105: 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)
106: {
108: SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
109: PetscReal dcurnorm,dmin = -1.0;
110: Vec *Xdot = ngmres->Xdot;
111: PetscInt i;
114: if (xMnorm) {
115: VecNormBegin(XM,NORM_2,xMnorm);
116: }
117: if (fMnorm) {
118: VecNormBegin(FM,NORM_2,fMnorm);
119: }
120: if (yMnorm) {
121: VecCopy(X,D);
122: VecAXPY(D,-1.0,XM);
123: VecNormBegin(D,NORM_2,yMnorm);
124: }
125: if (xAnorm) {
126: VecNormBegin(XA,NORM_2,xAnorm);
127: }
128: if (fAnorm) {
129: VecNormBegin(FA,NORM_2,fAnorm);
130: }
131: if (yAnorm) {
132: VecCopy(X,D);
133: VecAXPY(D,-1.0,XA);
134: VecNormBegin(D,NORM_2,yAnorm);
135: }
136: if (dnorm) {
137: VecCopy(XA,D);
138: VecAXPY(D,-1.0,XM);
139: VecNormBegin(D,NORM_2,dnorm);
140: }
141: if (dminnorm) {
142: for (i=0; i<l; i++) {
143: VecCopy(Xdot[i],D);
144: VecAXPY(D,-1.0,XA);
145: VecNormBegin(D,NORM_2,&ngmres->xnorms[i]);
146: }
147: }
148: if (xMnorm) {VecNormEnd(XM,NORM_2,xMnorm);}
149: if (fMnorm) {VecNormEnd(FM,NORM_2,fMnorm);}
150: if (yMnorm) {VecNormEnd(D,NORM_2,yMnorm);}
151: if (xAnorm) {VecNormEnd(XA,NORM_2,xAnorm);}
152: if (fAnorm) {VecNormEnd(FA,NORM_2,fAnorm);}
153: if (yAnorm) {VecNormEnd(D,NORM_2,yAnorm);}
154: if (dnorm) {VecNormEnd(D,NORM_2,dnorm);}
155: if (dminnorm) {
156: for (i=0; i<l; i++) {
157: VecNormEnd(D,NORM_2,&ngmres->xnorms[i]);
158: dcurnorm = ngmres->xnorms[i];
159: if ((dcurnorm < dmin) || (dmin < 0.0)) dmin = dcurnorm;
160: }
161: *dminnorm = dmin;
162: }
163: return(0);
164: }
166: 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)
167: {
168: SNES_NGMRES *ngmres = (SNES_NGMRES*) snes->data;
169: PetscErrorCode ierr;
170: SNESLineSearchReason lssucceed;
171: PetscBool selectA;
174: if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
175: /* X = X + \lambda(XA - X) */
176: if (ngmres->monitor) {
177: PetscViewerASCIIPrintf(ngmres->monitor,"||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
178: }
179: VecCopy(FM,F);
180: VecCopy(XM,X);
181: VecCopy(XA,Y);
182: VecAYPX(Y,-1.0,X);
183: *fnorm = fMnorm;
184: SNESLineSearchApply(ngmres->additive_linesearch,X,F,fnorm,Y);
185: SNESLineSearchGetReason(ngmres->additive_linesearch,&lssucceed);
186: SNESLineSearchGetNorms(ngmres->additive_linesearch,xnorm,fnorm,ynorm);
187: if (lssucceed) {
188: if (++snes->numFailures >= snes->maxFailures) {
189: snes->reason = SNES_DIVERGED_LINE_SEARCH;
190: return(0);
191: }
192: }
193: if (ngmres->monitor) {
194: PetscViewerASCIIPrintf(ngmres->monitor,"Additive solution: ||F||_2 = %e\n",*fnorm);
195: }
196: } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
197: selectA = PETSC_TRUE;
198: /* Conditions for choosing the accelerated answer */
199: /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
200: if (fAnorm >= ngmres->gammaA*fminnorm) selectA = PETSC_FALSE;
202: /* Criterion B -- the choice of x^A isn't too close to some other choice */
203: if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(*fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) {
204: } else selectA=PETSC_FALSE;
206: if (selectA) {
207: if (ngmres->monitor) {
208: PetscViewerASCIIPrintf(ngmres->monitor,"picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
209: }
210: /* copy it over */
211: *xnorm = xAnorm;
212: *fnorm = fAnorm;
213: *ynorm = yAnorm;
214: VecCopy(FA,F);
215: VecCopy(XA,X);
216: } else {
217: if (ngmres->monitor) {
218: PetscViewerASCIIPrintf(ngmres->monitor,"picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
219: }
220: *xnorm = xMnorm;
221: *fnorm = fMnorm;
222: *ynorm = yMnorm;
223: VecCopy(XM,Y);
224: VecAXPY(Y,-1.0,X);
225: VecCopy(FM,F);
226: VecCopy(XM,X);
227: }
228: } else { /* none */
229: *xnorm = xAnorm;
230: *fnorm = fAnorm;
231: *ynorm = yAnorm;
232: VecCopy(FA,F);
233: VecCopy(XA,X);
234: }
235: return(0);
236: }
238: PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes,PetscInt l,PetscReal fMnorm, PetscReal fAnorm,PetscReal dnorm,PetscReal fminnorm,PetscReal dminnorm,PetscBool *selectRestart)
239: {
240: SNES_NGMRES *ngmres = (SNES_NGMRES*)snes->data;
244: *selectRestart = PETSC_FALSE;
245: /* difference stagnation restart */
246: if ((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm)) && l > 0) {
247: if (ngmres->monitor) {
248: PetscViewerASCIIPrintf(ngmres->monitor,"difference restart: %e > %e\n",ngmres->epsilonB*dnorm,dminnorm);
249: }
250: *selectRestart = PETSC_TRUE;
251: }
252: /* residual stagnation restart */
253: if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
254: if (ngmres->monitor) {
255: PetscViewerASCIIPrintf(ngmres->monitor,"residual restart: %e > %e\n",PetscSqrtReal(fAnorm),ngmres->gammaC*PetscSqrtReal(fminnorm));
256: }
257: *selectRestart = PETSC_TRUE;
258: }
260: /* F_M stagnation restart */
261: if (ngmres->restart_fm_rise && fMnorm > snes->norm) {
262: if (ngmres->monitor) {
263: PetscViewerASCIIPrintf(ngmres->monitor,"F_M rise restart: %e > %e\n",fMnorm,snes->norm);
264: }
265: *selectRestart = PETSC_TRUE;
266: }
268: return(0);
269: }