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: }