Actual source code: sinvert.c

  1: /*
  2:       Implements the shift-and-invert technique for eigenvalue problems.
  3: */
 4:  #include src/st/stimpl.h
 5:  #include sinvert.h

  7: typedef struct {
  8:   STSinvertMatMode    shift_matrix;
  9:   MatStructure str;          /* whether matrices have the same pattern or not */
 10:   Mat          mat;
 11:   Vec          w;
 12: } ST_SINV;

 16: static int STApply_Sinvert(ST st,Vec x,Vec y)
 17: {
 18:   int       ierr;
 19:   ST_SINV   *ctx = (ST_SINV *) st->data;

 22:   if (st->B) {
 23:     /* generalized eigenproblem: y = (A - sB)^-1 B x */
 24:     MatMult(st->B,x,ctx->w);
 25:     STAssociatedKSPSolve(st,ctx->w,y);
 26:   }
 27:   else {
 28:     /* standard eigenproblem: y = (A - sI)^-1 x */
 29:     STAssociatedKSPSolve(st,x,y);
 30:   }
 31:   return(0);
 32: }

 36: static int STApplyNoB_Sinvert(ST st,Vec x,Vec y)
 37: {
 38:   int       ierr;

 41:   STAssociatedKSPSolve(st,x,y);
 42:   return(0);
 43: }

 47: int STBackTransform_Sinvert(ST st,PetscScalar *eigr,PetscScalar *eigi)
 48: {
 49:   PetscScalar t;
 51: #ifndef PETSC_USE_COMPLEX
 54:   if (*eigi == 0) *eigr = 1.0 / *eigr + st->sigma;
 55:   else {
 56:     t = *eigr * *eigr + *eigi * *eigi;
 57:     *eigr = *eigr / t + st->sigma;
 58:     *eigi = - *eigi / t;
 59:   }
 60: #else
 62:   *eigr = 1.0 / *eigr + st->sigma;
 63: #endif
 64:   return(0);
 65: }

 69: int STPost_Sinvert(ST st)
 70: {
 71:   ST_SINV      *ctx = (ST_SINV *) st->data;
 72:   PetscScalar  alpha;
 73:   int          ierr;

 76:   if (ctx->shift_matrix == STSINVERT_MATMODE_INPLACE) {
 77:     alpha = st->sigma;
 78:     if( st->B ) { MatAXPY(&alpha,st->B,st->A,ctx->str); }
 79:     else { MatShift( &alpha, st->A );  }
 80:     st->setupcalled = 0;
 81:   }
 82:   return(0);
 83: }

 87: static int STSetUp_Sinvert(ST st)
 88: {
 89:   int          ierr;
 90:   ST_SINV      *ctx = (ST_SINV *) st->data;
 91:   PetscScalar  alpha;


 95:   switch (ctx->shift_matrix) {
 96:   case STSINVERT_MATMODE_INPLACE:
 97:     alpha = -st->sigma;
 98:     if (st->B) { MatAXPY(&alpha,st->B,st->A,ctx->str); }
 99:     else { MatShift(&alpha,st->A); }
100:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
101:      * improve performance when solving a number of related eigenproblems */
102:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
103:     break;
104:   case STSINVERT_MATMODE_SHELL:
105:     MatCreateMatSinvert(st,&ctx->mat);
106:     KSPSetOperators(st->ksp,ctx->mat,ctx->mat,DIFFERENT_NONZERO_PATTERN);
107:     break;
108:   default:
109:     MatDuplicate(st->A,MAT_COPY_VALUES,&ctx->mat);
110:     alpha = -st->sigma;
111:     if (st->B) { MatAXPY(&alpha,st->B,ctx->mat,ctx->str); }
112:     else { MatShift(&alpha,ctx->mat); }
113:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
114:      * improve performance when solving a number of related eigenproblems */
115:     KSPSetOperators(st->ksp,ctx->mat,ctx->mat,SAME_NONZERO_PATTERN);
116:   }
117:   if (st->B && !ctx->w) { VecDuplicate(st->vec,&ctx->w); }
118:   KSPSetRhs(st->ksp,st->vec);
119:   KSPSetUp(st->ksp);
120:   return(0);
121: }

