Actual source code: pepdefault.c

slepc-3.6.1 2015-09-03
Report Typos and Errors
  1: /*
  2:      This file contains some simple default routines for common PEP operations.

  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>     /*I "slepcpep.h" I*/

 28: /*@
 29:    PEPSetWorkVecs - Sets a number of work vectors into a PEP object.

 31:    Collective on PEP

 33:    Input Parameters:
 34: +  pep - polynomial eigensolver context
 35: -  nw  - number of work vectors to allocate

 37:    Developers Note:
 38:    This is PETSC_EXTERN because it may be required by user plugin PEP
 39:    implementations.

 41:    Level: developer
 42: @*/
 43: PetscErrorCode PEPSetWorkVecs(PEP pep,PetscInt nw)
 44: {
 46:   Vec            t;

 49:   if (pep->nwork < nw) {
 50:     VecDestroyVecs(pep->nwork,&pep->work);
 51:     pep->nwork = nw;
 52:     BVGetColumn(pep->V,0,&t);
 53:     VecDuplicateVecs(t,nw,&pep->work);
 54:     BVRestoreColumn(pep->V,0,&t);
 55:     PetscLogObjectParents(pep,nw,pep->work);
 56:   }
 57:   return(0);
 58: }

 62: /*
 63:   PEPConvergedEigRelative - Checks convergence relative to the eigenvalue.
 64: */
 65: PetscErrorCode PEPConvergedEigRelative(PEP pep,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
 66: {
 67:   PetscReal w;

 70:   w = SlepcAbsEigenvalue(eigr,eigi);
 71:   *errest = res/w;
 72:   return(0);
 73: }

 77: /*
 78:   PEPConvergedLinear - Checks convergence related to the linearized eigenproblem.
 79: */
 80: PetscErrorCode PEPConvergedLinear(PEP pep,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
 81: {
 83:   PetscScalar    er,ei;
 84:   PetscBool      flg;
 86:   STGetTransform(pep->st,&flg);
 87:   if (!flg) {
 88:     PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&flg);
 89:   } else flg = PETSC_FALSE;
 90:   er = eigr; ei = eigi;
 91:   STBackTransform(pep->st,1,&er,&ei);
 92:   if (flg) *errest = res*((pep->nrml[0]+PetscAbsScalar(pep->target)*pep->nrml[1])/SlepcAbsEigenvalue(eigr,eigi))/(pep->nrml[0]+SlepcAbsEigenvalue(er,ei)*pep->nrml[1]);
 93:   else *errest = res*pep->nrml[1]/(pep->nrml[0]+SlepcAbsEigenvalue(er,ei)*pep->nrml[1]);
 94:   return(0);
 95: }

 99: /*
100:   PEPConvergedNorm - Checks convergence relative to the matrix norms.
101: */
102: PetscErrorCode PEPConvergedNorm(PEP pep,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
103: {
104:   PetscReal      w=0.0,t;
105:   PetscInt       j;
106:   PetscBool      flg;

110:   /* initialization of matrix norms */
111:   if (!pep->nrma[pep->nmat-1]) {
112:     for (j=0;j<pep->nmat;j++) {
113:       MatHasOperation(pep->A[j],MATOP_NORM,&flg);
114:       if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"The convergence test related to the matrix norms requires a matrix norm operation");
115:       MatNorm(pep->A[j],NORM_INFINITY,&pep->nrma[j]);
116:     }
117:   }
118:   t = SlepcAbsEigenvalue(eigr,eigi);
119:   for (j=pep->nmat-1;j>=0;j--) {
120:     w = w*t+pep->nrma[j];
121:   }
122:   *errest = res/w;
123:   return(0);
124: }

128: /*
129:   PEPConvergedAbsolute - Checks convergence absolutely.
130: */
131: PetscErrorCode PEPConvergedAbsolute(PEP pep,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
132: {
134:   *errest = res;
135:   return(0);
136: }

140: PetscErrorCode PEPBackTransform_Default(PEP pep)
141: {

145:   STBackTransform(pep->st,pep->nconv,pep->eigr,pep->eigi);
146:   return(0);
147: }

151: PetscErrorCode PEPComputeVectors_Default(PEP pep)
152: {
154:   PetscInt       i;
155:   Vec            v;
156: #if !defined(PETSC_USE_COMPLEX)
157:   Vec            v1;
158: #endif

161:   PEPExtractVectors(pep);

163:   /* Fix eigenvectors if balancing was used */
164:   if ((pep->scale==PEP_SCALE_DIAGONAL || pep->scale==PEP_SCALE_BOTH) && pep->Dr && (pep->refine!=PEP_REFINE_MULTIPLE)) {
165:     for (i=0;i<pep->nconv;i++) {
166:       BVGetColumn(pep->V,i,&v);
167:       VecPointwiseMult(v,v,pep->Dr);
168:       BVRestoreColumn(pep->V,i,&v);
169:     }
170:   }

172:   /* normalization */
173:   for (i=0;i<pep->nconv;i++) {
174: #if !defined(PETSC_USE_COMPLEX)
175:     if (pep->eigi[i]!=0.0) {   /* first eigenvalue of a complex conjugate pair */
176:       BVGetColumn(pep->V,i,&v);
177:       BVGetColumn(pep->V,i+1,&v1);
178:       SlepcVecNormalize(v,v1,PETSC_TRUE,NULL);
179:       BVRestoreColumn(pep->V,i,&v);
180:       BVRestoreColumn(pep->V,i+1,&v1);
181:       i++;
182:     } else   /* real eigenvalue */
183: #endif
184:     {
185:       BVGetColumn(pep->V,i,&v);
186:       SlepcVecNormalize(v,NULL,PETSC_FALSE,NULL);
187:       BVRestoreColumn(pep->V,i,&v);
188:     }
189:   }
190:   return(0);
191: }

195: /*
196:    PEPKrylovConvergence - This is the analogue to EPSKrylovConvergence, but
197:    for polynomial Krylov methods.

199:    Differences:
200:    - Always non-symmetric
201:    - Does not check for STSHIFT
202:    - No correction factor
203:    - No support for true residual
204: */
205: PetscErrorCode PEPKrylovConvergence(PEP pep,PetscBool getall,PetscInt kini,PetscInt nits,PetscReal beta,PetscInt *kout)
206: {
208:   PetscInt       k,newk,marker,ld,inside;
209:   PetscScalar    re,im;
210:   PetscReal      resnorm;
211:   PetscBool      istrivial;

214:   RGIsTrivial(pep->rg,&istrivial);
215:   DSGetLeadingDimension(pep->ds,&ld);
216:   marker = -1;
217:   if (pep->trackall) getall = PETSC_TRUE;
218:   for (k=kini;k<kini+nits;k++) {
219:     /* eigenvalue */
220:     re = pep->eigr[k];
221:     im = pep->eigi[k];
222:     if (!istrivial) {
223:       STBackTransform(pep->st,1,&re,&im);
224:       RGCheckInside(pep->rg,1,&re,&im,&inside);
225:       if (marker==-1 && inside<=0) marker = k;
226:       re = pep->eigr[k];
227:       im = pep->eigi[k];
228:     }
229:     newk = k;
230:     DSVectors(pep->ds,DS_MAT_X,&newk,&resnorm);
231:     resnorm *= beta;
232:     /* error estimate */
233:     (*pep->converged)(pep,re,im,resnorm,&pep->errest[k],pep->convergedctx);
234:     if (marker==-1 && pep->errest[k] >= pep->tol) marker = k;
235:     if (newk==k+1) {
236:       pep->errest[k+1] = pep->errest[k];
237:       k++;
238:     }
239:     if (marker!=-1 && !getall) break;
240:   }
241:   if (marker!=-1) k = marker;
242:   *kout = k;
243:   return(0);
244: }

248: /*
249:   PEPBuildDiagonalScaling - compute two diagonal matrices to be applied for balancing 
250:   in polynomial eigenproblems.
251: */
252: PetscErrorCode PEPBuildDiagonalScaling(PEP pep)
253: {
255:   PetscInt       it,i,j,k,nmat,nr,e,nz,lst,lend,nc=0,*cols,emax,emin,emaxl,eminl;
256:   const PetscInt *cidx,*ridx;
257:   Mat            M,*T,A;
258:   PetscMPIInt    n;
259:   PetscBool      cont=PETSC_TRUE,flg=PETSC_FALSE;
260:   PetscScalar    *array,*Dr,*Dl,t;
261:   PetscReal      l2,d,*rsum,*aux,*csum,w=1.0;
262:   MatStructure   str;
263:   MatInfo        info;

266:   l2 = 2*PetscLogReal(2.0);
267:   nmat = pep->nmat;
268:   PetscMPIIntCast(pep->n,&n);
269:   STGetMatStructure(pep->st,&str);
270:   PetscMalloc1(nmat,&T);
271:   for (k=0;k<nmat;k++) {
272:     STGetTOperators(pep->st,k,&T[k]);
273:   }
274:   /* Form local auxiliar matrix M */
275:   PetscObjectTypeCompareAny((PetscObject)T[0],&cont,MATMPIAIJ,MATSEQAIJ,"");
276:   if (!cont) SETERRQ(PetscObjectComm((PetscObject)T[0]),PETSC_ERR_SUP,"Only for MPIAIJ or SEQAIJ matrix types");
277:   PetscObjectTypeCompare((PetscObject)T[0],MATMPIAIJ,&cont);
278:   if (cont) {
279:     MatMPIAIJGetLocalMat(T[0],MAT_INITIAL_MATRIX,&M);
280:     flg = PETSC_TRUE; 
281:   } else {
282:     MatDuplicate(T[0],MAT_COPY_VALUES,&M);
283:   }
284:   MatGetInfo(M,MAT_LOCAL,&info);
285:   nz = info.nz_used;
286:   MatSeqAIJGetArray(M,&array);
287:   for (i=0;i<nz;i++) {
288:     t = PetscAbsScalar(array[i]);
289:     array[i] = t*t;
290:   }
291:   MatSeqAIJRestoreArray(M,&array);
292:   for (k=1;k<nmat;k++) {
293:     if (flg) {
294:       MatMPIAIJGetLocalMat(T[k],MAT_INITIAL_MATRIX,&A);
295:     } else {
296:       if (str==SAME_NONZERO_PATTERN) {
297:         MatCopy(T[k],A,SAME_NONZERO_PATTERN);
298:       } else {
299:         MatDuplicate(T[k],MAT_COPY_VALUES,&A);
300:       }
301:     }
302:     MatGetInfo(A,MAT_LOCAL,&info);
303:     nz = info.nz_used;
304:     MatSeqAIJGetArray(A,&array);
305:     for (i=0;i<nz;i++) {
306:       t = PetscAbsScalar(array[i]);
307:       array[i] = t*t;
308:     }
309:     MatSeqAIJRestoreArray(A,&array);
310:     w *= pep->slambda*pep->slambda*pep->sfactor;
311:     MatAXPY(M,w,A,str);
312:     if (flg || str!=SAME_NONZERO_PATTERN || k==nmat-2) {
313:       MatDestroy(&A);
314:     } 
315:   }
316:   MatGetRowIJ(M,0,PETSC_FALSE,PETSC_FALSE,&nr,&ridx,&cidx,&cont);
317:   if (!cont) SETERRQ(PetscObjectComm((PetscObject)T[0]), PETSC_ERR_SUP,"It is not possible to compute scaling diagonals for these PEP matrices");
318:   MatGetInfo(M,MAT_LOCAL,&info);
319:   nz = info.nz_used;
320:   VecGetOwnershipRange(pep->Dl,&lst,&lend);
321:   PetscMalloc4(nr,&rsum,pep->n,&csum,pep->n,&aux,PetscMin(pep->n-lend+lst,nz),&cols);
322:   VecSet(pep->Dr,1.0);
323:   VecSet(pep->Dl,1.0);
324:   VecGetArray(pep->Dl,&Dl);
325:   VecGetArray(pep->Dr,&Dr);
326:   MatSeqAIJGetArray(M,&array);
327:   PetscMemzero(aux,pep->n*sizeof(PetscReal));
328:   for (j=0;j<nz;j++) {
329:     /* Search non-zero columns outsize lst-lend */
330:     if (aux[cidx[j]]==0 && (cidx[j]<lst || lend<=cidx[j])) cols[nc++] = cidx[j];
331:     /* Local column sums */
332:     aux[cidx[j]] += PetscAbsScalar(array[j]);
333:   }
334:   for (it=0;it<pep->sits && cont;it++) {
335:     emaxl = 0; eminl = 0;
336:     /* Column sum  */    
337:     if (it>0) { /* it=0 has been already done*/
338:       MatSeqAIJGetArray(M,&array);
339:       PetscMemzero(aux,pep->n*sizeof(PetscReal));
340:       for (j=0;j<nz;j++) aux[cidx[j]] += PetscAbsScalar(array[j]);
341:       MatSeqAIJRestoreArray(M,&array); 
342:     }
343:     MPI_Allreduce(aux,csum,n,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)pep->Dr));
344:     /* Update Dr */
345:     for (j=lst;j<lend;j++) {
346:       d = PetscLogReal(csum[j])/l2;
347:       e = -(PetscInt)((d < 0)?(d-0.5):(d+0.5));
348:       d = PetscPowReal(2.0,e);
349:       Dr[j-lst] *= d;
350:       aux[j] = d*d;
351:       emaxl = PetscMax(emaxl,e);
352:       eminl = PetscMin(eminl,e);
353:     }
354:     for (j=0;j<nc;j++) {
355:       d = PetscLogReal(csum[cols[j]])/l2;
356:       e = -(PetscInt)((d < 0)?(d-0.5):(d+0.5));
357:       d = PetscPowReal(2.0,e);
358:       aux[cols[j]] = d*d;
359:       emaxl = PetscMax(emaxl,e);
360:       eminl = PetscMin(eminl,e);
361:     }
362:     /* Scale M */
363:     MatSeqAIJGetArray(M,&array);
364:     for (j=0;j<nz;j++) {
365:       array[j] *= aux[cidx[j]];
366:     }
367:     MatSeqAIJRestoreArray(M,&array);
368:     /* Row sum */    
369:     PetscMemzero(rsum,nr*sizeof(PetscReal));
370:     MatSeqAIJGetArray(M,&array);
371:     for (i=0;i<nr;i++) {
372:       for (j=ridx[i];j<ridx[i+1];j++) rsum[i] += PetscAbsScalar(array[j]);
373:       /* Update Dl */
374:       d = PetscLogReal(rsum[i])/l2;
375:       e = -(PetscInt)((d < 0)?(d-0.5):(d+0.5));
376:       d = PetscPowReal(2.0,e);
377:       Dl[i] *= d;
378:       /* Scale M */
379:       for (j=ridx[i];j<ridx[i+1];j++) array[j] *= d*d;
380:       emaxl = PetscMax(emaxl,e);
381:       eminl = PetscMin(eminl,e);      
382:     }
383:     MatSeqAIJRestoreArray(M,&array);  
384:     /* Compute global max and min */
385:     MPI_Allreduce(&emaxl,&emax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)pep->Dl));
386:     MPI_Allreduce(&eminl,&emin,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)pep->Dl));
387:     if (emax<=emin+2) cont = PETSC_FALSE;
388:   }
389:   VecRestoreArray(pep->Dr,&Dr);
390:   VecRestoreArray(pep->Dl,&Dl);
391:   /* Free memory*/
392:   MatDestroy(&M);
393:   PetscFree4(rsum,csum,aux,cols);
394:   PetscFree(T);
395:   return(0);
396: }

