Date: 2015-09-03T15:05:34+00:00

Actual source code: peprefine.c
slepc-3.6.1 2015-09-03
Report Typos and Errors

      1: /*
      2:    Newton refinement for PEP, simple version.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

      8:    This file is part of SLEPc.

     10:    SLEPc is free software: you can redistribute it and/or modify it under  the
     11:    terms of version 3 of the GNU Lesser General Public License as published by
     12:    the Free Software Foundation.

     14:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     15:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     16:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     17:    more details.

     19:    You  should have received a copy of the GNU Lesser General  Public  License
     20:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     21:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     22: */

     24: #include <slepc/private/pepimpl.h>
     25: #include <slepcblaslapack.h>

     27: #define NREF_MAXIT 10

     29: typedef struct {
     30:   VecScatter    *scatter_id;
     31:   Mat           *A;
     32:   Vec           vg,v;
     33: } PEPSimpNRefctx;

     37: static PetscErrorCode PEPSimpleNRefSetUp(PEP pep,PEPSimpNRefctx **ctx_)
     38: {
     40:   PetscInt       i,si,j,n0,m0,nloc,*idx1,*idx2;
     41:   IS             is1,is2;
     42:   PEPSimpNRefctx *ctx;
     43:   Vec            v;

     46:   PetscMalloc1(1,ctx_);
     47:   ctx = *ctx_;
     48:   if (pep->npart==1) {
     49:     pep->refinesubc = NULL;
     50:     ctx->scatter_id = NULL;
     51:     ctx->A = pep->A;
     52:   } else {
     53:     PetscMalloc2(pep->nmat,&ctx->A,pep->npart,&ctx->scatter_id);

     55:     /* Duplicate matrices */
     56:     for (i=0;i<pep->nmat;i++) {
     57:       MatCreateRedundantMatrix(pep->A[i],0,PetscSubcommChild(pep->refinesubc),MAT_INITIAL_MATRIX,&ctx->A[i]);
     58:     }
     59:     MatCreateVecs(ctx->A[0],&ctx->v,NULL);

     61:     /* Create scatters for sending vectors to each subcommucator */
     62:     BVGetColumn(pep->V,0,&v);
     63:     VecGetOwnershipRange(v,&n0,&m0);
     64:     BVRestoreColumn(pep->V,0,&v);
     65:     VecGetLocalSize(ctx->v,&nloc);
     66:     PetscMalloc2(m0-n0,&idx1,m0-n0,&idx2);
     67:     VecCreateMPI(PetscObjectComm((PetscObject)pep),nloc,PETSC_DECIDE,&ctx->vg);
     68:     for (si=0;si<pep->npart;si++) {
     69:       j = 0;
     70:       for (i=n0;i<m0;i++) {
     71:         idx1[j]   = i;
     72:         idx2[j++] = i+pep->n*si;
     73:       }
     74:       ISCreateGeneral(PetscObjectComm((PetscObject)pep),(m0-n0),idx1,PETSC_COPY_VALUES,&is1);
     75:       ISCreateGeneral(PetscObjectComm((PetscObject)pep),(m0-n0),idx2,PETSC_COPY_VALUES,&is2);
     76:       BVGetColumn(pep->V,0,&v);
     77:       VecScatterCreate(v,is1,ctx->vg,is2,&ctx->scatter_id[si]);
     78:       BVRestoreColumn(pep->V,0,&v);
     79:       ISDestroy(&is1);
     80:       ISDestroy(&is2);
     81:     }
     82:     PetscFree2(idx1,idx2);
     83:   }
     84:   return(0);
     85: }

     87: /*
     88:   Gather Eigenpair idx from subcommunicator with color sc
     89: */
     92: static PetscErrorCode PEPSimpleNRefGatherEigenpair(PEP pep,PEPSimpNRefctx *ctx,PetscInt sc,PetscInt idx)
     93: {
     94:   PetscErrorCode    ierr;
     95:   PetscMPIInt       nproc,p;
     96:   MPI_Comm          comm=((PetscObject)pep)->comm;
     97:   Vec               v;
     98:   const PetscScalar *array;

    101:   /* The eigenvalue information is in the last process of the
    102:      subcommunicator sc. p is its mapping in the general comm */
    103:   MPI_Comm_size(comm,&nproc);
    104:   p = (nproc/pep->npart)*(sc+1)+PetscMin(nproc%pep->npart,sc+1)-1;
    105:   MPI_Bcast(&pep->eigr[idx],1,MPIU_SCALAR,p,comm);

    107:   if (pep->npart>1) {
    108:     /* Gather pep->V[idx] from the subcommuniator sc */
    109:     BVGetColumn(pep->V,idx,&v);
    110:     if (pep->refinesubc->color==sc) {
    111:       VecGetArrayRead(ctx->v,&array);
    112:       VecPlaceArray(ctx->vg,array);
    113:     }
    114:     VecScatterBegin(ctx->scatter_id[sc],ctx->vg,v,INSERT_VALUES,SCATTER_REVERSE);
    115:     VecScatterEnd(ctx->scatter_id[sc],ctx->vg,v,INSERT_VALUES,SCATTER_REVERSE);
    116:     if (pep->refinesubc->color==sc) {
    117:       VecResetArray(ctx->vg);
    118:       VecRestoreArrayRead(ctx->v,&array);
    119:     }
    120:     BVRestoreColumn(pep->V,idx,&v);
    121:   }
    122:   return(0);
    123: }

    127: static PetscErrorCode PEPSimpleNRefScatterEigenvector(PEP pep,PEPSimpNRefctx *ctx,PetscInt sc,PetscInt idx)
    128: {
    129:   PetscErrorCode    ierr;
    130:   Vec               v;
    131:   const PetscScalar *array;
    132:
    134:   if (pep->npart>1) {
    135:     BVGetColumn(pep->V,idx,&v);
    136:     if (pep->refinesubc->color==sc) {
    137:       VecGetArrayRead(ctx->v,&array);
    138:       VecPlaceArray(ctx->vg,array);
    139:     }
    140:     VecScatterBegin(ctx->scatter_id[sc],v,ctx->vg,INSERT_VALUES,SCATTER_FORWARD);
    141:     VecScatterEnd(ctx->scatter_id[sc],v,ctx->vg,INSERT_VALUES,SCATTER_FORWARD);
    142:     if (pep->refinesubc->color==sc) {
    143:       VecResetArray(ctx->vg);
    144:       VecRestoreArrayRead(ctx->v,&array);
    145:     }
    146:     BVRestoreColumn(pep->V,idx,&v);
    147:   }
    148:   return(0);
    149: }

    153: static PetscErrorCode PEPEvaluateFunctionDerivatives(PEP pep,PetscScalar alpha,PetscScalar *vals)
    154: {
    155:   PetscInt    i,nmat=pep->nmat;
    156:   PetscScalar a0,a1,a2;
    157:   PetscReal   *a=pep->pbc,*b=a+nmat,*g=b+nmat;

    160:   a0 = 0.0;
    161:   a1 = 1.0;
    162:   vals[0] = 0.0;
    163:   if (nmat>1) vals[1] = 1/a[0];
    164:   for (i=2;i<nmat;i++) {
    165:     a2 = ((alpha-b[i-2])*a1-g[i-2]*a0)/a[i-2];
    166:     vals[i] = (a2+(alpha-b[i-1])*vals[i-1]-g[i-1]*vals[i-2])/a[i-1];
    167:     a0 = a1; a1 = a2;
    168:   }
    169:   return(0);
    170: }

    174: static PetscErrorCode PEPSimpleNRefSetUpSystem(PEP pep,Mat *A,PetscInt idx,Mat *M,Mat *T,PetscBool ini,Vec *t,Vec v)
    175: {
    176:   PetscErrorCode    ierr;
    177:   PetscInt          i,nmat=pep->nmat,ml,m0,m1,mg;
    178:   PetscInt          *dnz,*onz,ncols,*cols2,*nnz;
    179:   PetscScalar       zero=0.0,*coeffs;
    180:   PetscMPIInt       rank,size;
    181:   MPI_Comm          comm;
    182:   const PetscInt    *cols;
    183:   const PetscScalar *vals,*array;
    184:   MatStructure      str;
    185:   Vec               w=t[1],q=t[0];

    188:   comm = PetscObjectComm((PetscObject)A[0]);
    189:   STGetMatStructure(pep->st,&str);
    190:   PetscMalloc1(nmat,&coeffs);
    191:   MPI_Comm_rank(comm,&rank);
    192:   MPI_Comm_size(comm,&size);
    193:   if (ini) {
    194:     MatDuplicate(A[0],MAT_COPY_VALUES,T);
    195:   } else {
    196:     MatCopy(A[0],*T,DIFFERENT_NONZERO_PATTERN);
    197:   }
    198:   PEPEvaluateBasis(pep,pep->eigr[idx],0,coeffs,NULL);
    199:   MatScale(*T,coeffs[0]);
    200:   for (i=1;i<nmat;i++) {
    201:     MatAXPY(*T,coeffs[i],A[i],(ini)?str:SUBSET_NONZERO_PATTERN);
    202:   }
    203:   MatGetSize(*T,&mg,NULL);
    204:   MatGetOwnershipRange(*T,&m0,&m1);
    205:   if (ini) {
    206:     MatCreate(comm,M);
    207:     MatGetLocalSize(*T,&ml,NULL);
    208:     if (rank==size-1) ml++;
    209:     MatSetSizes(*M,ml,ml,mg+1,mg+1);
    210:     MatSetFromOptions(*M);
    211:     MatSetUp(*M);
    212:     /* Preallocate M */
    213:     if (size>1) {
    214:       MatPreallocateInitialize(comm,ml,ml,dnz,onz);
    215:       for (i=m0;i<m1;i++) {
    216:         MatGetRow(*T,i,&ncols,&cols,NULL);
    217:         MatPreallocateSet(i,ncols,cols,dnz,onz);
    218:         MatPreallocateSet(i,1,&mg,dnz,onz);
    219:         MatRestoreRow(*T,i,&ncols,&cols,NULL);
    220:       }
    221:       if (rank==size-1) {
    222:         PetscCalloc1(mg+1,&cols2);
    223:         for (i=0;i<mg+1;i++) cols2[i]=i;
    224:         MatPreallocateSet(m1,mg+1,cols2,dnz,onz);
    225:         PetscFree(cols2);
    226:       }
    227:       MatMPIAIJSetPreallocation(*M,0,dnz,0,onz);
    228:       MatPreallocateFinalize(dnz,onz);
    229:     } else {
    230:       PetscCalloc1(mg+1,&nnz);
    231:       for (i=0;i<mg;i++) {
    232:         MatGetRow(*T,i,&ncols,NULL,NULL);
    233:         nnz[i] = ncols+1;
    234:         MatRestoreRow(*T,i,&ncols,NULL,NULL);
    235:       }
    236:       nnz[mg] = mg+1;
    237:       MatSeqAIJSetPreallocation(*M,0,nnz);
    238:       PetscFree(nnz);
    239:     }
    240:   }
    241:   PEPEvaluateFunctionDerivatives(pep,pep->eigr[idx],coeffs);
    242:   for (i=0;i<nmat && PetscAbsScalar(coeffs[i])==0.0;i++);
    243:   MatMult(A[i],v,w);
    244:   if (coeffs[i]!=1.0) {
    245:     VecScale(w,coeffs[i]);
    246:   }
    247:   for (i++;i<nmat;i++) {
    248:     MatMult(A[i],v,q);
    249:     VecAXPY(w,coeffs[i],q);
    250:   }
    251:
    252:   /* Set values */
    253:   PetscMalloc1(m1-m0,&cols2);
    254:   for (i=0;i<m1-m0;i++) cols2[i]=m0+i;
    255:   VecGetArrayRead(w,&array);
    256:   for (i=m0;i<m1;i++) {
    257:     MatGetRow(*T,i,&ncols,&cols,&vals);
    258:     MatSetValues(*M,1,&i,ncols,cols,vals,INSERT_VALUES);
    259:     MatRestoreRow(*T,i,&ncols,&cols,&vals);
    260:     MatSetValues(*M,1,&i,1,&mg,array+i-m0,INSERT_VALUES);
    261:   }
    262:   VecRestoreArrayRead(w,&array);
    263:   VecConjugate(v);
    264:   VecGetArrayRead(v,&array);
    265:   MatSetValues(*M,1,&mg,m1-m0,cols2,array,INSERT_VALUES);
    266:   MatSetValues(*M,1,&mg,1,&mg,&zero,INSERT_VALUES);
    267:   VecRestoreArrayRead(v,&array);
    268:   VecConjugate(v);
    269:   MatAssemblyBegin(*M,MAT_FINAL_ASSEMBLY);
    270:   MatAssemblyEnd(*M,MAT_FINAL_ASSEMBLY);
    271:   PetscFree(cols2);
    272:   PetscFree(coeffs);
    273:   return(0);
    274: }

    278: PetscErrorCode PEPNewtonRefinementSimple(PEP pep,PetscInt *maxits,PetscReal *tol,PetscInt k)
    279: {
    280:   PetscErrorCode    ierr;
    281:   PetscInt          i,n,its,idx=0,*idx_sc,*its_sc,color;
    282:   PetscMPIInt       rank,size;
    283:   KSP               ksp;
    284:   Mat               M=NULL,T=NULL;
    285:   MPI_Comm          comm;
    286:   Vec               r,v,dv,rr=NULL,dvv=NULL,t[2];
    287:   PetscScalar       *array2;
    288:   const PetscScalar *array;
    289:   PetscReal         norm,error;
    290:   PetscBool         ini=PETSC_TRUE,sc_pend,solved=PETSC_FALSE;
    291:   PEPSimpNRefctx    *ctx;
    292:   KSPConvergedReason reason;

    295:   PetscLogEventBegin(PEP_Refine,pep,0,0,0);
    296:   PEPSimpleNRefSetUp(pep,&ctx);
    297:   its = (maxits)?*maxits:NREF_MAXIT;
    298:   comm = (pep->npart==1)?PetscObjectComm((PetscObject)pep):PetscSubcommChild(pep->refinesubc);
    299:   PEPRefineGetKSP(pep,&ksp);
    300:   if (pep->npart==1) {
    301:     BVGetColumn(pep->V,0,&v);
    302:   } else v = ctx->v;
    303:   VecDuplicate(v,&r);
    304:   VecDuplicate(v,&dv);
    305:   VecDuplicate(v,&t[0]);
    306:   VecDuplicate(v,&t[1]);
    307:   if (pep->npart==1) { BVRestoreColumn(pep->V,0,&v); }
    308:   MPI_Comm_size(comm,&size);
    309:   MPI_Comm_rank(comm,&rank);
    310:   VecGetLocalSize(r,&n);
    311:   PetscMalloc2(pep->npart,&idx_sc,pep->npart,&its_sc);
    312:   for (i=0;i<pep->npart;i++) its_sc[i] = 0;
    313:   color = (pep->npart==1)?0:pep->refinesubc->color;
    314:
    315:   /* Loop performing iterative refinements */
    316:   while (!solved) {
    317:     for (i=0;i<pep->npart;i++) {
    318:       sc_pend = PETSC_TRUE;
    319:       if (its_sc[i]==0) {
    320:         idx_sc[i] = idx++;
    321:         if (idx_sc[i]>=k) {
    322:           sc_pend = PETSC_FALSE;
    323:         } else {
    324:           PEPSimpleNRefScatterEigenvector(pep,ctx,i,idx_sc[i]);
    325:         }
    326:       }  else { /* Gather Eigenpair from subcommunicator i */
    327:         PEPSimpleNRefGatherEigenpair(pep,ctx,i,idx_sc[i]);
    328:       }
    329:       while (sc_pend) {
    330:         if (tol) {
    331:           PEPComputeError(pep,idx_sc[i],PEP_ERROR_BACKWARD,&error);
    332:         }
    333:         if (error<=*tol || its_sc[i]>=its) {
    334:           idx_sc[i] = idx++;
    335:           its_sc[i] = 0;
    336:           if (idx_sc[i]<k) { PEPSimpleNRefScatterEigenvector(pep,ctx,i,idx_sc[i]); }
    337:         } else {
    338:           sc_pend = PETSC_FALSE;
    339:           its_sc[i]++;
    340:         }
    341:         if (idx_sc[i]>=k) sc_pend = PETSC_FALSE;
    342:       }
    343:     }
    344:     solved = PETSC_TRUE;
    345:     for (i=0;i<pep->npart&&solved;i++) solved = (idx_sc[i]<k)?PETSC_FALSE:PETSC_TRUE;
    346:     if (idx_sc[color]<k) {
    347: #if !defined(PETSC_USE_COMPLEX)
    348:       if (pep->eigi[idx_sc[color]]!=0.0) SETERRQ(PetscObjectComm((PetscObject)pep),1,"Simple Refinement not implemented in real scalars for complex eigenvalues");
    349: #endif
    350:       if (pep->npart==1) {
    351:         BVGetColumn(pep->V,idx_sc[color],&v);
    352:       } else v = ctx->v;
    353:       PEPSimpleNRefSetUpSystem(pep,ctx->A,idx_sc[color],&M,&T,ini,t,v);
    354:       KSPSetOperators(ksp,M,M);
    355:       if (ini) {
    356:         KSPSetFromOptions(ksp);
    357:         MatCreateVecs(M,&dvv,NULL);
    358:         VecDuplicate(dvv,&rr);
    359:         ini = PETSC_FALSE;
    360:       }
    361:       MatMult(T,v,r);
    362:       VecGetArrayRead(r,&array);
    363:       if (rank==size-1) {
    364:         VecGetArray(rr,&array2);
    365:         PetscMemcpy(array2,array,n*sizeof(PetscScalar));
    366:         array2[n] = 0.0;
    367:         VecRestoreArray(rr,&array2);
    368:       } else {
    369:         VecPlaceArray(rr,array);
    370:       }
    371:       KSPSolve(ksp,rr,dvv);
    372:       KSPGetConvergedReason(ksp,&reason);
    373:       if (reason<0) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_NOT_CONVERGED,"KSP did not converge (reason=%s)",KSPConvergedReasons[reason]);
    374:       if (rank != size-1) {
    375:         VecResetArray(rr);
    376:       }
    377:       VecRestoreArrayRead(r,&array);
    378:       VecGetArrayRead(dvv,&array);
    379:       VecPlaceArray(dv,array);
    380:       VecAXPY(v,-1.0,dv);
    381:       VecNorm(v,NORM_2,&norm);
    382:       VecScale(v,1.0/norm);
    383:       VecResetArray(dv);
    384:       if (rank==size-1) pep->eigr[idx_sc[color]] -= array[n];
    385:       VecRestoreArrayRead(dvv,&array);
    386:       if (pep->npart==1) { BVRestoreColumn(pep->V,idx_sc[color],&v); }
    387:     }
    388:   }
    389:   MatDestroy(&M);
    390:   MatDestroy(&T);
    391:   VecDestroy(&t[0]);
    392:   VecDestroy(&t[1]);
    393:   VecDestroy(&dv);
    394:   VecDestroy(&dvv);
    395:   VecDestroy(&r);
    396:   VecDestroy(&rr);
    397:   PetscFree2(idx_sc,its_sc);
    398:   if (pep->npart>1) {
    399:     VecDestroy(&ctx->vg);
    400:     VecDestroy(&ctx->v);
    401:     for (i=0;i<pep->nmat;i++) {
    402:       MatDestroy(&ctx->A[i]);
    403:     }
    404:     for (i=0;i<pep->npart;i++) {
    405:       VecScatterDestroy(&ctx->scatter_id[i]);
    406:     }
    407:     PetscFree2(ctx->A,ctx->scatter_id);
    408:   }
    409:   PetscFree(ctx);
    410:   PetscLogEventEnd(PEP_Refine,pep,0,0,0);
    411:   return(0);
    412: }