Subversion Repositories slepc-dev

Rev

Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2404 jroman 1
/*                      
2
 
3
   SLEPc eigensolver: "krylovschur"
4
 
5
   Method: Krylov-Schur with spectrum slicing for symmetric eigenproblems
6
 
7
   References:
8
 
9
       [1] R.G. Grimes et al., "A shifted block Lanczos algorithm for solving
10
           sparse symmetric generalized eigenproblems", SIAM J. Matrix Analysis
11
           and App., 15(1), pp. 228–272, 1994.
12
 
13
       [2] G.W. Stewart, "A Krylov-Schur Algorithm for Large Eigenproblems",
14
           SIAM J. Matrix Analysis and App., 23(3), pp. 601-614, 2001.
15
 
16
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
17
   SLEPc - Scalable Library for Eigenvalue Problem Computations
2575 eromero 18
   Copyright (c) 2002-2011, Universitat Politecnica de Valencia, Spain
2404 jroman 19
 
20
   This file is part of SLEPc.
2459 carcamgo 21
 
2404 jroman 22
   SLEPc is free software: you can redistribute it and/or modify it under  the
23
   terms of version 3 of the GNU Lesser General Public License as published by
24
   the Free Software Foundation.
25
 
26
   SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
27
   WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
28
   FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
29
   more details.
30
 
31
   You  should have received a copy of the GNU Lesser General  Public  License
32
   along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
33
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34
*/
35
 
36
#include <private/epsimpl.h>                /*I "slepceps.h" I*/
37
#include <slepcblaslapack.h>
38
 
39
extern PetscErrorCode EPSProjectedKSSym(EPS,PetscInt,PetscInt,PetscReal*,PetscReal*,PetscScalar*,PetscScalar*,PetscReal*,PetscInt*);
40
 
2459 carcamgo 41
 
42
/* Type of data characterizing a shift (place from where an eps is applied) */
43
typedef struct _n_shift *shift;
44
struct _n_shift{
45
  PetscReal     value;
46
  PetscInt      inertia;
2596 carcamgo 47
  PetscBool     comp[2]; /* Shows completion of subintervals (left and right) */
48
  shift         neighb[2];/* Adjacent shifts */
49
  PetscInt      index;/* Index in eig where found values are stored */
50
  PetscInt      neigs; /* Number of values found */
51
  PetscReal     ext[2];   /* Limits for accepted values */
52
  PetscInt      nsch[2];  /* Number of missing values for each subinterval */
53
  PetscInt      nconv[2]; /* Converged on each side (accepted or not)*/
2459 carcamgo 54
};
55
 
56
/* Type of data  for storing the state of spectrum slicing*/
2464 carcamgo 57
struct _n_SR{
2596 carcamgo 58
  PetscReal       int0,int1; /* Extremes of the interval */
59
  PetscInt        dir; /* Determines the order of values in eig (+1 incr, -1 decr) */
60
  PetscBool       hasEnd; /* Tells whether the interval has an end */
2459 carcamgo 61
  PetscInt        inertia0,inertia1;
62
  Vec             *V;
2599 carcamgo 63
  PetscScalar     *eig,*eigi,*monit;
2596 carcamgo 64
  PetscReal       *errest;
65
  PetscInt        *perm;/* Permutation for keeping the eigenvalues in order */
66
  PetscInt        numEigs; /* Number of eigenvalues in the interval */
2459 carcamgo 67
  PetscInt        indexEig;
2596 carcamgo 68
  shift           sPres; /* Present shift */
69
  shift           *pending;/* Pending shifts array */
70
  PetscInt        nPend;/* Number of pending shifts */
71
  PetscInt        maxPend;/* Size of "pending" array */
72
  Vec             *VDef; /* Vector for deflation */
73
  PetscInt        *idxDef;/* For deflation */
2459 carcamgo 74
  PetscInt        nMAXCompl;
75
  PetscInt        iterCompl;
2596 carcamgo 76
  PetscInt        itsKs; /* Krylovschur restarts */
77
  PetscInt        nleap;
78
  shift           s0;/* Initial shift */
2459 carcamgo 79
};
2464 carcamgo 80
typedef struct _n_SR  *SR;
81
 
82
/*
83
   Fills the fields of a shift structure
84
 
85
*/
2459 carcamgo 86
#undef __FUNCT__
87
#define __FUNCT__ "EPSCreateShift"
2470 jroman 88
static PetscErrorCode EPSCreateShift(EPS eps,PetscReal val, shift neighb0,shift neighb1)
2404 jroman 89
{
2459 carcamgo 90
  PetscErrorCode   ierr;
91
  shift            s,*pending2;
92
  PetscInt         i;
93
  SR               sr;
94
 
95
  PetscFunctionBegin;
96
  sr = (SR)(eps->data);
97
  ierr = PetscMalloc(sizeof(struct _n_shift),&s);CHKERRQ(ierr);
98
  s->value = val;
99
  s->neighb[0] = neighb0;
2464 carcamgo 100
  if(neighb0) neighb0->neighb[1] = s;
2459 carcamgo 101
  s->neighb[1] = neighb1;
2464 carcamgo 102
  if(neighb1) neighb1->neighb[0] = s;
2468 eromero 103
  s->comp[0] = PETSC_FALSE;
104
  s->comp[1] = PETSC_FALSE;
2459 carcamgo 105
  s->index = -1;
106
  s->neigs = 0;
2596 carcamgo 107
  s->nconv[0] = s->nconv[1] = 0;
2459 carcamgo 108
  s->nsch[0] = s->nsch[1]=0;
2596 carcamgo 109
  /* Inserts in the stack of pending shifts */
110
  /* If needed, the array is resized */
2459 carcamgo 111
  if(sr->nPend >= sr->maxPend){
112
    sr->maxPend *= 2;
113
    ierr = PetscMalloc((sr->maxPend)*sizeof(shift),&pending2);CHKERRQ(ierr);
114
    for(i=0;i < sr->nPend; i++)pending2[i] = sr->pending[i];
115
    ierr = PetscFree(sr->pending);CHKERRQ(ierr);
116
    sr->pending = pending2;
117
  }
118
  sr->pending[sr->nPend++]=s;
119
  PetscFunctionReturn(0);
120
}
121
 
