Actual source code: cayley.c
1: /*
2: Implements the Cayley spectral transform.
3: */
4: #include src/st/stimpl.h
6: typedef struct {
7: PetscScalar tau;
8: PetscTruth tau_set;
9: Vec w2;
10: } ST_CAYLEY;
14: PetscErrorCode STApply_Cayley(ST st,Vec x,Vec y)
15: {
16: PetscErrorCode ierr;
17: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
18: PetscScalar tau = ctx->tau;
19:
21: if (st->shift_matrix == STMATMODE_INPLACE) { tau = tau + st->sigma; };
23: if (st->B) {
24: /* generalized eigenproblem: y = (A - sB)^-1 (A + tB)x */
25: MatMult(st->A,x,st->w);
26: MatMult(st->B,x,ctx->w2);
27: VecAXPY(&tau,ctx->w2,st->w);
28: STAssociatedKSPSolve(st,st->w,y);
29: }
30: else {
31: /* standard eigenproblem: y = (A - sI)^-1 (A + tI)x */
32: MatMult(st->A,x,st->w);
33: VecAXPY(&tau,x,st->w);
34: STAssociatedKSPSolve(st,st->w,y);
35: }
36: return(0);
37: }
41: PetscErrorCode STApplyNoB_Cayley(ST st,Vec x,Vec y)
42: {
43: PetscErrorCode ierr;
46: STAssociatedKSPSolve(st,x,y);
47: return(0);
48: }
52: PetscErrorCode STApplyB_Cayley(ST st,Vec x,Vec y)
53: {
54: PetscErrorCode ierr;
55: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
56: PetscScalar tau = ctx->tau;
57:
59: if (st->shift_matrix == STMATMODE_INPLACE) { tau = tau + st->sigma; };
61: if (st->B) {
62: /* generalized eigenproblem: y = (A + tB)x */
63: MatMult(st->A,x,y);
64: MatMult(st->B,x,ctx->w2);
65: VecAXPY(&tau,ctx->w2,y);
66: }
67: else {
68: /* standard eigenproblem: y = (A + tI)x */
69: MatMult(st->A,x,y);
70: VecAXPY(&tau,x,y);
71: }
72: return(0);
73: }
77: PetscErrorCode STBackTransform_Cayley(ST st,PetscScalar *eigr,PetscScalar *eigi)
78: {
79: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
80: #ifndef PETSC_USE_COMPLEX
81: PetscScalar t,i,r;
85: if (*eigi == 0.0) *eigr = (ctx->tau + *eigr * st->sigma) / (*eigr - 1.0);
86: else {
87: r = *eigr;
88: i = *eigi;
89: r = st->sigma * (r * r + i * i - r) + ctx->tau * (r - 1);
90: i = - st->sigma * i - ctx->tau * i;
91: t = i * i + r * (r - 2.0) + 1.0;
92: *eigr = r / t;
93: *eigi = i / t;
94: }
95: #else
98: *eigr = (ctx->tau + *eigr * st->sigma) / (*eigr - 1.0);
99: #endif
100: return(0);
101: }
105: PetscErrorCode STPost_Cayley(ST st)
106: {
107: PetscErrorCode ierr;
108: PetscScalar alpha;
111: if (st->shift_matrix == STMATMODE_INPLACE) {
112: alpha = st->sigma;
113: if( st->B ) { MatAXPY(&alpha,st->B,st->A,st->str); }
114: else { MatShift(&alpha, st->A); }
115: st->setupcalled = 0;
116: }
117: return(0);
118: }
122: PetscErrorCode STSetUp_Cayley(ST st)
123: {
124: PetscErrorCode ierr;
125: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
126: PetscScalar alpha;
130: if (st->mat) { MatDestroy(st->mat); }
131: if (!ctx->tau_set) { ctx->tau = st->sigma; }
132: if (ctx->tau == 0.0 && st->sigma == 0.0) {
133: SETERRQ(1,"Values of shift and antishift cannot be zero simultaneously");
134: }
136: switch (st->shift_matrix) {
137: case STMATMODE_INPLACE:
138: st->mat = PETSC_NULL;
139: if (st->sigma != 0.0) {
140: alpha = -st->sigma;
141: if (st->B) {
142: MatAXPY(&alpha,st->B,st->A,st->str);
143: } else {
144: MatShift(&alpha,st->A);
145: }
146: }
147: /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
148: * improve performance when solving a number of related eigenproblems */
149: KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
150: break;
151: case STMATMODE_SHELL:
152: STMatShellCreate(st,&st->mat);
153: KSPSetOperators(st->ksp,st->mat,st->mat,DIFFERENT_NONZERO_PATTERN);
154: break;
155: default:
156: MatDuplicate(st->A,MAT_COPY_VALUES,&st->mat);
157: if (st->sigma != 0.0) {
158: alpha = -st->sigma;
159: if (st->B) {
160: MatAXPY(&alpha,st->B,st->mat,st->str);
161: } else {
162: MatShift(&alpha,st->mat);
163: }
164: }
165: /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
166: * improve performance when solving a number of related eigenproblems */
167: KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
168: }
169: if (st->B) {
170: if (ctx->w2) { VecDestroy(ctx->w2); }
171: MatGetVecs(st->B,&ctx->w2,PETSC_NULL);
172: }
173: KSPSetUp(st->ksp);
174: return(0);
175: }
179: PetscErrorCode STSetShift_Cayley(ST st,PetscScalar newshift)
180: {
181: PetscErrorCode ierr;
182: PetscScalar alpha;
183: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
187: /* Nothing to be done if STSetUp has not been called yet */
188: if (!st->setupcalled) return(0);
190: switch (st->shift_matrix) {
191: case STMATMODE_INPLACE:
192: /* Undo previous operations */
193: if (st->sigma != 0.0) {
194: alpha = st->sigma;
195: if (st->B) { MatAXPY(&alpha,st->B,st->A,st->str); }
196: else { MatShift(&alpha,st->A); }
197: }
198: /* Apply new shift */
199: if (newshift != 0.0) {
200: alpha = -newshift;
201: if (st->B) { MatAXPY(&alpha,st->B,st->A,st->str); }
202: else { MatShift(&alpha,st->A); }
203: }
204: KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
205: break;
206: case STMATMODE_SHELL:
207: KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
208: break;
209: default:
210: MatCopy(st->A, st->mat,SUBSET_NONZERO_PATTERN);
211: if (newshift != 0.0) {
212: alpha = -newshift;
213: if (st->B) { MatAXPY(&alpha,st->B,st->mat,st->str); }
214: else { MatShift(&alpha,st->mat); }
215: }
216: /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
217: * improve performance when solving a number of related eigenproblems */
218: KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
219: }
220: st->sigma = newshift;
221: if (!ctx->tau_set) { ctx->tau = newshift; }
222: KSPSetUp(st->ksp);
223: return(0);
224: }
228: PetscErrorCode STSetFromOptions_Cayley(ST st)
229: {
230: PetscErrorCode ierr;
231: PetscScalar tau;
232: PetscTruth flg;
233: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
236: PetscOptionsHead("ST Cayley Options");
237: PetscOptionsScalar("-st_antishift","Value of the antishift","STSetAntishift",ctx->tau,&tau,&flg);
238: if (flg) {
239: STCayleySetAntishift(st,tau);
240: }
241: PetscOptionsTail();
242: return(0);
243: }
245: EXTERN_C_BEGIN
248: PetscErrorCode STCayleySetAntishift_Cayley(ST st,PetscScalar newshift)
249: {
250: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
253: ctx->tau = newshift;
254: ctx->tau_set = PETSC_TRUE;
255: return(0);
256: }
257: EXTERN_C_END
261: /*@
262: STCayleySetAntishift - Sets the value of the anti-shift for the Cayley
263: spectral transformation.
265: Collective on ST
267: Input Parameters:
268: + st - the spectral transformation context
269: - tau - the anti-shift
271: Options Database Key:
272: . -st_antishift - Sets the value of the anti-shift
274: Level: intermediate
276: Note:
277: In the generalized Cayley transform, the operator can be expressed as
278: OP = inv(A - sigma B)*(A + tau B). This function sets the value of tau.
279: Use STSetShift() for setting sigma.
281: .seealso: STSetShift()
282: @*/
283: PetscErrorCode STCayleySetAntishift(ST st,PetscScalar tau)
284: {
285: PetscErrorCode ierr, (*f)(ST,PetscScalar);
289: PetscObjectQueryFunction((PetscObject)st,"STCayleySetAntishift_C",(void (**)(void))&f);
290: if (f) {
291: (*f)(st,tau);
292: }
293: return(0);
294: }
298: PetscErrorCode STView_Cayley(ST st,PetscViewer viewer)
299: {
300: PetscErrorCode ierr;
301: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
304: #if !defined(PETSC_USE_COMPLEX)
305: PetscViewerASCIIPrintf(viewer," antishift: %g\n",ctx->tau);
306: #else
307: PetscViewerASCIIPrintf(viewer," antishift: %g+%g i\n",PetscRealPart(ctx->tau),PetscImaginaryPart(ctx->tau));
308: #endif
309: STView_Default(st,viewer);
310: return(0);
311: }
315: PetscErrorCode STDestroy_Cayley(ST st)
316: {
317: PetscErrorCode ierr;
318: ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;
321: if (ctx->w2) { VecDestroy(ctx->w2); }
322: PetscFree(ctx);
323: return(0);
324: }
326: EXTERN_C_BEGIN
329: PetscErrorCode STCreate_Cayley(ST st)
330: {
331: PetscErrorCode ierr;
332: ST_CAYLEY *ctx;
335: PetscNew(ST_CAYLEY,&ctx);
336: PetscMemzero(ctx,sizeof(ST_CAYLEY));
337: PetscLogObjectMemory(st,sizeof(ST_CAYLEY));
338: st->data = (void *) ctx;
340: st->ops->apply = STApply_Cayley;
341: st->ops->applyB = STApplyB_Cayley;
342: st->ops->applynoB = STApplyNoB_Cayley;
343: st->ops->postsolve = STPost_Cayley;
344: st->ops->backtr = STBackTransform_Cayley;
345: st->ops->setfromoptions = STSetFromOptions_Cayley;
346: st->ops->setup = STSetUp_Cayley;
347: st->ops->setshift = STSetShift_Cayley;
348: st->ops->destroy = STDestroy_Cayley;
349: st->ops->view = STView_Cayley;
350:
351: st->checknullspace = STCheckNullSpace_Default;
353: ctx->tau = 0.0;
354: ctx->tau_set = PETSC_FALSE;
356: PetscObjectComposeFunctionDynamic((PetscObject)st,"STCayleySetAntishift_C","STCayleySetAntishift_Cayley",
357: STCayleySetAntishift_Cayley);
359: return(0);
360: }
361: EXTERN_C_END