400: /*
401:    PEPComputeScaleFactor - compute sfactor as described in [Betcke 2008].
402: */
403: PetscErrorCode PEPComputeScaleFactor(PEP pep)
404: {
406:   PetscBool      has0,has1,flg;
407:   PetscReal      norm0,norm1;
408:   Mat            T[2];
409:   PEPBasis       basis;
410:   PetscInt       i;

413:   if (pep->scale==PEP_SCALE_NONE || pep->scale==PEP_SCALE_DIAGONAL) {  /* no scalar scaling */
414:     pep->sfactor = 1.0;
415:     pep->dsfactor = 1.0;
416:     return(0);
417:   }
418:   if (pep->sfactor_set) return(0);  /* user provided value */
419:   pep->sfactor = 1.0;
420:   pep->dsfactor = 1.0;
421:   PEPGetBasis(pep,&basis);
422:   if (basis==PEP_BASIS_MONOMIAL) {
423:     STGetTransform(pep->st,&flg);
424:     if (flg) {
425:       STGetTOperators(pep->st,0,&T[0]);
426:       STGetTOperators(pep->st,pep->nmat-1,&T[1]);
427:     } else {
428:       T[0] = pep->A[0];
429:       T[1] = pep->A[pep->nmat-1];
430:     }
431:     if (pep->nmat>2) {
432:       MatHasOperation(T[0],MATOP_NORM,&has0);
433:       MatHasOperation(T[1],MATOP_NORM,&has1);
434:       if (has0 && has1) {
435:         MatNorm(T[0],NORM_INFINITY,&norm0);
436:         MatNorm(T[1],NORM_INFINITY,&norm1);
437:         pep->sfactor = PetscPowReal(norm0/norm1,1.0/(pep->nmat-1));
438:         pep->dsfactor = norm1;
439:         for (i=pep->nmat-2;i>0;i--) {
440:           STGetTOperators(pep->st,i,&T[1]);
441:           MatHasOperation(T[1],MATOP_NORM,&has1);
442:           if (has1) {
443:             MatNorm(T[1],NORM_INFINITY,&norm1);
444:             pep->dsfactor = pep->dsfactor*pep->sfactor+norm1;
445:           } else break;
446:         }
447:         if (has1) {
448:           pep->dsfactor = pep->dsfactor*pep->sfactor+norm0;
449:           pep->dsfactor = pep->nmat/pep->dsfactor;
450:         } else pep->dsfactor = 1.0;
451:       } 
452:     }
453:   } 
454:   return(0);
455: }

