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