Date: 2016-07-24T17:09:17+00:00

Actual source code: ngmresfunc.c
petsc-3.7.3 2016-07-24
Report Typos and Errors

      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;
    182:   PetscErrorCode       ierr;
    183:   SNESLineSearchReason lssucceed;
    184:   PetscBool            selectA;

    187:   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
    188:     /* X = X + \lambda(XA - X) */
    189:     if (ngmres->monitor) {
    190:       PetscViewerASCIIPrintf(ngmres->monitor,"||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
    191:     }
    192:     VecCopy(FM,F);
    193:     VecCopy(XM,X);
    194:     VecCopy(XA,Y);
    195:     VecAYPX(Y,-1.0,X);
    196:     *fnorm = fMnorm;
    197:     SNESLineSearchApply(ngmres->additive_linesearch,X,F,fnorm,Y);
    198:     SNESLineSearchGetReason(ngmres->additive_linesearch,&lssucceed);
    199:     SNESLineSearchGetNorms(ngmres->additive_linesearch,xnorm,fnorm,ynorm);
    200:     if (lssucceed) {
    201:       if (++snes->numFailures >= snes->maxFailures) {
    202:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
    203:         return(0);
    204:       }
    205:     }
    206:     if (ngmres->monitor) {
    207:       PetscViewerASCIIPrintf(ngmres->monitor,"Additive solution: ||F||_2 = %e\n",*fnorm);
    208:     }
    209:   } else if (ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
    210:     selectA = PETSC_TRUE;
    211:     /* Conditions for choosing the accelerated answer */
    212:     /* Criterion A -- the norm of the function isn't increased above the minimum by too much */
    213:     if (fAnorm >= ngmres->gammaA*fminnorm) selectA = PETSC_FALSE;

    215:     /* Criterion B -- the choice of x^A isn't too close to some other choice */
    216:     if (ngmres->epsilonB*dnorm<dminnorm || PetscSqrtReal(*fnorm)<ngmres->deltaB*PetscSqrtReal(fminnorm)) {
    217:     } else selectA=PETSC_FALSE;

    219:     if (selectA) {
    220:       if (ngmres->monitor) {
    221:         PetscViewerASCIIPrintf(ngmres->monitor,"picked X_A, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
    222:       }
    223:       /* copy it over */
    224:       *xnorm = xAnorm;
    225:       *fnorm = fAnorm;
    226:       *ynorm = yAnorm;
    227:       VecCopy(FA,F);
    228:       VecCopy(XA,X);
    229:     } else {
    230:       if (ngmres->monitor) {
    231:         PetscViewerASCIIPrintf(ngmres->monitor,"picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
    232:       }
    233:       *xnorm = xMnorm;
    234:       *fnorm = fMnorm;
    235:       *ynorm = yMnorm;
    236:       VecCopy(XM,Y);
    237:       VecAXPY(Y,-1.0,X);
    238:       VecCopy(FM,F);
    239:       VecCopy(XM,X);
    240:     }
    241:   } else { /* none */
    242:     *xnorm = xAnorm;
    243:     *fnorm = fAnorm;
    244:     *ynorm = yAnorm;
    245:     VecCopy(FA,F);
    246:     VecCopy(XA,X);
    247:   }
    248:   return(0);
    249: }

    253: PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes,PetscInt l,PetscReal fMnorm, PetscReal fAnorm,PetscReal dnorm,PetscReal fminnorm,PetscReal dminnorm,PetscBool *selectRestart)
    254: {
    255:   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;

    259:   *selectRestart = PETSC_FALSE;
    260:   /* difference stagnation restart */
    261:   if ((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm)) && l > 0) {
    262:     if (ngmres->monitor) {
    263:       PetscViewerASCIIPrintf(ngmres->monitor,"difference restart: %e > %e\n",ngmres->epsilonB*dnorm,dminnorm);
    264:     }
    265:     *selectRestart = PETSC_TRUE;
    266:   }
    267:   /* residual stagnation restart */
    268:   if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
    269:     if (ngmres->monitor) {
    270:       PetscViewerASCIIPrintf(ngmres->monitor,"residual restart: %e > %e\n",PetscSqrtReal(fAnorm),ngmres->gammaC*PetscSqrtReal(fminnorm));
    271:     }
    272:     *selectRestart = PETSC_TRUE;
    273:   }

    275:   /* F_M stagnation restart */
    276:   if (ngmres->restart_fm_rise && fMnorm > snes->norm) {
    277:     if (ngmres->monitor) {
    278:       PetscViewerASCIIPrintf(ngmres->monitor,"F_M rise restart: %e > %e\n",fMnorm,snes->norm);
    279:     }
    280:     *selectRestart = PETSC_TRUE;
    281:   }

    283:   return(0);
    284: }