459: /*
460:    PEPComputeLinearNorms - compute norm for the linearized problem.
461: */
462: PetscErrorCode PEPComputeLinearNorms(PEP pep)
463: {
464:   PetscErrorCode    ierr;
465:   PetscReal         out=0.0,nrmd=0.0,max=0.0,summ,summrow,summd=0.0;
466:   PetscReal         *pbc,*a,*b,*g,t;
467:   PetscInt          i,m0,m1,ncols,j,k;
468:   const PetscScalar *vals;
469:   Mat               *T;

472:   PetscMalloc2(3*pep->nmat,&pbc,pep->nmat,&T);
473:   for (i=0;i<pep->nmat;i++) {
474:     STGetTOperators(pep->st,i,&T[i]);
475:   }
476:   a=pbc; b=pbc+pep->nmat; g = b+pep->nmat;
477:   PEPBasisCoefficients(pep,pbc);
478:   out = b[0]+a[0];
479:   for (i=1;i<pep->nmat-2;i++) out = PetscMax(out,a[i]+b[i]+g[i]);
480:   MatGetOwnershipRange(T[0],&m0,&m1);
481:   for (i=m0;i<m1;i++) {
482:     summrow = 0.0;
483:     t = 1.0;
484:     for (j=0;j<pep->nmat;j++) {
485:       summ = 0.0;
486:       MatGetRow(T[j],i,&ncols,NULL,&vals);
487:       for (k=0;k<ncols;k++) summ += PetscAbsScalar(vals[k]);
488:       MatRestoreRow(T[j],i,&ncols,NULL,&vals);
489:       summ *= t;
490:       if (j==pep->nmat-1) {
491:         summd = summ;
492:         summ *= (b[pep->nmat-2]+g[pep->nmat-2])/a[pep->nmat-2];
493:       } else summ *= a[pep->nmat-2];
494:       summrow += summ;
495:       t *= pep->sfactor;
496:     }
497:     nrmd = PetscMax(nrmd,summd);
498:     max = PetscMax(max,summrow);
499:   }
500:   max = PetscMax(max*pep->dsfactor,out);
501:   MPI_Allreduce(&max,&pep->nrml[0],1,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)pep));
502:   MPI_Allreduce(&nrmd,&pep->nrml[1],1,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)pep));
503:   pep->nrml[1] = PetscMax(1.0,pep->nrml[1]*pep->dsfactor);
504:   PetscFree2(pbc,T);
505:   return(0);
506: }