125: static int STSetShift_Sinvert(ST st,PetscScalar newshift)
126: {
127:   int          ierr;
128:   ST_SINV      *stctx = (ST_SINV *) st->data;
129:   PetscScalar  alpha;
130:   CTX_SINV     *ctx;


134:   /* Nothing to be done if STSetUp has not been called yet */
135:   if (!st->setupcalled) return(0);

137:   switch (stctx->shift_matrix) {
138:   case STSINVERT_MATMODE_INPLACE:
139:     /* Undo previous operations */
140:     alpha = st->sigma;
141:     if (st->B) { MatAXPY(&alpha,st->B,st->A,stctx->str); }
142:     else { MatShift(&alpha,st->A); }
143:     /* Apply new shift */
144:     alpha = -newshift;
145:     if (st->B) { MatAXPY(&alpha,st->B,st->A,stctx->str); }
146:     else { MatShift(&alpha,st->A); }
147:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
148:     break;
149:   case STSINVERT_MATMODE_SHELL:
150:     MatShellGetContext(stctx->mat,(void**)&ctx);
151:     ctx->sigma = newshift;
152:     KSPSetOperators(st->ksp,stctx->mat,stctx->mat,SAME_NONZERO_PATTERN);
153:     break;
154:   default:
155:     MatCopy(st->A, stctx->mat, DIFFERENT_NONZERO_PATTERN);
156:     alpha = -st->sigma;
157:     if (st->B) { MatAXPY(&alpha,st->B,stctx->mat,stctx->str); }
158:     else { MatShift(&alpha,stctx->mat); }
159:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
160:      * improve performance when solving a number of related eigenproblems */
161:     KSPSetOperators(st->ksp,stctx->mat,stctx->mat,SAME_NONZERO_PATTERN);
162:   }
163:   KSPSetRhs(st->ksp,st->vec);
164:   KSPSetUp(st->ksp);
165:   return(0);
166: }

170: static int STDestroy_Sinvert(ST st)
171: {
172:   ST_SINV  *ctx = (ST_SINV *) st->data;
173:   int      ierr;

176:   if (ctx->shift_matrix != STSINVERT_MATMODE_INPLACE && ctx->mat) {
177:     MatDestroy(ctx->mat);
178:   }
179:   if (st->B) { VecDestroy(ctx->w); }
180:   PetscFree(ctx);
181:   return(0);
182: }

186: static int STView_Sinvert(ST st,PetscViewer viewer)
187: {
188:   ST_SINV    *ctx = (ST_SINV *) st->data;
189:   int        ierr;
190:   PetscTruth isascii;
191:   char       *str;

194:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
195:   if (!isascii) {
196:     SETERRQ1(1,"Viewer type %s not supported for STSINV",((PetscObject)viewer)->type_name);
197:   }
198:   switch (ctx->shift_matrix) {
199:   case STSINVERT_MATMODE_COPY:
200:     break;
201:   case STSINVERT_MATMODE_INPLACE:
202:     PetscViewerASCIIPrintf(viewer,"Shifting the matrix and unshifting at exit\n");
203:     break;
204:   case STSINVERT_MATMODE_SHELL:
205:     PetscViewerASCIIPrintf(viewer,"Using a shell matrix\n");
206:     break;
207:   }
208:   if (st->B && ctx->shift_matrix != STSINVERT_MATMODE_SHELL) {
209:     switch (ctx->str) {
210:       case SAME_NONZERO_PATTERN:      str = "same nonzero pattern";break;
211:       case DIFFERENT_NONZERO_PATTERN: str = "different nonzero pattern";break;
212:       case SUBSET_NONZERO_PATTERN:    str = "subset nonzero pattern";break;
213:       default:                        SETERRQ(1,"Wrong structure flag");break;
214:     }
215:     PetscViewerASCIIPrintf(viewer,"Matrices A and B have %s\n",str);
216:   }
217:   return(0);
218: }