122
/* Provides next shift to be computed */
123
#undef __FUNCT__
124
#define __FUNCT__ "EPSExtractShift"
125
static PetscErrorCode EPSExtractShift(EPS eps){
126
  PetscErrorCode   ierr;
127
  PetscInt         iner;
128
  Mat              F;
129
  PC               pc;
130
  KSP              ksp;
131
  SR               sr;
132
 
133
  PetscFunctionBegin;  
134
  sr = (SR)(eps->data);
135
  if(sr->nPend > 0){
136
    sr->sPres = sr->pending[--sr->nPend];
137
    ierr = STSetShift(eps->OP, sr->sPres->value);CHKERRQ(ierr);
138
    ierr = STGetKSP(eps->OP, &ksp);CHKERRQ(ierr);
139
    ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
140
    ierr = PCFactorGetMatrix(pc,&F);CHKERRQ(ierr);
141
    ierr = MatGetInertia(F,&iner,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
142
    sr->sPres->inertia = iner;
143
    eps->target = sr->sPres->value;
144
    eps->nconv = 0;
145
    eps->reason = EPS_CONVERGED_ITERATING;
2596 carcamgo 146
    eps->its = 0;
2459 carcamgo 147
   }else sr->sPres = PETSC_NULL;
148
   PetscFunctionReturn(0);
149
}
150
 
151
/*
2464 carcamgo 152
   Symmetric KrylovSchur adapted to spectrum slicing:
2596 carcamgo 153
   Allows searching an specific amount of eigenvalues in the subintervals left and right.
154
   Returns whether the search has succeeded
2459 carcamgo 155
*/
156
#undef __FUNCT__
157
#define __FUNCT__ "EPSKrylovSchur_Slice"
158
static PetscErrorCode EPSKrylovSchur_Slice(EPS eps)
159
{
2404 jroman 160
  PetscErrorCode ierr;
2459 carcamgo 161
  PetscInt       i,conv,k,l,lds,lt,nv,m,*iwork,p,j;
2404 jroman 162
  Vec            u=eps->work[0];
163
  PetscScalar    *Q;
2596 carcamgo 164
  PetscReal      *a,*b,*work,beta,rtmp;
2404 jroman 165
  PetscBool      breakdown;
2596 carcamgo 166
  PetscInt       count0,count1;
2459 carcamgo 167
  PetscReal      theta,lambda;
168
  shift          sPres;
2596 carcamgo 169
  PetscBool      complIterating;/* Shows whether iterations are made for completion */
170
  PetscBool      sch0,sch1;/* Shows whether values are looked after on each side */
2599 carcamgo 171
  PetscInt       iterCompl=0,n0,n1,aux,auxc;
2459 carcamgo 172
  SR             sr;
173
 
2404 jroman 174
  PetscFunctionBegin;
2596 carcamgo 175
  /* Spectrum slicing data */
2459 carcamgo 176
  sr = (SR)eps->data;
177
  sPres = sr->sPres;
178
  complIterating =PETSC_FALSE;
179
  sch1 = sch0 = PETSC_TRUE;
2404 jroman 180
  lds = PetscMin(eps->mpd,eps->ncv);
181
  ierr = PetscMalloc(lds*lds*sizeof(PetscReal),&work);CHKERRQ(ierr);
182
  ierr = PetscMalloc(lds*lds*sizeof(PetscScalar),&Q);CHKERRQ(ierr);
183
  ierr = PetscMalloc(2*lds*sizeof(PetscInt),&iwork);CHKERRQ(ierr);
184
  lt = PetscMin(eps->nev+eps->mpd,eps->ncv);
2459 carcamgo 185
  ierr = PetscMalloc(lt*sizeof(PetscReal),&a);CHKERRQ(ierr);
186
  ierr = PetscMalloc(lt*sizeof(PetscReal),&b);CHKERRQ(ierr);
2596 carcamgo 187
  count0=0;count1=0; /* Found on both sides */
2599 carcamgo 188
 
189
   /* filling in values for the monitor */
190
  for(i=0;i<sr->indexEig;i++){
191
      sr->monit[i]=1.0/(sr->eig[i] - sPres->value);
192
    }
2459 carcamgo 193
 
2404 jroman 194
  /* Get the starting Lanczos vector */
195
  ierr = EPSGetStartVector(eps,0,eps->V[0],PETSC_NULL);CHKERRQ(ierr);
196
  l = 0;
197
  /* Restart loop */
198
  while (eps->reason == EPS_CONVERGED_ITERATING) {
2596 carcamgo 199
    eps->its++; sr->itsKs++;
2404 jroman 200
    /* Compute an nv-step Lanczos factorization */
201
    m = PetscMin(eps->nconv+eps->mpd,eps->ncv);
2459 carcamgo 202
 
2404 jroman 203
    ierr = EPSFullLanczos(eps,a+l,b+l,eps->V,eps->nconv+l,&m,u,&breakdown);CHKERRQ(ierr);
204
    nv = m - eps->nconv;
205
    beta = b[nv-1];
206
 
2459 carcamgo 207
    /* Solve projected problem and compute residual norm estimates */
2404 jroman 208
    ierr = EPSProjectedKSSym(eps,nv,l,a,b,eps->eigr+eps->nconv,Q,work,iwork);CHKERRQ(ierr);
2596 carcamgo 209
    /* Residual */
2583 jroman 210
    ierr = EPSKrylovConvergence(eps,PETSC_TRUE,PETSC_TRUE,eps->nconv,nv,PETSC_NULL,nv,Q,eps->V+eps->nconv,nv,beta,1.0,&k,PETSC_NULL);CHKERRQ(ierr);
2596 carcamgo 211
    /* Check convergence */
212
    conv=k=j=0;
213
    for(i=0;i<nv;i++)if(eps->errest[eps->nconv+i] < eps->tol)conv++;
214
    for(i=0;i<nv;i++){
215
      if(eps->errest[eps->nconv+i] < eps->tol){
216
        iwork[j++]=i;
217
      }else iwork[conv+k++]=i;
2459 carcamgo 218
    }
2596 carcamgo 219
    for(i=0;i<nv;i++){
2599 carcamgo 220
      a[i]=PetscRealPart(eps->eigr[eps->nconv+i]);
221
      b[i]=eps->errest[eps->nconv+i];
222
    }
223
    for(i=0;i<nv;i++){
2596 carcamgo 224
      eps->eigr[eps->nconv+i] = a[iwork[i]];
2599 carcamgo 225
      eps->errest[eps->nconv+i] = b[iwork[i]];
2459 carcamgo 226
    }
2596 carcamgo 227
    for( i=0;i<nv;i++){
228
      p=iwork[i];
229
      if(p!=i){
230
        j=i+1;
231
        while(iwork[j]!=i)j++;
232
        iwork[j]=p;iwork[i]=i;
233
        for(k=0;k<nv;k++){
234
          rtmp=Q[k+p*nv];Q[k+p*nv]=Q[k+i*nv];Q[k+i*nv]=rtmp;
235
        }
236
      }
237
    }
238
    k=eps->nconv+conv;
2459 carcamgo 239
    /* Checking values obtained for completing */
240
    count0=count1=0;
241
    for(i=0;i<k;i++){      
242
      theta = PetscRealPart(eps->eigr[i]);
243
      lambda = sPres->value + 1/theta;
244
      if( ((sr->dir)*theta < 0) && ((sr->dir)*(lambda - sPres->ext[0]) > 0))count0++;
245
      if( ((sr->dir)*theta > 0) && ((sr->dir)*(sPres->ext[1] - lambda) > 0))count1++;
246
    }
2404 jroman 247
 
2596 carcamgo 248
    /* Checks completion */
2459 carcamgo 249
    if( (!sch0||count0 >= sPres->nsch[0]) && (!sch1 ||count1 >= sPres->nsch[1]) ) {
250
      eps->reason = EPS_CONVERGED_TOL;
251
    }else {
252
      if(!complIterating && eps->its >= eps->max_it) eps->reason = EPS_DIVERGED_ITS;
253
      if(complIterating){
254
        if(--iterCompl <= 0) eps->reason = EPS_DIVERGED_ITS;
2596 carcamgo 255
      }else if (k >= eps->nev) {
2459 carcamgo 256
        n0 = sPres->nsch[0]-count0;
257
        n1 = sPres->nsch[1]-count1;
258
        if( sr->iterCompl>0 && ( (n0>0&& n0<= sr->nMAXCompl)||(n1>0&&n1<=sr->nMAXCompl) )){
2596 carcamgo 259
          /* Iterating for completion*/
2459 carcamgo 260
          complIterating = PETSC_TRUE;
261
          if(n0 >sr->nMAXCompl)sch0 = PETSC_FALSE;
262
          if(n1 >sr->nMAXCompl)sch1 = PETSC_FALSE;
263
          iterCompl = sr->iterCompl;
264
        }else eps->reason = EPS_CONVERGED_TOL;
265
      }      
266
    }
267
 
2404 jroman 268
    /* Update l */
269
    if (eps->reason != EPS_CONVERGED_ITERATING || breakdown) l = 0;
270
    else l = (eps->nconv+nv-k)/2;
271
 
272
    if (eps->reason == EPS_CONVERGED_ITERATING) {
273
      if (breakdown) {
274
        /* Start a new Lanczos factorization */
2499 jroman 275
        ierr = PetscInfo2(eps,"Breakdown in Krylov-Schur method (it=%D norm=%G)\n",eps->its,beta);CHKERRQ(ierr);
2404 jroman 276
        ierr = EPSGetStartVector(eps,k,eps->V[k],&breakdown);CHKERRQ(ierr);
277
        if (breakdown) {
278
          eps->reason = EPS_DIVERGED_BREAKDOWN;
2499 jroman 279
          ierr = PetscInfo(eps,"Unable to generate more start vectors\n");CHKERRQ(ierr);
2404 jroman 280
        }
281
      } else {
282
        /* Prepare the Rayleigh quotient for restart */
283
        for (i=0;i<l;i++) {
284
          a[i] = PetscRealPart(eps->eigr[i+k]);
285
          b[i] = PetscRealPart(Q[nv-1+(i+k-eps->nconv)*nv]*beta);
286
        }
287
      }
288
    }
289
    /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
290
    ierr = SlepcUpdateVectors(nv,eps->V+eps->nconv,0,k+l-eps->nconv,Q,nv,PETSC_FALSE);CHKERRQ(ierr);
291
    /* Normalize u and append it to V */
292
    if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
293
      ierr = VecAXPBY(eps->V[k+l],1.0/beta,0.0,u);CHKERRQ(ierr);
294
    }
2599 carcamgo 295
    aux = auxc = 0;
296
    for(i=0;i<nv+eps->nconv;i++){
297
      theta = PetscRealPart(eps->eigr[i]);
298
      lambda = sPres->value + 1/theta;
299
      if( ((sr->dir)*(lambda - sPres->ext[0]) > 0)&& ((sr->dir)*(sPres->ext[1] - lambda) > 0)){
300
        sr->monit[sr->indexEig+aux]=eps->eigr[i];
301
        sr->errest[sr->indexEig+aux]=eps->errest[i];
302
        aux++;
303
        if(eps->errest[i] < eps->tol)auxc++;
304
      }
305
    }
306
    ierr = EPSMonitor(eps,eps->its,auxc+sr->indexEig,sr->monit,sr->eigi,sr->errest,sr->indexEig+aux);CHKERRQ(ierr);
2404 jroman 307
    eps->nconv = k;
2459 carcamgo 308
  }
2596 carcamgo 309
  /* Check for completion */
310
  for(i=0;i< eps->nconv; i++){
311
    if( (sr->dir)*PetscRealPart(eps->eigr[i])>0 )sPres->nconv[1]++;
312
    else sPres->nconv[0]++;
313
  }
2468 eromero 314
  sPres->comp[0] = (count0 >= sPres->nsch[0])?PETSC_TRUE:PETSC_FALSE;
315
  sPres->comp[1] = (count1 >= sPres->nsch[1])?PETSC_TRUE:PETSC_FALSE;
2404 jroman 316
  ierr = PetscFree(Q);CHKERRQ(ierr);
317
  ierr = PetscFree(a);CHKERRQ(ierr);
318
  ierr = PetscFree(b);CHKERRQ(ierr);
319
  ierr = PetscFree(work);CHKERRQ(ierr);
320
  ierr = PetscFree(iwork);CHKERRQ(ierr);
321
  PetscFunctionReturn(0);
322
}
323
 