510: /*
511:    PEPBasisCoefficients - compute polynomial basis coefficients
512: */
513: PetscErrorCode PEPBasisCoefficients(PEP pep,PetscReal *pbc)
514: {
515:   PetscReal *ca,*cb,*cg;
516:   PetscInt  k,nmat=pep->nmat;
517:   
519:   ca = pbc;
520:   cb = pbc+nmat;
521:   cg = pbc+2*nmat;
522:   switch (pep->basis) {
523:   case PEP_BASIS_MONOMIAL:
524:     for (k=0;k<nmat;k++) {
525:       ca[k] = 1.0; cb[k] = 0.0; cg[k] = 0.0;
526:     }
527:     break;
528:   case PEP_BASIS_CHEBYSHEV1:
529:     ca[0] = 1.0; cb[0] = 0.0; cg[0] = 0.0;
530:     for (k=1;k<nmat;k++) {
531:       ca[k] = .5; cb[k] = 0.0; cg[k] = .5;
532:     }
533:     break;
534:   case PEP_BASIS_CHEBYSHEV2:
535:     ca[0] = .5; cb[0] = 0.0; cg[0] = 0.0;
536:     for (k=1;k<nmat;k++) {
537:       ca[k] = .5; cb[k] = 0.0; cg[k] = .5;
538:     }    
539:     break;
540:   case PEP_BASIS_LEGENDRE:
541:     ca[0] = 1.0; cb[0] = 0.0; cg[0] = 0.0;
542:     for (k=1;k<nmat;k++) {
543:       ca[k] = k+1; cb[k] = -2*k; cg[k] = k;
544:     }
545:     break;
546:   case PEP_BASIS_LAGUERRE:
547:     ca[0] = -1.0; cb[0] = 0.0; cg[0] = 0.0;
548:     for (k=1;k<nmat;k++) {
549:       ca[k] = -(k+1); cb[k] = 2*k+1; cg[k] = -k;
550:     }
551:     break;
552:   case PEP_BASIS_HERMITE:
553:     ca[0] = .5; cb[0] = 0.0; cg[0] = 0.0;
554:     for (k=1;k<nmat;k++) {
555:       ca[k] = .5; cb[k] = 0.0; cg[k] = -k;
556:     }
557:     break;
558:   default:
559:     SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid 'basis' value");
560:   }
561:   return(0);
562: }