222: static int STSetFromOptions_Sinvert(ST st)
223: {
224:   int        i,ierr;
225:   PetscTruth flg;
226:   const char *mode_list[3] = { "copy", "inplace", "shell" };

229:   PetscOptionsHead("ST Shift-and-invert Options");
230:     PetscOptionsEList("-st_sinvert_matmode", "Shift matrix mode","STSinvertSetMatMode",mode_list,3,mode_list[0],&i,&flg);
231:     if (flg) {
232:       STSinvertSetMatMode(st, (STSinvertMatMode)i);
233:     }
234: 
235:     PetscOptionsLogicalGroupBegin("-st_sinvert_same_pattern","same nonzero pattern","STSinvertSetMatStructure",&flg);
236:     if (flg) {STSinvertSetMatStructure(st,SAME_NONZERO_PATTERN);}
237:     PetscOptionsLogicalGroup("-st_sinvert_different_pattern","different nonzero pattern","STSinvertSetMatStructure",&flg);
238:     if (flg) {STSinvertSetMatStructure(st,DIFFERENT_NONZERO_PATTERN);}
239:     PetscOptionsLogicalGroupEnd("-st_sinvert_subset_pattern","subset nonzero pattern","STSinvertSetMatStructure",&flg);
240:     if (flg) {STSinvertSetMatStructure(st,SUBSET_NONZERO_PATTERN);}
241:   PetscOptionsTail();
242:   return(0);
243: }

245: /* -------------------------------------------------------------------------*/

247: EXTERN_C_BEGIN
250: int STSinvertSetMatMode_Sinvert(ST st,STSinvertMatMode mode)
251: {
252:   int        ierr;
253:   PC         pc;
254:   ST_SINV    *ctx = (ST_SINV *) st->data;

257:   ctx->shift_matrix = mode;
258:   if (mode == STSINVERT_MATMODE_SHELL) {
259:     /* if shift_mat is set then the default preconditioner is ILU,
260:        otherwise set Jacobi as the default */
261:     KSPGetPC(st->ksp,&pc);
262:     PCSetType(pc,PCJACOBI);
263:   }
264:   return(0);
265: }
266: EXTERN_C_END

270: /*@
271:    STSinvertSetMatMode - Sets a flag to indicate how the matrix is
272:    being shifted in the shift-and-invert spectral transformation.

274:    Collective on ST

276:    Input Parameters:
277: +  st - the spectral transformation context
278: -  mode - the mode flag, one of STSINVERT_MATMODE_COPY, 
279:           STSINVERT_MATMODE_INPLACE or STSINVERT_MATMODE_SHELL

281:    Options Database Key:
282: .  -st_sinvert_matmode <mode> - Activates STSinvertSetMatMode()

284:    Note:
285:    By default (STSINVERT_MATMODE_COPY), a copy of matrix A is made and then 
286:    this copy is shifted explicitly, e.g. A <- (A - s B). 

288:    With STSINVERT_MATMODE_INPLACE, the original matrix A is shifted at 
289:    STSetUp() and unshifted at the end of the computations. With respect to
290:    the previous one, this mode avoids a copy of matrix A. However, a
291:    backdraw is that the recovered matrix might be slightly different 
292:    from the original one (due to roundoff).

294:    With STSINVERT_MATMODE_SHELL, the solver works with an implicit shell 
295:    matrix that represents the shifted matrix. This mode is the most efficient 
296:    in creating the shifted matrix but it places serious limitations to the 
297:    linear solves performed in each iteration of the eigensolver (typically,
298:    only interative solvers with Jacobi preconditioning can be used).
299:    
300:    In the case of generalized problems, in the two first modes the matrix
301:    A - s B has to be computed explicitly. The efficiency of this computation 
302:    can be controlled with STSinvertSetMatStructure().

304:    Level: intermediate

306: .seealso: STSetOperators(), STSinvertSetMatStructure()
307: @*/
308: int STSinvertSetMatMode(ST st, STSinvertMatMode mode)
309: {
310:   int ierr, (*f)(ST,STSinvertMatMode);

314:   PetscObjectQueryFunction((PetscObject)st,"STSinvertSetMatMode_C",(void (**)(void))&f);
315:   if (f) {
316:     (*f)(st,mode);
317:   }
318:   return(0);
319: }