2459 carcamgo 324
/*
2596 carcamgo 325
  Obtains value of subsequent shift
2459 carcamgo 326
*/
327
#undef __FUNCT__
328
#define __FUNCT__ "EPSGetNewShiftValue"
329
static PetscErrorCode EPSGetNewShiftValue(EPS eps,PetscInt side,PetscReal *newS){
2596 carcamgo 330
  PetscReal   lambda,d_prev;
2459 carcamgo 331
  PetscInt    i,idxP;
332
  SR          sr;
333
  shift       sPres;
334
 
335
  PetscFunctionBegin;  
336
  sr = (SR)eps->data;
337
  sPres = sr->sPres;
2464 carcamgo 338
  if( sPres->neighb[side]){
2596 carcamgo 339
  /* Completing a previous interval */
340
    if(!sPres->neighb[side]->neighb[side] && sPres->neighb[side]->nconv[side]==0){ /* One of the ends might be too far from eigenvalues */
341
      if(side) *newS = (sPres->value + PetscRealPart(sr->eig[sr->perm[sr->indexEig-1]]))/2;
342
      else *newS = (sPres->value + PetscRealPart(sr->eig[sr->perm[0]]))/2;
343
    }else *newS=(sPres->value + sPres->neighb[side]->value)/2;
344
  }else{ /* (Only for side=1). Creating a new interval. */
345
    if(sPres->neigs==0){/* No value has been accepted*/
2464 carcamgo 346
      if(sPres->neighb[0]){
2596 carcamgo 347
        /* Multiplying by 10 the previous distance */
2465 jroman 348
        *newS = sPres->value + 10*(sr->dir)*PetscAbsReal(sPres->value - sPres->neighb[0]->value);
2596 carcamgo 349
        sr->nleap++;
350
        /* Stops when the interval is open and no values are found in the last 5 shifts (there might be infinite eigenvalues) */
351
        if( !sr->hasEnd && sr->nleap > 5)SETERRQ(((PetscObject)eps)->comm,1,"Unable to compute the wanted eigenvalues with open interval");          
352
      }else {/* First shift */
2459 carcamgo 353
        if(eps->nconv != 0){
2596 carcamgo 354
           /* Unaccepted values give information for next shift */
355
           idxP=0;/* Number of values left from shift */
2459 carcamgo 356
           for(i=0;i<eps->nconv;i++){
357
             lambda = PetscRealPart(eps->eigr[i]);
358
             if( (sr->dir)*(lambda - sPres->value) <0)idxP++;
359
             else break;
360
           }
2596 carcamgo 361
           /* Avoiding subtraction of eigenvalues (might be the same).*/
2459 carcamgo 362
           if(idxP>0){
2465 jroman 363
             d_prev = PetscAbsReal(sPres->value - PetscRealPart(eps->eigr[0]))/(idxP+0.3);
2459 carcamgo 364
           }else {
2465 jroman 365
             d_prev = PetscAbsReal(sPres->value - PetscRealPart(eps->eigr[eps->nconv-1]))/(eps->nconv+0.3);
2459 carcamgo 366
           }
367
           *newS = sPres->value + ((sr->dir)*d_prev*eps->nev)/2;
2596 carcamgo 368
        }else{/* No values found, no information for next shift */
369
          SETERRQ(((PetscObject)eps)->comm,1,"First shift renders no information");
2459 carcamgo 370
        }
371
      }
2596 carcamgo 372
    }else{/* Accepted values found */
373
      sr->nleap = 0;
374
      /* Average distance of values in previous subinterval */
2459 carcamgo 375
      shift s = sPres->neighb[0];
2464 carcamgo 376
      while(s && PetscAbs(s->inertia - sPres->inertia)==0){
2596 carcamgo 377
        s = s->neighb[0];/* Looking for previous shifts with eigenvalues within */
2459 carcamgo 378
      }
2464 carcamgo 379
      if(s){
2465 jroman 380
        d_prev = PetscAbsReal( (sPres->value - s->value)/(sPres->inertia - s->inertia));
2596 carcamgo 381
      }else{/* First shift. Average distance obtained with values in this shift */
382
        /* first shift might be too far from first wanted eigenvalue (no values found outside the interval)*/
2609 carcamgo 383
        if( (sr->dir)*(PetscRealPart(sr->eig[0])-sPres->value)>0 && PetscAbsReal( (PetscRealPart(sr->eig[sr->indexEig-1]) - PetscRealPart(sr->eig[0]))/PetscRealPart(sr->eig[0])) > PetscSqrtReal(eps->tol) ){
2596 carcamgo 384
          d_prev =  PetscAbsReal( (PetscRealPart(sr->eig[sr->indexEig-1]) - PetscRealPart(sr->eig[0])))/(sPres->neigs+0.3);
385
        }else{
386
          d_prev = PetscAbsReal( PetscRealPart(sr->eig[sr->indexEig-1]) - sPres->value)/(sPres->neigs+0.3);          
387
        }
2459 carcamgo 388
      }
2596 carcamgo 389
      /* Average distance is used for next shift by adding it to value on the right or to shift */
2465 jroman 390
      if( (sr->dir)*(PetscRealPart(sr->eig[sPres->index + sPres->neigs -1]) - sPres->value) >0){
391
        *newS = PetscRealPart(sr->eig[sPres->index + sPres->neigs -1])+ ((sr->dir)*d_prev*(eps->nev))/2;  
2596 carcamgo 392
      }else{/* Last accepted value is on the left of shift. Adding to shift */
2459 carcamgo 393
        *newS = sPres->value + ((sr->dir)*d_prev*(eps->nev))/2;
394
      }
395
    }
2596 carcamgo 396
    /* End of interval can not be surpassed */
397
    if((sr->dir)*( sr->int1 - *newS) < 0) *newS = sr->int1;
2609 carcamgo 398
  }/* of neighb[side]==null */
2459 carcamgo 399
  PetscFunctionReturn(0);
400
}
401
 
