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
2044 antodo 1
/*                      
2
 
3
   Q-Arnoldi method for quadratic eigenproblems.
4
 
5
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6
   SLEPc - Scalable Library for Eigenvalue Problem Computations
2116 eromero 7
   Copyright (c) 2002-2010, Universidad Politecnica de Valencia, Spain
2044 antodo 8
 
9
   This file is part of SLEPc.
10
 
11
   SLEPc is free software: you can redistribute it and/or modify it under  the
12
   terms of version 3 of the GNU Lesser General Public License as published by
13
   the Free Software Foundation.
14
 
15
   SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
16
   WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
17
   FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
18
   more details.
19
 
20
   You  should have received a copy of the GNU Lesser General  Public  License
21
   along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
22
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23
*/
24
 
25
#include "private/qepimpl.h"         /*I "slepcqep.h" I*/
26
#include "private/epsimpl.h"
27
#include "petscblaslapack.h"
28
 
29
typedef struct {
30
  KSP ksp;
31
} QEP_QARNOLDI;
32
 
33
#undef __FUNCT__  
34
#define __FUNCT__ "QEPSetUp_QARNOLDI"
35
PetscErrorCode QEPSetUp_QARNOLDI(QEP qep)
36
{
37
  PetscErrorCode ierr;
38
  QEP_QARNOLDI   *ctx = (QEP_QARNOLDI *)qep->data;
39
 
40
  PetscFunctionBegin;
41
 
42
  if (qep->ncv) { /* ncv set */
2214 jroman 43
    if (qep->ncv<qep->nev) SETERRQ(((PetscObject)qep)->comm,1,"The value of ncv must be at least nev");
2044 antodo 44
  }
45
  else if (qep->mpd) { /* mpd set */
46
    qep->ncv = PetscMin(qep->n,qep->nev+qep->mpd);
47
  }
48
  else { /* neither set: defaults depend on nev being small or large */
49
    if (qep->nev<500) qep->ncv = PetscMin(qep->n,PetscMax(2*qep->nev,qep->nev+15));
50
    else { qep->mpd = 500; qep->ncv = PetscMin(qep->n,qep->nev+qep->mpd); }
51
  }
52
  if (!qep->mpd) qep->mpd = qep->ncv;
2214 jroman 53
  if (qep->ncv>qep->nev+qep->mpd) SETERRQ(((PetscObject)qep)->comm,1,"The value of ncv must not be larger than nev+mpd");
2044 antodo 54
  if (!qep->max_it) qep->max_it = PetscMax(100,2*qep->n/qep->ncv);
55
  if (!qep->which) qep->which = QEP_LARGEST_MAGNITUDE;
56
  if (qep->problem_type != QEP_GENERAL)
2214 jroman 57
    SETERRQ(((PetscObject)qep)->comm,1,"Wrong value of qep->problem_type");
2044 antodo 58
 
59
  ierr = PetscFree(qep->T);CHKERRQ(ierr);
60
  ierr = PetscMalloc(qep->ncv*qep->ncv*sizeof(PetscScalar),&qep->T);CHKERRQ(ierr);
61
  ierr = QEPDefaultGetWork(qep,4);CHKERRQ(ierr);
62
 
2051 jroman 63
  ierr = KSPSetOperators(ctx->ksp,qep->M,qep->M,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
2044 antodo 64
  ierr = KSPSetUp(ctx->ksp);CHKERRQ(ierr);
65
 
66
  PetscFunctionReturn(0);
67
}
68
 
69
#undef __FUNCT__  
70
#define __FUNCT__ "QEPQArnoldiCGS"
71
/*
2066 jroman 72
  Compute a step of Classical Gram-Schmidt orthogonalization
2044 antodo 73
*/
74
PetscErrorCode QEPQArnoldiCGS(QEP qep,PetscScalar *H,PetscBLASInt ldh,PetscScalar *h,PetscBLASInt j,Vec *V,Vec t,Vec v,Vec w,PetscReal *onorm,PetscReal *norm,PetscScalar *work)
75
{
76
  PetscErrorCode ierr;
77
  PetscBLASInt   ione = 1, j_1 = j+1;
2060 jroman 78
  PetscReal      x, y;
79
  PetscScalar    dot, one = 1.0, zero = 0.0;
2044 antodo 80
 
81
  PetscFunctionBegin;
82
  /* compute norm of v and w */
83
  if (onorm) {
84
    ierr = VecNorm(v,NORM_2,&x);CHKERRQ(ierr);
85
    ierr = VecNorm(w,NORM_2,&y);CHKERRQ(ierr);
2060 jroman 86
    *onorm = sqrt(x*x+y*y);
2044 antodo 87
  }
88
 
89
  /* orthogonalize: compute h */
90
  ierr = VecMDot(v,j_1,V,h);CHKERRQ(ierr);
91
  ierr = VecMDot(w,j_1,V,work);CHKERRQ(ierr);
92
  if (j>0)
2067 jroman 93
    BLASgemv_("C",&j_1,&j,&one,H,&ldh,work,&ione,&one,h,&ione);
2060 jroman 94
  ierr = VecDot(t,w,&dot);CHKERRQ(ierr);
95
  h[j] += dot;
2044 antodo 96
 
97
  /* orthogonalize: update v and w */
98
  ierr = SlepcVecMAXPBY(v,1.0,-1.0,j_1,h,V);CHKERRQ(ierr);
99
  if (j>0) {
100
    BLASgemv_("N",&j_1,&j,&one,H,&ldh,h,&ione,&zero,work,&ione);
101
    ierr = SlepcVecMAXPBY(w,1.0,-1.0,j_1,work,V);CHKERRQ(ierr);
102
  }
103
  ierr = VecAXPY(w,-h[j],t);CHKERRQ(ierr);
104
 
105
  /* compute norm of v and w */
106
  if (norm) {
107
    ierr = VecNorm(v,NORM_2,&x);CHKERRQ(ierr);
108
    ierr = VecNorm(w,NORM_2,&y);CHKERRQ(ierr);
2060 jroman 109
    *norm = sqrt(x*x+y*y);CHKERRQ(ierr);
2044 antodo 110
  }
111
  PetscFunctionReturn(0);
112
}
113
 
114
#undef __FUNCT__  
115
#define __FUNCT__ "QEPQArnoldi"
116
/*
2066 jroman 117
  Compute a run of Q-Arnoldi iterations
2044 antodo 118
*/
119
PetscErrorCode QEPQArnoldi(QEP qep,PetscScalar *H,PetscInt ldh,Vec *V,PetscInt k,PetscInt *M,Vec v,Vec w,PetscReal *beta,PetscTruth *breakdown,PetscScalar *work)
120
{
121
  PetscErrorCode ierr;
122
  PetscInt       i,j,l,m = *M;
123
  QEP_QARNOLDI   *ctx = (QEP_QARNOLDI *)qep->data;
124
  Vec            t = qep->work[2], u = qep->work[3];
125
  IPOrthogonalizationRefinementType refinement;
126
  PetscReal      norm,onorm,eta;
127
  PetscScalar    *c = work + m;
128
 
129
  PetscFunctionBegin;
130
  ierr = IPGetOrthogonalization(qep->ip,PETSC_NULL,&refinement,&eta);CHKERRQ(ierr);
131
  ierr = VecCopy(v,qep->V[k]);CHKERRQ(ierr);
132
 
133
  for (j=k;j<m;j++) {
134
    /* apply operator */
135
    ierr = VecCopy(w,t);CHKERRQ(ierr);
2051 jroman 136
    ierr = MatMult(qep->K,v,u);CHKERRQ(ierr);
2050 antodo 137
    ierr = MatMult(qep->C,t,w);CHKERRQ(ierr);
138
    ierr = VecAXPY(u,qep->sfactor,w);CHKERRQ(ierr);
2044 antodo 139
    ierr = KSPSolve(ctx->ksp,u,w);CHKERRQ(ierr);
2051 jroman 140
    ierr = VecScale(w,-1.0/(qep->sfactor*qep->sfactor));CHKERRQ(ierr);
2044 antodo 141
    ierr = VecCopy(t,v);CHKERRQ(ierr);
142
 
143
    /* orthogonalize */
144
    switch (refinement) {
145
      case IP_ORTH_REFINE_NEVER:
146
        ierr = QEPQArnoldiCGS(qep,H,ldh,H+ldh*j,j,V,t,v,w,PETSC_NULL,&norm,work);CHKERRQ(ierr);
147
        *breakdown = PETSC_FALSE;
148
        break;
149
      case IP_ORTH_REFINE_ALWAYS:
150
        ierr = QEPQArnoldiCGS(qep,H,ldh,H+ldh*j,j,V,t,v,w,PETSC_NULL,PETSC_NULL,work);CHKERRQ(ierr);
151
        ierr = QEPQArnoldiCGS(qep,H,ldh,c,j,V,t,v,w,&onorm,&norm,work);CHKERRQ(ierr);
152
        for (i=0;i<j;i++) H[ldh*j+i] += c[i];
153
        if (norm < eta * onorm) *breakdown = PETSC_TRUE;
154
        else *breakdown = PETSC_FALSE;
155
        break;
156
      case IP_ORTH_REFINE_IFNEEDED:
157
        ierr = QEPQArnoldiCGS(qep,H,ldh,H+ldh*j,j,V,t,v,w,&onorm,&norm,work);CHKERRQ(ierr);
158
        /* ||q|| < eta ||h|| */
159
        l = 1;
160
        while (l<3 && norm < eta * onorm) {
161
          l++;
162
          onorm = norm;
163
          ierr = QEPQArnoldiCGS(qep,H,ldh,c,j,V,t,v,w,PETSC_NULL,&norm,work);CHKERRQ(ierr);
164
          for (i=0;i<j;i++) H[ldh*j+i] += c[i];
165
        }
166
        if (norm < eta * onorm) *breakdown = PETSC_TRUE;
167
        else *breakdown = PETSC_FALSE;
168
        break;
2214 jroman 169
      default: SETERRQ(((PetscObject)qep)->comm,1,"Wrong value of ip->orth_ref");
2044 antodo 170
    }
171
    ierr = VecScale(v,1.0/norm);CHKERRQ(ierr);
172
    ierr = VecScale(w,1.0/norm);CHKERRQ(ierr);
173
 
174
    if (j<m-1) {
175
      H[j+1+ldh*j] = norm;
176
      ierr = VecCopy(v,V[j+1]);CHKERRQ(ierr);
177
    }
178
  }
179
  *beta = norm;
180
  PetscFunctionReturn(0);
181
}
182
 
183
 
184
#undef __FUNCT__  
185
#define __FUNCT__ "QEPProjectedKSNonsym"
186
/*
187
   QEPProjectedKSNonsym - Solves the projected eigenproblem in the Krylov-Schur
188
   method (non-symmetric case).
189
 
190
   On input:
191
     l is the number of vectors kept in previous restart (0 means first restart)
192
     S is the projected matrix (leading dimension is lds)
193
 
194
   On output:
195
     S has (real) Schur form with diagonal blocks sorted appropriately
196
     Q contains the corresponding Schur vectors (order n, leading dimension n)
197
*/
198
PetscErrorCode QEPProjectedKSNonsym(QEP qep,PetscInt l,PetscScalar *S,PetscInt lds,PetscScalar *Q,PetscInt n)
199
{
200
  PetscErrorCode ierr;
201
  PetscInt       i;
202
 
203
  PetscFunctionBegin;
204
  if (l==0) {
205
    ierr = PetscMemzero(Q,n*n*sizeof(PetscScalar));CHKERRQ(ierr);
206
    for (i=0;i<n;i++)
207
      Q[i*(n+1)] = 1.0;
208
  } else {
209
    /* Reduce S to Hessenberg form, S <- Q S Q' */
210
    ierr = EPSDenseHessenberg(n,qep->nconv,S,lds,Q);CHKERRQ(ierr);
211
  }
212
  /* Reduce S to (quasi-)triangular form, S <- Q S Q' */
213
  ierr = EPSDenseSchur(n,qep->nconv,S,lds,Q,qep->eigr,qep->eigi);CHKERRQ(ierr);
214
  /* Sort the remaining columns of the Schur form */
215
  ierr = QEPSortDenseSchur(qep,n,qep->nconv,S,lds,Q,qep->eigr,qep->eigi);CHKERRQ(ierr);    
216
  PetscFunctionReturn(0);
217
}
218
 
219
#undef __FUNCT__  
220
#define __FUNCT__ "QEPSolve_QARNOLDI"
221
PetscErrorCode QEPSolve_QARNOLDI(QEP qep)
222
{
223
  PetscErrorCode ierr;
224
  PetscInt       i,j,k,l,lwork,nv;
225
  Vec            v=qep->work[0],w=qep->work[1];
2060 jroman 226
  PetscScalar    *S=qep->T,*Q,*work;
227
  PetscReal      beta,norm,x,y;
2066 jroman 228
  PetscTruth     breakdown;
2044 antodo 229
 
230
  PetscFunctionBegin;
231
 
232
  ierr = PetscMemzero(S,qep->ncv*qep->ncv*sizeof(PetscScalar));CHKERRQ(ierr);
233
  ierr = PetscMalloc(qep->ncv*qep->ncv*sizeof(PetscScalar),&Q);CHKERRQ(ierr);
2066 jroman 234
  lwork = 7*qep->ncv;
2044 antodo 235
  ierr = PetscMalloc(lwork*sizeof(PetscScalar),&work);CHKERRQ(ierr);
236
 
237
  /* Get the starting Arnoldi vector */
238
  if (qep->nini>0) {
239
    ierr = VecCopy(qep->V[0],v);CHKERRQ(ierr);
240
  } else {
241
    ierr = SlepcVecSetRandom(v,qep->rand);CHKERRQ(ierr);
242
  }
243
  /* w is always a random vector */
244
  ierr = SlepcVecSetRandom(w,qep->rand);CHKERRQ(ierr);
245
  ierr = VecNorm(v,NORM_2,&x);CHKERRQ(ierr);
246
  ierr = VecNorm(w,NORM_2,&y);CHKERRQ(ierr);
2060 jroman 247
  norm = sqrt(x*x+y*y);CHKERRQ(ierr);
2066 jroman 248
  ierr = VecScale(v,1.0/norm);CHKERRQ(ierr);
249
  ierr = VecScale(w,1.0/norm);CHKERRQ(ierr);
2044 antodo 250
 
251
  /* Restart loop */
252
  l = 0;
2112 eromero 253
  while (qep->reason == QEP_CONVERGED_ITERATING) {
2044 antodo 254
    qep->its++;
255
 
256
    /* Compute an nv-step Arnoldi factorization */
257
    nv = PetscMin(qep->nconv+qep->mpd,qep->ncv);
258
    ierr = QEPQArnoldi(qep,S,qep->ncv,qep->V,qep->nconv+l,&nv,v,w,&beta,&breakdown,work);CHKERRQ(ierr);
259
 
260
    /* Solve projected problem */
261
    ierr = QEPProjectedKSNonsym(qep,l,S,qep->ncv,Q,nv);CHKERRQ(ierr);
262
 
2066 jroman 263
    /* Check convergence */
264
    ierr = QEPKrylovConvergence(qep,qep->nconv,nv-qep->nconv,S,qep->ncv,Q,nv,beta,&k,work);CHKERRQ(ierr);
2112 eromero 265
    if (qep->its >= qep->max_it) qep->reason = QEP_DIVERGED_ITS;
266
    if (k >= qep->nev) qep->reason = QEP_CONVERGED_TOL;
2044 antodo 267
 
268
    /* Update l */
2112 eromero 269
    if (qep->reason != QEP_CONVERGED_ITERATING || breakdown) l = 0;
2044 antodo 270
    else {
271
      l = (nv-k)/2;
272
#if !defined(PETSC_USE_COMPLEX)
273
      if (S[(k+l-1)*(qep->ncv+1)+1] != 0.0) {
274
        if (k+l<nv-1) l = l+1;
275
        else l = l-1;
276
      }
277
#endif
278
    }
279
 
2112 eromero 280
    if (qep->reason == QEP_CONVERGED_ITERATING) {
2044 antodo 281
      if (breakdown) {
282
        /* Stop if breakdown */
283
        PetscInfo2(qep,"Breakdown Quadratic Arnoldi method (it=%i norm=%g)\n",qep->its,beta);
2112 eromero 284
        qep->reason = QEP_DIVERGED_BREAKDOWN;
2044 antodo 285
      } else {
286
        /* Prepare the Rayleigh quotient for restart */
287
        for (i=k;i<k+l;i++) {
288
          S[i*qep->ncv+k+l] = Q[(i+1)*nv-1]*beta;
289
        }
290
      }
291
    }
292
    /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
293
    ierr = SlepcUpdateVectors(nv,qep->V,qep->nconv,k+l,Q,nv,PETSC_FALSE);CHKERRQ(ierr);
294
 
295
    qep->nconv = k;
296
 
2112 eromero 297
    QEPMonitor(qep,qep->its,qep->nconv,qep->eigr,qep->eigi,qep->errest,nv);
2044 antodo 298
 
299
  }
300
 
301
  for (j=0;j<qep->nconv;j++) {
2051 jroman 302
    qep->eigr[j] *= qep->sfactor;
303
    qep->eigi[j] *= qep->sfactor;
2044 antodo 304
  }
305
 
306
  /* Compute eigenvectors */
2049 antodo 307
  if (qep->nconv > 0) {
308
    ierr = QEPComputeVectors_Schur(qep);
309
  }
2044 antodo 310
 
311
  ierr = PetscFree(Q);CHKERRQ(ierr);
312
  ierr = PetscFree(work);CHKERRQ(ierr);
313
  PetscFunctionReturn(0);
314
}
315
 
316
#undef __FUNCT__  
317
#define __FUNCT__ "QEPSetFromOptions_QARNOLDI"
318
PetscErrorCode QEPSetFromOptions_QARNOLDI(QEP qep)
319
{
320
  PetscErrorCode ierr;
321
  QEP_QARNOLDI   *ctx = (QEP_QARNOLDI *)qep->data;
322
 
323
  PetscFunctionBegin;
324
  ierr = KSPSetFromOptions(ctx->ksp);CHKERRQ(ierr);
325
  PetscFunctionReturn(0);
326
}
327
 
328
#undef __FUNCT__  
329
#define __FUNCT__ "QEPView_QARNOLDI"
330
PetscErrorCode QEPView_QARNOLDI(QEP qep,PetscViewer viewer)
331
{
332
  PetscErrorCode ierr;
333
  QEP_QARNOLDI   *ctx = (QEP_QARNOLDI *)qep->data;
334
 
335
  PetscFunctionBegin;
336
  ierr = KSPView(ctx->ksp,viewer);CHKERRQ(ierr);
337
  PetscFunctionReturn(0);
338
}
339
 
340
#undef __FUNCT__  
341
#define __FUNCT__ "QEPDestroy_QARNOLDI"
342
PetscErrorCode QEPDestroy_QARNOLDI(QEP qep)
343
{
344
  PetscErrorCode ierr;
345
  QEP_QARNOLDI   *ctx = (QEP_QARNOLDI *)qep->data;
346
 
347
  PetscFunctionBegin;
348
  ierr = KSPDestroy(ctx->ksp);CHKERRQ(ierr);
349
  ierr = QEPDestroy_Default(qep);CHKERRQ(ierr);
350
  PetscFunctionReturn(0);
351
}
352
 
353
EXTERN_C_BEGIN
354
#undef __FUNCT__  
355
#define __FUNCT__ "QEPCreate_QARNOLDI"
356
PetscErrorCode QEPCreate_QARNOLDI(QEP qep)
357
{
358
  PetscErrorCode ierr;
359
  QEP_QARNOLDI   *ctx;
360
 
361
  PetscFunctionBegin;
362
  ierr = PetscNew(QEP_QARNOLDI,&ctx);CHKERRQ(ierr);
363
  PetscLogObjectMemory(qep,sizeof(QEP_QARNOLDI));
364
  qep->data                      = ctx;
365
  qep->ops->solve                = QEPSolve_QARNOLDI;
366
  qep->ops->setup                = QEPSetUp_QARNOLDI;
367
  qep->ops->setfromoptions       = QEPSetFromOptions_QARNOLDI;
368
  qep->ops->destroy              = QEPDestroy_QARNOLDI;
369
  qep->ops->view                 = QEPView_QARNOLDI;
370
 
371
  ierr = KSPCreate(((PetscObject)qep)->comm,&ctx->ksp);CHKERRQ(ierr);
372
  ierr = KSPSetOptionsPrefix(ctx->ksp,((PetscObject)qep)->prefix);CHKERRQ(ierr);
373
  ierr = KSPAppendOptionsPrefix(ctx->ksp,"qep_");CHKERRQ(ierr);
374
  ierr = PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)qep,1);CHKERRQ(ierr);  
375
  PetscLogObjectParent(qep,ctx->ksp);
376
  PetscFunctionReturn(0);
377
}
378
EXTERN_C_END
379