321: EXTERN_C_BEGIN
324: int STSinvertSetMatStructure_Sinvert(ST st,MatStructure str)
325: {
326:   ST_SINV    *ctx = (ST_SINV *) st->data;

329:   ctx->str = str;
330:   return(0);
331: }
332: EXTERN_C_END

336: /*@
337:    STSinvertSetMatStructure - Sets an internal MatStructure attribute to 
338:    indicate which is the relation of the sparsity pattern of the two matrices
339:    A and B constituting the generalized eigenvalue problem. This function
340:    has no effect in the case of standard eigenproblems.

342:    Collective on ST

344:    Input Parameters:
345: +  st  - the spectral transformation context
346: -  str - either SAME_NONZERO_PATTERN, DIFFERENT_NONZERO_PATTERN or
347:          SUBSET_NONZERO_PATTERN

349:    Options Database Key:
350: +  -st_sinvert_same_pattern - Indicates A and B have the same nonzero pattern
351: .  -st_sinvert_different_pattern - Indicates A and B have different nonzero pattern
352: -  -st_sinvert_subset_pattern - Indicates B's nonzero pattern is a subset of B's

354:    Note:
355:    By default, the sparsity patterns are assumed to be different. If the
356:    patterns are equal or a subset then it is recommended to set this attribute
357:    for efficiency reasons (in particular, for internal MatAXPY() operations).
358:    
359:    Level: advanced

361: .seealso: STSetOperators(), MatAXPY()
362: @*/
363: int STSinvertSetMatStructure(ST st,MatStructure str)
364: {
365:   int ierr, (*f)(ST,MatStructure);

369:   PetscObjectQueryFunction((PetscObject)st,"STSinvertSetMatStructure_C",(void (**)(void))&f);
370:   if (f) {
371:     (*f)(st,str);
372:   }
373:   return(0);
374: }

376: /* ---------------------------------------------------------------------------*/

378: EXTERN_C_BEGIN
381: int STCreate_Sinvert(ST st)
382: {
383:   int       ierr;
384:   char      *prefix;
385:   ST_SINV   *ctx;

388:   PetscNew(ST_SINV,&ctx);
389:   PetscMemzero(ctx,sizeof(ST_SINV));
390:   PetscLogObjectMemory(st,sizeof(ST_SINV));
391:   st->numberofshifts      = 1;
392:   st->data                = (void *) ctx;

394:   st->ops->apply          = STApply_Sinvert;
395:   st->ops->applynoB       = STApplyNoB_Sinvert;
396:   st->ops->postsolve      = STPost_Sinvert;
397:   st->ops->backtr         = STBackTransform_Sinvert;
398:   st->ops->setup          = STSetUp_Sinvert;
399:   st->ops->setshift       = STSetShift_Sinvert;
400:   st->ops->destroy        = STDestroy_Sinvert;
401:   st->ops->setfromoptions = STSetFromOptions_Sinvert;
402:   st->ops->view           = STView_Sinvert;

404:   KSPCreate(st->comm,&st->ksp);
405:   STGetOptionsPrefix(st,&prefix);
406:   KSPSetOptionsPrefix(st->ksp,prefix);
407:   KSPAppendOptionsPrefix(st->ksp,"st_");
408:   ctx->shift_matrix = STSINVERT_MATMODE_COPY;
409:   ctx->str          = DIFFERENT_NONZERO_PATTERN;

411:   PetscObjectComposeFunctionDynamic((PetscObject)st,"STSinvertSetMatMode_C","STSinvertSetMatMode_Sinvert",
412:                     STSinvertSetMatMode_Sinvert);
413:   PetscObjectComposeFunctionDynamic((PetscObject)st,"STSinvertSetMatStructure_C","STSinvertSetMatStructure_Sinvert",
414:                     STSinvertSetMatStructure_Sinvert);

416:   return(0);
417: }
418: EXTERN_C_END