402
/*
2596 carcamgo 403
  Function for sorting an array of real values
2459 carcamgo 404
*/
405
#undef __FUNCT__
406
#define __FUNCT__ "sortRealEigenvalues"
407
static PetscErrorCode sortRealEigenvalues(PetscScalar *r,PetscInt *perm,PetscInt nr,PetscBool prev,PetscInt dir)
408
{
409
  PetscReal      re;
410
  PetscInt       i,j,tmp;
411
 
412
  PetscFunctionBegin;
2464 carcamgo 413
  if(!prev) for (i=0; i < nr; i++) { perm[i] = i; }
2596 carcamgo 414
  /* Insertion sort */
2459 carcamgo 415
  for (i=1; i < nr; i++) {
416
    re = PetscRealPart(r[perm[i]]);
417
    j = i-1;
418
    while ( j>=0 && dir*(re - PetscRealPart(r[perm[j]])) <= 0 ) {
419
      tmp = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp; j--;
420
    }
421
  }
422
  PetscFunctionReturn(0);
423
}
424
 
425
/* Stores the pairs obtained since the last shift in the global arrays */
426
#undef __FUNCT__
427
#define __FUNCT__ "EPSStoreEigenpairs"
428
PetscErrorCode EPSStoreEigenpairs(EPS eps)
429
{
430
  PetscErrorCode ierr;
2596 carcamgo 431
  PetscReal      lambda,err,norm;
2459 carcamgo 432
  PetscInt       i,count;
433
  PetscBool      cond;
434
  SR             sr;
435
  shift          sPres;
436
 
437
  PetscFunctionBegin;
438
  sr = (SR)(eps->data);
439
  sPres = sr->sPres;
440
  sPres->index = sr->indexEig;
441
  count = sr->indexEig;
2596 carcamgo 442
  /* Backtransform */
2459 carcamgo 443
  for(i=0;i < eps->nconv; i++) eps->eigr[i] =  sPres->value + 1.0/(eps->eigr[i]);
2596 carcamgo 444
  /* Sort eigenvalues */
2459 carcamgo 445
  ierr = sortRealEigenvalues(eps->eigr,eps->perm,eps->nconv,PETSC_FALSE,sr->dir);
2596 carcamgo 446
  /* Values stored in global array */
447
  /* Condition for avoiding comparing with a non-existing end */
2468 eromero 448
  cond = (!sPres->neighb[1] && !sr->hasEnd)?PETSC_TRUE:PETSC_FALSE;
2459 carcamgo 449
  for( i=0; i < eps->nconv ;i++ ){
450
    lambda = PetscRealPart(eps->eigr[eps->perm[i]]);
2596 carcamgo 451
    err = eps->errest[eps->perm[i]];
452
    if(  (sr->dir)*(lambda - sPres->ext[0]) > 0 && (sr->dir)*(sPres->ext[1] - lambda) > 0  ){/* Valid value */
453
      if(count>=sr->numEigs){/* Error found */
2609 carcamgo 454
         SETERRQ(((PetscObject)eps)->comm,1,"Unexpected error in Spectrum Slicing");
2464 carcamgo 455
      }  
2459 carcamgo 456
      sr->eig[count] = lambda;
2596 carcamgo 457
      sr->errest[count] = err;
458
      /* Purification */
2609 carcamgo 459
      if (eps->isgeneralized){
460
        ierr = STApply(eps->OP,eps->V[eps->perm[i]],sr->V[count]);CHKERRQ(ierr);
461
        ierr = IPNorm(eps->ip,sr->V[count],&norm);CHKERRQ(ierr);
462
        ierr = VecScale(sr->V[count],1.0/norm);CHKERRQ(ierr);
463
      }else{
464
        ierr = VecCopy(eps->V[eps->perm[i]], sr->V[count]);CHKERRQ(ierr);
465
      }
2459 carcamgo 466
      count++;
2596 carcamgo 467
    }
2459 carcamgo 468
  }
469
  sPres->neigs = count - sr->indexEig;
470
  sr->indexEig = count;
2596 carcamgo 471
  /* Global ordering array updating */
2459 carcamgo 472
  ierr = sortRealEigenvalues(sr->eig,sr->perm,count,PETSC_TRUE,sr->dir);CHKERRQ(ierr);
473
  PetscFunctionReturn(0);
474
}
475
 
