Actual source code: peprefine.c
slepc-3.6.1 2015-09-03
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: }