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