476
#undef __FUNCT__
477
#define __FUNCT__ "EPSLookForDeflation"
478
PetscErrorCode EPSLookForDeflation(EPS eps)
479
{
2596 carcamgo 480
  PetscReal       val;
2459 carcamgo 481
  PetscInt        i,count0=0,count1=0;
482
  shift           sPres;
2596 carcamgo 483
  PetscInt        ini,fin,k,idx0,idx1;
2459 carcamgo 484
  SR              sr;
485
 
486
  PetscFunctionBegin;
487
  sr = (SR)(eps->data);
488
  sPres = sr->sPres;
489
 
2464 carcamgo 490
  if(sPres->neighb[0]) ini = (sr->dir)*(sPres->neighb[0]->inertia - sr->inertia0);
2459 carcamgo 491
  else ini = 0;
492
  fin = sr->indexEig;
2596 carcamgo 493
  /* Selection of ends for searching new values */
494
  if(!sPres->neighb[0]) sPres->ext[0] = sr->int0;/* First shift */
2459 carcamgo 495
  else sPres->ext[0] = sPres->neighb[0]->value;
2464 carcamgo 496
  if(!sPres->neighb[1]) {
2459 carcamgo 497
    if(sr->hasEnd) sPres->ext[1] = sr->int1;
498
    else sPres->ext[1] = (sr->dir > 0)?PETSC_MAX_REAL:PETSC_MIN_REAL;
499
  }else sPres->ext[1] = sPres->neighb[1]->value;
2596 carcamgo 500
  /* Selection of values between right and left ends */
2459 carcamgo 501
  for(i=ini;i<fin;i++){
502
    val=PetscRealPart(sr->eig[sr->perm[i]]);
2596 carcamgo 503
    /* Values to the right of left shift */
2459 carcamgo 504
    if( (sr->dir)*(val - sPres->ext[1]) < 0 ){
505
      if((sr->dir)*(val - sPres->value) < 0)count0++;
506
      else count1++;
507
    }else break;
508
  }
2596 carcamgo 509
  /* The number of values on each side are found */
2464 carcamgo 510
  if(sPres->neighb[0])
2459 carcamgo 511
     sPres->nsch[0] = (sr->dir)*(sPres->inertia - sPres->neighb[0]->inertia)-count0;
512
  else sPres->nsch[0] = 0;
513
 
2464 carcamgo 514
  if(sPres->neighb[1])
2459 carcamgo 515
    sPres->nsch[1] = (sr->dir)*(sPres->neighb[1]->inertia - sPres->inertia) - count1;
516
  else sPres->nsch[1] = (sr->dir)*(sr->inertia1 - sPres->inertia);
517
 
2596 carcamgo 518
  /* Completing vector of indexes for deflation */
519
  idx0 = ini;
520
  idx1 = ini+count0+count1;
2459 carcamgo 521
  k=0;
522
  for(i=idx0;i<idx1;i++)sr->idxDef[k++]=sr->perm[i];
523
  for(i=0;i<k;i++)sr->VDef[i]=sr->V[sr->idxDef[i]];
524
  eps->DS = sr->VDef;
525
  eps->nds = k;
526
  PetscFunctionReturn(0);
527
}
528
 
