Date: 2013-07-02T14:49:31+00:00

Actual source code: ngmresfunc.c
petsc-3.4.2 2013-07-02

      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;
     11:   PetscScalar    *xi     = ngmres->xi;
     12:   PetscInt       i;
     13:   PetscReal      nu;

     17:   if (ivec > l) SETERRQ2(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Cannot update vector %d with space size %d!",ivec,l);
     18:   VecCopy(F,Fdot[ivec]);
     19:   VecCopy(X,Xdot[ivec]);

     21:   ngmres->fnorms[ivec] = fnorm;
     22:   if (l > 0) {
     23:     VecMDot(F,l,Fdot,xi);
     24:     for (i = 0; i < l; i++) {
     25:       Q(i,ivec) = xi[i];
     26:       Q(ivec,i) = xi[i];
     27:     }
     28:   } else {
     29:     nu     = fnorm*fnorm;
     30:     Q(0,0) = nu;
     31:   }
     32:   return(0);
     33: }

     37: PetscErrorCode SNESNGMRESFormCombinedSolution_Private(SNES snes,PetscInt l,Vec XM,Vec FM,PetscReal fMnorm,Vec X,Vec XA,Vec FA)
     38: {
     39:   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
     40:   PetscInt       i,j;
     41:   Vec            *Fdot      = ngmres->Fdot;
     42:   Vec            *Xdot      = ngmres->Xdot;
     43:   PetscScalar    *beta      = ngmres->beta;
     44:   PetscScalar    *xi        = ngmres->xi;
     45:   PetscScalar    alph_total = 0.;
     47:   PetscReal      nu;
     48:   Vec            Y = snes->work[2];
     49:   PetscBool      changed_y,changed_w;

     52:   nu = fMnorm*fMnorm;

     54:   /* construct the right hand side and xi factors */
     55:   VecMDot(FM,l,Fdot,xi);
     56:   for (i = 0; i < l; i++) beta[i] = nu - xi[i];

     58:   /* construct h */
     59:   for (j = 0; j < l; j++) {
     60:     for (i = 0; i < l; i++) {
     61:       H(i,j) = Q(i,j)-xi[i]-xi[j]+nu;
     62:     }
     63:   }
     64:   if (l == 1) {
     65:     /* simply set alpha[0] = beta[0] / H[0, 0] */
     66:     if (H(0,0) != 0.) beta[0] = beta[0]/H(0,0);
     67:     else beta[0] = 0.;
     68:   } else {
     69: #if defined(PETSC_MISSING_LAPACK_GELSS)
     70:     SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"NGMRES with LS requires the LAPACK GELSS routine.");
     71: #else
     72:     PetscBLASIntCast(l,&ngmres->m);
     73:     PetscBLASIntCast(l,&ngmres->n);
     74:     ngmres->info  = 0;
     75:     ngmres->rcond = -1.;
     76:     PetscFPTrapPush(PETSC_FP_TRAP_OFF);
     77: #if defined(PETSC_USE_COMPLEX)
     78:     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));
     79: #else
     80:     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));
     81: #endif
     82:     PetscFPTrapPop();
     83:     if (ngmres->info < 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"Bad argument to GELSS");
     84:     if (ngmres->info > 0) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD failed to converge");
     85: #endif
     86:   }
     87:   for (i=0; i<l; i++) {
     88:     if (PetscIsInfOrNanScalar(beta[i])) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_LIB,"SVD generated inconsistent output");
     89:   }
     90:   alph_total = 0.;
     91:   for (i = 0; i < l; i++) alph_total += beta[i];

     93:   VecCopy(XM,XA);
     94:   VecScale(XA,1.-alph_total);
     95:   VecMAXPY(XA,l,beta,Xdot);
     96:   /* check the validity of the step */
     97:   VecCopy(XA,Y);
     98:   VecAXPY(Y,-1.0,X);
     99:   SNESLineSearchPostCheck(snes->linesearch,X,Y,XA,&changed_y,&changed_w);
    100:   if (!ngmres->approxfunc) {SNESComputeFunction(snes,XA,FA);}
    101:   else {
    102:     VecCopy(FM,FA);
    103:     VecScale(FA,1.-alph_total);
    104:     VecMAXPY(FA,l,beta,Fdot);
    105:   }
    106:   return(0);
    107: }

    111: PetscErrorCode SNESNGMRESCalculateDifferences_Private(SNES snes,PetscInt l,Vec X,Vec F,Vec XM,Vec FM,Vec XA,Vec FA,Vec D,PetscReal *dnorm,PetscReal *dminnorm,PetscReal *fAnorm)
    112: {
    114:   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
    115:   PetscReal      dcurnorm;
    116:   Vec            *Xdot = ngmres->Xdot;
    117:   PetscInt       i;

    120:   if (ngmres->singlereduction) {
    121:     *dminnorm = -1.0;
    122:     if (fAnorm) {
    123:       VecNormBegin(FA,NORM_2,fAnorm);
    124:     }
    125:     if (dnorm) {
    126:       VecCopy(XA,D);
    127:       VecAXPY(D,-1.0,XM);
    128:       VecNormBegin(D,NORM_2,dnorm);
    129:     }
    130:     if (dminnorm) {
    131:       for (i=0; i<l; i++) {
    132:         ierr=VecAXPY(Xdot[i],-1.0,XA);
    133:       }
    134:       for (i=0; i<l; i++) {
    135:         VecNormBegin(Xdot[i],NORM_2,&ngmres->xnorms[i]);
    136:       }
    137:     }
    138:     if (fAnorm) {VecNormEnd(FA,NORM_2,fAnorm);}
    139:     if (dnorm) {VecNormEnd(D,NORM_2,dnorm);}
    140:     if (dminnorm) {
    141:       for (i=0; i<l; i++) {
    142:         VecNormEnd(Xdot[i],NORM_2,&ngmres->xnorms[i]);
    143:       }
    144:       for (i=0; i<l; i++) {
    145:         dcurnorm = ngmres->xnorms[i];
    146:         if ((dcurnorm < *dminnorm) || (*dminnorm < 0.0)) *dminnorm = dcurnorm;
    147:         ierr=VecAXPY(Xdot[i],1.0,XA);
    148:       }
    149:     }
    150:   } else {
    151:     if (dnorm) {
    152:       ierr=VecCopy(XA,D);
    153:       ierr=VecAXPY(D,-1.0,XM);
    154:       ierr=VecNormBegin(D,NORM_2,dnorm);
    155:     }
    156:     if (fAnorm) {
    157:       ierr=VecNormBegin(FA,NORM_2,fAnorm);
    158:     }
    159:     if (dnorm) {
    160:       ierr=VecNormEnd(D,NORM_2,dnorm);
    161:     }
    162:     if (fAnorm) {
    163:       ierr=VecNormEnd(FA,NORM_2,fAnorm);
    164:     }
    165:     if (dminnorm) {
    166:       *dminnorm = -1.0;
    167:       for (i=0; i<l; i++) {
    168:         ierr=VecCopy(XA,D);
    169:         ierr=VecAXPY(D,-1.0,Xdot[i]);
    170:         ierr=VecNorm(D,NORM_2,&dcurnorm);
    171:         if ((dcurnorm < *dminnorm) || (*dminnorm < 0.0)) *dminnorm = dcurnorm;
    172:       }
    173:     }
    174:   }
    175:   return(0);
    176: }

    180: PetscErrorCode SNESNGMRESSelect_Private(SNES snes,PetscInt k_restart,Vec XM,Vec FM,PetscReal fMnorm,Vec XA,Vec FA,PetscReal fAnorm,PetscReal dnorm,PetscReal fminnorm,PetscReal dminnorm,Vec X,Vec F,Vec Y,PetscReal *fnorm)
    181: {
    182:   SNES_NGMRES    *ngmres = (SNES_NGMRES*) snes->data;
    184:   PetscBool      lssucceed,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:     SNESLineSearchGetSuccess(ngmres->additive_linesearch,&lssucceed);
    199:     if (!lssucceed) {
    200:       if (++snes->numFailures >= snes->maxFailures) {
    201:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
    202:         return(0);
    203:       }
    204:     }
    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:       *fnorm = fAnorm;
    224:       VecCopy(FA,F);
    225:       VecCopy(XA,X);
    226:     } else {
    227:       if (ngmres->monitor) {
    228:         PetscViewerASCIIPrintf(ngmres->monitor,"picked X_M, ||F_A||_2 = %e, ||F_M||_2 = %e\n",fAnorm,fMnorm);
    229:       }
    230:       *fnorm = fMnorm;
    231:       VecCopy(XM,Y);
    232:       VecAXPY(Y,-1.0,X);
    233:       VecCopy(FM,F);
    234:       VecCopy(XM,X);
    235:     }
    236:   } else { /* none */
    237:     *fnorm = fAnorm;
    238:     VecCopy(FA,F);
    239:     VecCopy(XA,X);
    240:   }
    241:   return(0);
    242: }

    246: PetscErrorCode SNESNGMRESSelectRestart_Private(SNES snes,PetscInt l,PetscReal fAnorm,PetscReal dnorm,PetscReal fminnorm,PetscReal dminnorm,PetscBool *selectRestart)
    247: {
    248:   SNES_NGMRES    *ngmres = (SNES_NGMRES*)snes->data;

    252:   *selectRestart = PETSC_FALSE;
    253:   /* difference stagnation restart */
    254:   if ((ngmres->epsilonB*dnorm > dminnorm) && (PetscSqrtReal(fAnorm) > ngmres->deltaB*PetscSqrtReal(fminnorm)) && l > 0) {
    255:     if (ngmres->monitor) {
    256:       PetscViewerASCIIPrintf(ngmres->monitor,"difference restart: %e > %e\n",ngmres->epsilonB*dnorm,dminnorm);
    257:     }
    258:     *selectRestart = PETSC_TRUE;
    259:   }
    260:   /* residual stagnation restart */
    261:   if (PetscSqrtReal(fAnorm) > ngmres->gammaC*PetscSqrtReal(fminnorm)) {
    262:     if (ngmres->monitor) {
    263:       PetscViewerASCIIPrintf(ngmres->monitor,"residual restart: %e > %e\n",PetscSqrtReal(fAnorm),ngmres->gammaC*PetscSqrtReal(fminnorm));
    264:     }
    265:     *selectRestart = PETSC_TRUE;
    266:   }
    267:   return(0);
    268: }