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