529
#undef __FUNCT__
530
#define __FUNCT__ "EPSSolve_KrylovSchur_Slice"
531
PetscErrorCode EPSSolve_KrylovSchur_Slice(EPS eps)
532
{
533
  PetscErrorCode ierr;
2596 carcamgo 534
  PetscInt       i;
2459 carcamgo 535
  PetscReal      newS;
536
  KSP            ksp;
537
  PC             pc;
2596 carcamgo 538
  Mat            F;  
539
  PetscReal      *errest_left;
540
  Vec            t;
2459 carcamgo 541
  SR             sr;
542
 
543
  PetscFunctionBegin;
2464 carcamgo 544
  ierr = PetscMalloc(sizeof(struct _n_SR),&sr);CHKERRQ(ierr);
2459 carcamgo 545
  eps->data = sr;
2596 carcamgo 546
  sr->itsKs = 0;
547
  sr->nleap = 0;
548
  sr->nMAXCompl = eps->nev/4;
549
  sr->iterCompl = eps->max_it/4;
550
  /* Checking presence of ends and finding direction */
2459 carcamgo 551
  if( eps->inta > PETSC_MIN_REAL){
552
    sr->int0 = eps->inta;
553
    sr->int1 = eps->intb;
554
    sr->dir = 1;
2596 carcamgo 555
    if(eps->intb >= PETSC_MAX_REAL){ /* Right-open interval */
2459 carcamgo 556
      sr->hasEnd = PETSC_FALSE;
557
      sr->inertia1 = eps->n;
558
    }else sr->hasEnd = PETSC_TRUE;
2596 carcamgo 559
  }else{ /* Left-open interval */
2459 carcamgo 560
    sr->int0 = eps->intb;
561
    sr->int1 = eps->inta;
562
    sr->dir = -1;
563
    sr->hasEnd = PETSC_FALSE;
564
    sr->inertia1 = 0;
565
  }
2596 carcamgo 566
  /* Array of pending shifts */
567
  sr->maxPend = 100;/* Initial size */
2459 carcamgo 568
  ierr = PetscMalloc((sr->maxPend)*sizeof(shift),&sr->pending);CHKERRQ(ierr);
569
  if(sr->hasEnd){
570
    ierr = STGetKSP(eps->OP, &ksp);CHKERRQ(ierr);
571
    ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
572
    ierr = PCFactorGetMatrix(pc,&F);CHKERRQ(ierr);
2596 carcamgo 573
    /* Not looking for values in b (just inertia).*/
2459 carcamgo 574
    ierr = MatGetInertia(F,&sr->inertia1,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
575
  }
576
  sr->nPend = 0;
577
  ierr = EPSCreateShift(eps,sr->int0,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
578
  ierr = EPSExtractShift(eps);
579
  sr->s0 = sr->sPres;
580
  sr->inertia0 = sr->s0->inertia;
581
  sr->numEigs = (sr->dir)*(sr->inertia1 - sr->inertia0);
582
  sr->indexEig = 0;
2596 carcamgo 583
  /* Only with eigenvalues present in the interval ...*/
2464 carcamgo 584
  if(sr->numEigs==0){
585
    eps->reason = EPS_CONVERGED_TOL;
2596 carcamgo 586
    ierr = PetscFree(sr->s0);CHKERRQ(ierr);
587
    ierr = PetscFree(sr->pending);CHKERRQ(ierr);
588
    ierr = PetscFree(sr);CHKERRQ(ierr);
2464 carcamgo 589
    PetscFunctionReturn(0);
590
  }
2459 carcamgo 591
 
2596 carcamgo 592
  /* Memory reservation for eig, V and perm */
2464 carcamgo 593
  ierr = PetscMalloc((sr->numEigs)*sizeof(PetscScalar),&sr->eig);CHKERRQ(ierr);
2596 carcamgo 594
  ierr = PetscMalloc((sr->numEigs)*sizeof(PetscScalar),&sr->eigi);CHKERRQ(ierr);
2599 carcamgo 595
  ierr = PetscMalloc((sr->numEigs+eps->ncv) *sizeof(PetscReal),&sr->errest);CHKERRQ(ierr);
596
  ierr = PetscMalloc((sr->numEigs+eps->ncv)*sizeof(PetscReal),&errest_left);CHKERRQ(ierr);
2609 carcamgo 597
  ierr = PetscMalloc((sr->numEigs+eps->ncv)*sizeof(PetscScalar),&sr->monit);CHKERRQ(ierr);
2599 carcamgo 598
  for(i=0;i<sr->numEigs;i++){sr->eigi[i]=0;sr->eig[i] = 0;}
599
  for(i=0;i<sr->numEigs+eps->ncv;i++){errest_left[i]=0;sr->errest[i]=0;sr->monit[i]=0;}
2464 carcamgo 600
  ierr = VecCreateMPI(((PetscObject)eps)->comm,eps->nloc,PETSC_DECIDE,&t);CHKERRQ(ierr);
601
  ierr = VecDuplicateVecs(t,sr->numEigs,&sr->V);CHKERRQ(ierr);
602
  ierr = VecDestroy(&t);CHKERRQ(ierr);
2596 carcamgo 603
  /* Vector for maintaining order of eigenvalues */
2464 carcamgo 604
  ierr = PetscMalloc((sr->numEigs)*sizeof(PetscInt),&sr->perm);CHKERRQ(ierr);
605
  for(i=0;i< sr->numEigs;i++)sr->perm[i]=i;
2596 carcamgo 606
  /* Vectors for deflation */
607
  ierr = PetscMalloc((sr->numEigs)*sizeof(PetscInt),&sr->idxDef);CHKERRQ(ierr);
2464 carcamgo 608
  ierr = PetscMalloc((sr->numEigs)*sizeof(Vec),&sr->VDef);CHKERRQ(ierr);
609
  sr->indexEig = 0;
2459 carcamgo 610
 
2464 carcamgo 611
  while(sr->sPres){
2596 carcamgo 612
    /* Search for deflation */
2464 carcamgo 613
    ierr = EPSLookForDeflation(eps);CHKERRQ(ierr);
2596 carcamgo 614
    /* KrylovSchur */
2464 carcamgo 615
    ierr = EPSKrylovSchur_Slice(eps);CHKERRQ(ierr);
2596 carcamgo 616
 
2464 carcamgo 617
    ierr = EPSStoreEigenpairs(eps);CHKERRQ(ierr);
2596 carcamgo 618
    /* Select new shift */
2468 eromero 619
    if(!sr->sPres->comp[1]){
2464 carcamgo 620
      ierr = EPSGetNewShiftValue(eps,1,&newS);CHKERRQ(ierr);
621
      ierr = EPSCreateShift(eps,newS,sr->sPres,sr->sPres->neighb[1]);
622
    }
2468 eromero 623
    if(!sr->sPres->comp[0]){
2596 carcamgo 624
      /* Completing earlier interval */
2464 carcamgo 625
      ierr = EPSGetNewShiftValue(eps,0,&newS);CHKERRQ(ierr);
626
      ierr = EPSCreateShift(eps,newS,sr->sPres->neighb[0],sr->sPres);
627
    }
2596 carcamgo 628
    /* Preparing for a new search of values */
2464 carcamgo 629
    ierr = EPSExtractShift(eps);CHKERRQ(ierr);
630
  }
2596 carcamgo 631
 
632
  /* Updating eps values prior to exit */
2464 carcamgo 633
  ierr = VecDestroyVecs(eps->allocated_ncv,&eps->V);CHKERRQ(ierr);
634
  eps->V = sr->V;
635
  ierr = PetscFree(eps->eigr);CHKERRQ(ierr);
636
  ierr = PetscFree(eps->eigi);CHKERRQ(ierr);
637
  ierr = PetscFree(eps->errest);CHKERRQ(ierr);
638
  ierr = PetscFree(eps->errest_left);CHKERRQ(ierr);
639
  ierr = PetscFree(eps->perm);CHKERRQ(ierr);
2596 carcamgo 640
  eps->eigr = sr->eig;
641
  eps->eigi = sr->eigi;
642
  eps->errest = sr->errest;
643
  eps->errest_left = errest_left;
2464 carcamgo 644
  eps->perm = sr->perm;
2596 carcamgo 645
  eps->ncv = eps->allocated_ncv = sr->numEigs;
2464 carcamgo 646
  eps->nconv = sr->indexEig;
647
  eps->reason = EPS_CONVERGED_TOL;
2596 carcamgo 648
  eps->its = sr->itsKs;
2464 carcamgo 649
  eps->nds = 0;
650
  eps->DS = PETSC_NULL;
2596 carcamgo 651
  eps->evecsavailable = PETSC_TRUE;
2464 carcamgo 652
  ierr = PetscFree(sr->VDef);CHKERRQ(ierr);
653
  ierr = PetscFree(sr->idxDef);CHKERRQ(ierr);
654
  ierr = PetscFree(sr->pending);CHKERRQ(ierr);
2599 carcamgo 655
  ierr = PetscFree(sr->monit);CHKERRQ(ierr);
2596 carcamgo 656
  /* Reviewing list of shifts to free memory */
2464 carcamgo 657
  shift s = sr->s0;
658
  if(s){
659
    while(s->neighb[1]){
660
      s = s->neighb[1];
661
      ierr = PetscFree(s->neighb[0]);CHKERRQ(ierr);
2459 carcamgo 662
    }
2464 carcamgo 663
    ierr = PetscFree(s);CHKERRQ(ierr);
2459 carcamgo 664
  }
2464 carcamgo 665
  ierr = PetscFree(sr);CHKERRQ(ierr);
2459 carcamgo 666
  PetscFunctionReturn(0);
2599 carcamgo 667
}