566: /*
567:    PEPEvaluateBasis - evaluate the polynomial basis on a given parameter sigma
568: */
569: PetscErrorCode PEPEvaluateBasis(PEP pep,PetscScalar sigma,PetscScalar isigma,PetscScalar *vals,PetscScalar *ivals)
570: {
571:   PetscInt   nmat=pep->nmat,k;
572:   PetscReal  *a=pep->pbc,*b=pep->pbc+nmat,*g=pep->pbc+2*nmat;
573:   
575:   if (ivals) for (k=0;k<nmat;k++) ivals[k] = 0.0;
576:   vals[0] = 1.0;
577:   vals[1] = (sigma-b[0])/a[0];
578: #if !defined(PETSC_USE_COMPLEX)
579:   if (ivals) ivals[1] = isigma/a[0];
580: #endif
581:   for (k=2;k<nmat;k++) {
582:     vals[k] = ((sigma-b[k-1])*vals[k-1]-g[k-1]*vals[k-2])/a[k-1];
583:     if (ivals) vals[k] -= isigma*ivals[k-1]/a[k-1];
584: #if !defined(PETSC_USE_COMPLEX)
585:     if (ivals) ivals[k] = ((sigma-b[k-1])*ivals[k-1]+isigma*vals[k-1]-g[k-1]*ivals[k-2])/a[k-1];
586: #endif
587:   }
588:   return(0);
589: }