Actual source code: stsolve.c
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: ST interface routines, callable by users
12: */
14: #include <slepc/private/stimpl.h>
16: PetscErrorCode STApply_Generic(ST st,Vec x,Vec y)
17: {
18: PetscFunctionBegin;
19: if (st->M && st->P) {
20: PetscCall(MatMult(st->M,x,st->work[0]));
21: PetscCall(STMatSolve(st,st->work[0],y));
22: } else if (st->M) PetscCall(MatMult(st->M,x,y));
23: else PetscCall(STMatSolve(st,x,y));
24: PetscFunctionReturn(PETSC_SUCCESS);
25: }
27: /*@
28: STApply - Applies the spectral transformation operator to a vector, for
29: instance $y=(A - \sigma B)^{-1} Bx$ in the case of the shift-and-invert transformation
30: and generalized eigenproblem.
32: Collective
34: Input Parameters:
35: + st - the spectral transformation context
36: - x - input vector
38: Output Parameter:
39: . y - output vector
41: Level: developer
43: .seealso: [](ch:st), `STApplyTranspose()`, `STApplyHermitianTranspose()`
44: @*/
45: PetscErrorCode STApply(ST st,Vec x,Vec y)
46: {
47: Mat Op;
49: PetscFunctionBegin;
54: STCheckMatrices(st,1);
55: PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
56: PetscCall(VecSetErrorIfLocked(y,3));
57: PetscCall(STGetOperator_Private(st,&Op));
58: PetscCall(MatMult(Op,x,y));
59: PetscFunctionReturn(PETSC_SUCCESS);
60: }
62: PetscErrorCode STApplyMat_Generic(ST st,Mat B,Mat C)
63: {
64: Mat work;
66: PetscFunctionBegin;
67: if (st->M && st->P) {
68: PetscCall(MatMatMult(st->M,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&work));
69: PetscCall(STMatMatSolve(st,work,C));
70: PetscCall(MatDestroy(&work));
71: } else if (st->M) PetscCall(MatMatMult(st->M,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&C));
72: else PetscCall(STMatMatSolve(st,B,C));
73: PetscFunctionReturn(PETSC_SUCCESS);
74: }
76: /*@
77: STApplyMat - Applies the spectral transformation operator to a matrix, for
78: instance $Y = (A - \sigma B)^{-1} B X$ in the case of the shift-and-invert
79: transformation and generalized eigenproblem.
81: Collective
83: Input Parameters:
84: + st - the spectral transformation context
85: - X - input matrix
87: Output Parameter:
88: . Y - output matrix
90: Level: developer
92: .seealso: [](ch:st), `STApply()`
93: @*/
94: PetscErrorCode STApplyMat(ST st,Mat X,Mat Y)
95: {
96: PetscFunctionBegin;
101: STCheckMatrices(st,1);
102: PetscCheck(X!=Y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"X and Y must be different matrices");
103: PetscUseTypeMethod(st,applymat,X,Y);
104: PetscFunctionReturn(PETSC_SUCCESS);
105: }
107: PetscErrorCode STApplyTranspose_Generic(ST st,Vec x,Vec y)
108: {
109: PetscFunctionBegin;
110: if (st->M && st->P) {
111: PetscCall(STMatSolveTranspose(st,x,st->work[0]));
112: PetscCall(MatMultTranspose(st->M,st->work[0],y));
113: } else if (st->M) PetscCall(MatMultTranspose(st->M,x,y));
114: else PetscCall(STMatSolveTranspose(st,x,y));
115: PetscFunctionReturn(PETSC_SUCCESS);
116: }
118: /*@
119: STApplyTranspose - Applies the transpose of the operator to a vector, for
120: instance $y = B^T(A - \sigma B)^{-T} x$ in the case of the shift-and-invert
121: transformation and generalized eigenproblem.
123: Collective
125: Input Parameters:
126: + st - the spectral transformation context
127: - x - input vector
129: Output Parameter:
130: . y - output vector
132: Level: developer
134: .seealso: [](ch:st), `STApply()`, `STApplyHermitianTranspose()`
135: @*/
136: PetscErrorCode STApplyTranspose(ST st,Vec x,Vec y)
137: {
138: Mat Op;
140: PetscFunctionBegin;
145: STCheckMatrices(st,1);
146: PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
147: PetscCall(VecSetErrorIfLocked(y,3));
148: PetscCall(STGetOperator_Private(st,&Op));
149: PetscCall(MatMultTranspose(Op,x,y));
150: PetscFunctionReturn(PETSC_SUCCESS);
151: }
153: PetscErrorCode STApplyHermitianTranspose_Generic(ST st,Vec x,Vec y)
154: {
155: PetscFunctionBegin;
156: if (st->M && st->P) {
157: PetscCall(STMatSolveHermitianTranspose(st,x,st->work[0]));
158: PetscCall(MatMultHermitianTranspose(st->M,st->work[0],y));
159: } else if (st->M) PetscCall(MatMultHermitianTranspose(st->M,x,y));
160: else PetscCall(STMatSolveHermitianTranspose(st,x,y));
161: PetscFunctionReturn(PETSC_SUCCESS);
162: }
164: /*@
165: STApplyHermitianTranspose - Applies the Hermitian-transpose of the operator
166: to a vector, for instance $y=B^*(A - \sigma B)^{-*}x$ in the case of the shift-and-invert
167: transformation and generalized eigenproblem.
169: Collective
171: Input Parameters:
172: + st - the spectral transformation context
173: - x - input vector
175: Output Parameter:
176: . y - output vector
178: Note:
179: Currently implemented via `STApplyTranspose()` with appropriate conjugation.
181: Level: developer
183: .seealso: [](ch:st), `STApply()`, `STApplyTranspose()`
184: @*/
185: PetscErrorCode STApplyHermitianTranspose(ST st,Vec x,Vec y)
186: {
187: Mat Op;
189: PetscFunctionBegin;
194: STCheckMatrices(st,1);
195: PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
196: PetscCall(VecSetErrorIfLocked(y,3));
197: PetscCall(STGetOperator_Private(st,&Op));
198: PetscCall(MatMultHermitianTranspose(Op,x,y));
199: PetscFunctionReturn(PETSC_SUCCESS);
200: }
202: /*@
203: STGetBilinearForm - Returns the matrix used in the bilinear form with a
204: generalized eigenproblem with semi-definite $B$.
206: Logically Collective
208: Input Parameter:
209: . st - the spectral transformation context
211: Output Parameter:
212: . B - output matrix
214: Notes:
215: The output matrix `B` must be destroyed after use. It will be `NULL` in
216: case of standard eigenproblems.
218: Level: developer
220: .seealso: [](ch:st), `BVSetMatrix()`
221: @*/
222: PetscErrorCode STGetBilinearForm(ST st,Mat *B)
223: {
224: PetscFunctionBegin;
227: PetscAssertPointer(B,2);
228: STCheckMatrices(st,1);
229: PetscUseTypeMethod(st,getbilinearform,B);
230: PetscFunctionReturn(PETSC_SUCCESS);
231: }
233: PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
234: {
235: PetscFunctionBegin;
236: if (st->nmat==1) *B = NULL;
237: else {
238: *B = st->A[1];
239: PetscCall(PetscObjectReference((PetscObject)*B));
240: }
241: PetscFunctionReturn(PETSC_SUCCESS);
242: }
244: static PetscErrorCode MatMult_STOperator(Mat Op,Vec x,Vec y)
245: {
246: ST st;
248: PetscFunctionBegin;
249: PetscCall(MatShellGetContext(Op,&st));
250: PetscCall(STSetUp(st));
251: PetscCall(PetscLogEventBegin(ST_Apply,st,x,y,0));
252: if (st->D) { /* with balancing */
253: PetscCall(VecPointwiseDivide(st->wb,x,st->D));
254: PetscUseTypeMethod(st,apply,st->wb,y);
255: PetscCall(VecPointwiseMult(y,y,st->D));
256: } else PetscUseTypeMethod(st,apply,x,y);
257: PetscCall(PetscLogEventEnd(ST_Apply,st,x,y,0));
258: PetscFunctionReturn(PETSC_SUCCESS);
259: }
261: static PetscErrorCode MatMultTranspose_STOperator(Mat Op,Vec x,Vec y)
262: {
263: ST st;
265: PetscFunctionBegin;
266: PetscCall(MatShellGetContext(Op,&st));
267: PetscCall(STSetUp(st));
268: PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
269: if (st->D) { /* with balancing */
270: PetscCall(VecPointwiseMult(st->wb,x,st->D));
271: PetscUseTypeMethod(st,applytrans,st->wb,y);
272: PetscCall(VecPointwiseDivide(y,y,st->D));
273: } else PetscUseTypeMethod(st,applytrans,x,y);
274: PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
275: PetscFunctionReturn(PETSC_SUCCESS);
276: }
278: #if defined(PETSC_USE_COMPLEX)
279: static PetscErrorCode MatMultHermitianTranspose_STOperator(Mat Op,Vec x,Vec y)
280: {
281: ST st;
283: PetscFunctionBegin;
284: PetscCall(MatShellGetContext(Op,&st));
285: PetscCall(STSetUp(st));
286: PetscCall(PetscLogEventBegin(ST_ApplyHermitianTranspose,st,x,y,0));
287: if (st->ops->applyhermtrans) {
288: if (st->D) { /* with balancing */
289: PetscCall(VecConjugate(st->D));
290: PetscCall(VecPointwiseMult(st->wb,x,st->D));
291: PetscUseTypeMethod(st,applyhermtrans,st->wb,y);
292: PetscCall(VecPointwiseDivide(y,y,st->D));
293: PetscCall(VecConjugate(st->D));
294: } else PetscUseTypeMethod(st,applyhermtrans,x,y);
295: } else {
296: if (!st->wht) PetscCall(MatCreateVecs(st->A[0],&st->wht,NULL));
297: PetscCall(VecCopy(x,st->wht));
298: PetscCall(VecConjugate(st->wht));
299: if (st->D) { /* with balancing */
300: PetscCall(VecPointwiseMult(st->wb,st->wht,st->D));
301: PetscUseTypeMethod(st,applytrans,st->wb,y);
302: PetscCall(VecPointwiseDivide(y,y,st->D));
303: } else PetscUseTypeMethod(st,applytrans,st->wht,y);
304: PetscCall(VecConjugate(y));
305: }
306: PetscCall(PetscLogEventEnd(ST_ApplyHermitianTranspose,st,x,y,0));
307: PetscFunctionReturn(PETSC_SUCCESS);
308: }
309: #endif
311: static PetscErrorCode MatMatMult_STOperator(Mat Op,Mat B,Mat C,void *ctx)
312: {
313: ST st;
315: PetscFunctionBegin;
316: PetscCall(MatShellGetContext(Op,&st));
317: PetscCall(STSetUp(st));
318: PetscCall(PetscLogEventBegin(ST_Apply,st,B,C,0));
319: PetscCall(STApplyMat_Generic(st,B,C));
320: PetscCall(PetscLogEventEnd(ST_Apply,st,B,C,0));
321: PetscFunctionReturn(PETSC_SUCCESS);
322: }
324: PetscErrorCode STGetOperator_Private(ST st,Mat *Op)
325: {
326: PetscInt m,n,M,N;
327: Vec v;
328: VecType vtype;
330: PetscFunctionBegin;
331: if (!st->Op) {
332: if (Op) *Op = NULL;
333: /* create the shell matrix */
334: PetscCall(MatGetLocalSize(st->A[0],&m,&n));
335: PetscCall(MatGetSize(st->A[0],&M,&N));
336: PetscCall(MatCreateShell(PetscObjectComm((PetscObject)st),m,n,M,N,st,&st->Op));
337: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT,(PetscErrorCodeFn*)MatMult_STOperator));
338: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_TRANSPOSE,(PetscErrorCodeFn*)MatMultTranspose_STOperator));
339: #if defined(PETSC_USE_COMPLEX)
340: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(PetscErrorCodeFn*)MatMultHermitianTranspose_STOperator));
341: #else
342: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(PetscErrorCodeFn*)MatMultTranspose_STOperator));
343: #endif
344: if (!st->D && st->ops->apply==STApply_Generic) {
345: PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSE,MATDENSE));
346: PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSECUDA,MATDENSECUDA));
347: PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSEHIP,MATDENSEHIP));
348: }
349: /* make sure the shell matrix generates a vector of the same type as the problem matrices */
350: PetscCall(MatCreateVecs(st->A[0],&v,NULL));
351: PetscCall(VecGetType(v,&vtype));
352: PetscCall(MatShellSetVecType(st->Op,vtype));
353: PetscCall(VecDestroy(&v));
354: /* build the operator matrices */
355: PetscCall(STComputeOperator(st));
356: }
357: if (Op) *Op = st->Op;
358: PetscFunctionReturn(PETSC_SUCCESS);
359: }
361: /*@
362: STGetOperator - Returns a shell matrix that represents the operator of the
363: spectral transformation.
365: Collective
367: Input Parameter:
368: . st - the spectral transformation context
370: Output Parameter:
371: . Op - operator matrix
373: Notes:
374: The operator is defined in linear eigenproblems only, not in polynomial ones,
375: so the call will fail if more than 2 matrices were passed in `STSetMatrices()`.
377: The returned shell matrix is essentially a wrapper to the `STApply()` and
378: `STApplyTranspose()` operations. The operator can often be expressed as
380: $$Op = D K^{-1} M D^{-1}$$
382: where $D$ is the balancing matrix, and $M$ and $K$ are two matrices corresponding
383: to the numerator and denominator for spectral transformations that represent
384: a rational matrix function. In the case of `STSHELL`, the inner part $K^{-1}M$
385: is replaced by the user-provided operation from `STShellSetApply()`.
387: The preconditioner matrix $K$ typically depends on the value of the shift, and
388: its inverse is handled via an internal `KSP` object. Normal usage does not
389: require explicitly calling `STGetOperator()`, but it can be used to force the
390: creation of $K$ and $M$, and then $K$ is passed to the `KSP`. This is useful for
391: setting options associated with the `PCFactor` (to set MUMPS options, for instance).
393: The returned matrix must NOT be destroyed by the user. Instead, when no
394: longer needed it must be returned with `STRestoreOperator()`. In particular,
395: this is required before modifying the `ST` matrices or the shift.
397: A `NULL` pointer can be passed in `Op` in case the matrix is not required but we
398: want to force its creation. In this case, `STRestoreOperator()` should not be
399: called.
401: Level: advanced
403: .seealso: [](ch:st), `STApply()`, `STApplyTranspose()`, `STSetBalanceMatrix()`, `STShellSetApply()`, `STGetKSP()`, `STSetShift()`, `STRestoreOperator()`, `STSetMatrices()`
404: @*/
405: PetscErrorCode STGetOperator(ST st,Mat *Op)
406: {
407: PetscFunctionBegin;
410: STCheckMatrices(st,1);
411: STCheckNotSeized(st,1);
412: PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"The operator is not defined in polynomial eigenproblems");
413: PetscCall(STGetOperator_Private(st,Op));
414: if (Op) st->opseized = PETSC_TRUE;
415: PetscFunctionReturn(PETSC_SUCCESS);
416: }
418: /*@
419: STRestoreOperator - Restore the previously seized operator matrix.
421: Logically Collective
423: Input Parameters:
424: + st - the spectral transformation context
425: - Op - operator matrix
427: Notes:
428: The arguments must match the corresponding call to `STGetOperator()`.
430: Level: advanced
432: .seealso: [](ch:st), `STGetOperator()`
433: @*/
434: PetscErrorCode STRestoreOperator(ST st,Mat *Op)
435: {
436: PetscFunctionBegin;
438: PetscAssertPointer(Op,2);
440: PetscCheck(st->opseized,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must be called after STGetOperator()");
441: *Op = NULL;
442: st->opseized = PETSC_FALSE;
443: PetscFunctionReturn(PETSC_SUCCESS);
444: }
446: /*
447: STComputeOperator - Computes the matrices that constitute the operator
449: Op = D*inv(K)*M*inv(D).
451: K and M are computed here (D is user-provided) from the system matrices
452: and the shift sigma (whenever these are changed, this function recomputes
453: K and M). This is used only in linear eigenproblems (nmat<3).
455: K is the "preconditioner matrix": it is the denominator in rational operators,
456: e.g. (A-sigma*B) in shift-and-invert. In non-rational transformations such
457: as STFILTER, K=NULL which means identity. After computing K, it is passed to
458: the internal KSP object via KSPSetOperators.
460: M is the numerator in rational operators. If unused it is set to NULL (e.g.
461: in STPRECOND).
463: STSHELL does not compute anything here, but sets the flag as if it was ready.
464: */
465: PetscErrorCode STComputeOperator(ST st)
466: {
467: PC pc;
469: PetscFunctionBegin;
472: if (!st->opready && st->ops->computeoperator) {
473: PetscCall(PetscInfo(st,"Building the operator matrices\n"));
474: STCheckMatrices(st,1);
475: if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
476: PetscCall(PetscLogEventBegin(ST_ComputeOperator,st,0,0,0));
477: PetscUseTypeMethod(st,computeoperator);
478: PetscCall(PetscLogEventEnd(ST_ComputeOperator,st,0,0,0));
479: if (st->usesksp) {
480: if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
481: if (st->P) {
482: PetscCall(STSetDefaultKSP(st));
483: PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
484: } else {
485: /* STPRECOND defaults to PCNONE if st->P is empty */
486: PetscCall(KSPGetPC(st->ksp,&pc));
487: PetscCall(PCSetType(pc,PCNONE));
488: }
489: }
490: }
491: st->opready = PETSC_TRUE;
492: PetscFunctionReturn(PETSC_SUCCESS);
493: }
495: /*@
496: STSetUp - Prepares for the use of a spectral transformation.
498: Collective
500: Input Parameter:
501: . st - the spectral transformation context
503: Level: advanced
505: .seealso: [](ch:st), `STCreate()`, `STApply()`, `STDestroy()`
506: @*/
507: PetscErrorCode STSetUp(ST st)
508: {
509: PetscInt i,n,k;
511: PetscFunctionBegin;
514: STCheckMatrices(st,1);
515: switch (st->state) {
516: case ST_STATE_INITIAL:
517: PetscCall(PetscInfo(st,"Setting up new ST\n"));
518: if (!((PetscObject)st)->type_name) PetscCall(STSetType(st,STSHIFT));
519: break;
520: case ST_STATE_SETUP:
521: PetscFunctionReturn(PETSC_SUCCESS);
522: case ST_STATE_UPDATED:
523: PetscCall(PetscInfo(st,"Setting up updated ST\n"));
524: break;
525: }
526: PetscCall(PetscLogEventBegin(ST_SetUp,st,0,0,0));
527: if (st->state!=ST_STATE_UPDATED) {
528: if (!(st->nmat<3 && st->opready)) {
529: if (st->T) {
530: for (i=0;i<PetscMax(2,st->nmat);i++) PetscCall(MatDestroy(&st->T[i]));
531: }
532: PetscCall(MatDestroy(&st->P));
533: }
534: }
535: if (st->D) {
536: PetscCall(MatGetLocalSize(st->A[0],NULL,&n));
537: PetscCall(VecGetLocalSize(st->D,&k));
538: PetscCheck(n==k,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %" PetscInt_FMT " (should be %" PetscInt_FMT ")",k,n);
539: if (!st->wb) PetscCall(VecDuplicate(st->D,&st->wb));
540: }
541: if (st->nmat<3 && st->transform) PetscCall(STComputeOperator(st));
542: else {
543: if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
544: }
545: PetscTryTypeMethod(st,setup);
546: st->state = ST_STATE_SETUP;
547: PetscCall(PetscLogEventEnd(ST_SetUp,st,0,0,0));
548: PetscFunctionReturn(PETSC_SUCCESS);
549: }
551: /*
552: Computes coefficients for the transformed polynomial,
553: and stores the result in argument S.
555: alpha - value of the parameter of the transformed polynomial
556: beta - value of the previous shift (only used in inplace mode)
557: k - index of first matrix included in the computation
558: coeffs - coefficients of the expansion
559: initial - true if this is the first time
560: precond - whether the preconditioner matrix must be computed
561: */
562: PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,PetscBool precond,Mat *S)
563: {
564: PetscInt *matIdx=NULL,nmat,i,ini=-1;
565: PetscScalar t=1.0,ta,gamma;
566: PetscBool nz=PETSC_FALSE;
567: Mat *A=precond?st->Psplit:st->A;
568: MatStructure str=precond?st->strp:st->str;
570: PetscFunctionBegin;
571: nmat = st->nmat-k;
572: switch (st->matmode) {
573: case ST_MATMODE_INPLACE:
574: PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
575: PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for split preconditioner");
576: if (initial) {
577: PetscCall(PetscObjectReference((PetscObject)A[0]));
578: *S = A[0];
579: gamma = alpha;
580: } else gamma = alpha-beta;
581: if (gamma != 0.0) {
582: if (st->nmat>1) PetscCall(MatAXPY(*S,gamma,A[1],str));
583: else PetscCall(MatShift(*S,gamma));
584: }
585: break;
586: case ST_MATMODE_SHELL:
587: PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_SHELL not supported for split preconditioner");
588: if (initial) {
589: if (st->nmat>2) {
590: PetscCall(PetscMalloc1(nmat,&matIdx));
591: for (i=0;i<nmat;i++) matIdx[i] = k+i;
592: }
593: PetscCall(STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S));
594: if (st->nmat>2) PetscCall(PetscFree(matIdx));
595: } else PetscCall(STMatShellShift(*S,alpha));
596: break;
597: case ST_MATMODE_COPY:
598: if (coeffs) {
599: for (i=0;i<nmat && ini==-1;i++) {
600: if (coeffs[i]!=0.0) ini = i;
601: else t *= alpha;
602: }
603: if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
604: for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
605: } else { nz = PETSC_TRUE; ini = 0; }
606: if ((alpha == 0.0 || !nz) && t==1.0) {
607: PetscCall(PetscObjectReference((PetscObject)A[k+ini]));
608: PetscCall(MatDestroy(S));
609: *S = A[k+ini];
610: } else {
611: if (*S && *S!=A[k+ini]) {
612: PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
613: PetscCall(MatCopy(A[k+ini],*S,DIFFERENT_NONZERO_PATTERN));
614: } else {
615: PetscCall(MatDestroy(S));
616: PetscCall(MatDuplicate(A[k+ini],MAT_COPY_VALUES,S));
617: PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
618: }
619: if (coeffs && coeffs[ini]!=1.0) PetscCall(MatScale(*S,coeffs[ini]));
620: for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
621: t *= alpha;
622: ta = t;
623: if (coeffs) ta *= coeffs[i-k];
624: if (ta!=0.0) {
625: if (st->nmat>1) PetscCall(MatAXPY(*S,ta,A[i],str));
626: else PetscCall(MatShift(*S,ta));
627: }
628: }
629: }
630: }
631: PetscCall(MatSetOption(*S,MAT_SYMMETRIC,st->asymm));
632: PetscCall(MatSetOption(*S,MAT_HERMITIAN,(PetscImaginaryPart(st->sigma)==0.0)?st->aherm:PETSC_FALSE));
633: PetscFunctionReturn(PETSC_SUCCESS);
634: }
636: /*
637: Computes the values of the coefficients required by STMatMAXPY_Private
638: for the case of monomial basis.
639: */
640: PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
641: {
642: PetscInt k,i,ini,inip;
644: PetscFunctionBegin;
645: /* Compute binomial coefficients */
646: ini = (st->nmat*(st->nmat-1))/2;
647: for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
648: for (k=st->nmat-1;k>=1;k--) {
649: inip = ini+1;
650: ini = (k*(k-1))/2;
651: coeffs[ini] = 1.0;
652: for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
653: }
654: PetscFunctionReturn(PETSC_SUCCESS);
655: }
657: /*@
658: STPostSolve - Optional post-solve phase, intended for any actions that must
659: be performed on the `ST` object after the eigensolver has finished.
661: Collective
663: Input Parameter:
664: . st - the spectral transformation context
666: Level: developer
668: .seealso: [](ch:st), `EPSSolve()`
669: @*/
670: PetscErrorCode STPostSolve(ST st)
671: {
672: PetscFunctionBegin;
675: PetscTryTypeMethod(st,postsolve);
676: PetscFunctionReturn(PETSC_SUCCESS);
677: }
679: /*@
680: STBackTransform - Back-transformation phase, intended for
681: spectral transformations which require to transform the computed
682: eigenvalues back to the original eigenvalue problem.
684: Not Collective
686: Input Parameters:
687: + st - the spectral transformation context
688: . n - number of eigenvalues
689: . eigr - real part of a computed eigenvalues
690: - eigi - imaginary part of a computed eigenvalues
692: Level: developer
694: .seealso: [](ch:st), `STIsInjective()`
695: @*/
696: PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar eigr[],PetscScalar eigi[])
697: {
698: PetscFunctionBegin;
701: PetscTryTypeMethod(st,backtransform,n,eigr,eigi);
702: PetscFunctionReturn(PETSC_SUCCESS);
703: }
705: /*@
706: STIsInjective - Returns whether this spectral transformation is injective or not
707: (that is, if it corresponds to a one-to-one mapping). If not, then it
708: does not make sense to call `STBackTransform()`.
710: Not Collective
712: Input Parameter:
713: . st - the spectral transformation context
715: Output Parameter:
716: . is - the answer
718: Note:
719: In case of non-injective transformations such as `STFILTER`, the eigenvalues
720: of the original eigenproblem are computed via the Rayleigh quotient
721: $\rho(A,x) = \frac{x^*Ax}{x^*x}$ for each computed eigenvector $x$.
723: Level: developer
725: .seealso: [](ch:st), `STBackTransform()`
726: @*/
727: PetscErrorCode STIsInjective(ST st,PetscBool* is)
728: {
729: PetscBool shell;
731: PetscFunctionBegin;
734: PetscAssertPointer(is,2);
736: PetscCall(PetscObjectTypeCompare((PetscObject)st,STSHELL,&shell));
737: if (shell) PetscCall(STIsInjective_Shell(st,is));
738: else *is = st->ops->backtransform? PETSC_TRUE: PETSC_FALSE;
739: PetscFunctionReturn(PETSC_SUCCESS);
740: }
742: /*@
743: STMatSetUp - Build the preconditioner matrix used in `STMatSolve()`.
745: Collective
747: Input Parameters:
748: + st - the spectral transformation context
749: . sigma - the shift
750: - coeffs - the coefficients (may be `NULL`)
752: Note:
753: This function is not intended to be called by end users, but by SLEPc
754: solvers that use `ST`. It builds the internal matrix for the preconditioner as
755: $$
756: P=\begin{cases}
757: \sum_{i=0}^{\mathtt{nmat}-1}\mathtt{coeffs[i]}\,\sigma^i A_i, & \text{if coefficients given}\\
758: \sum_{i=0}^{\mathtt{nmat}-1}\sigma^i A_i, & \text{otherwise}
759: \end{cases}
760: $$
761: then calls `KSPSetUp()`.
763: Level: developer
765: .seealso: [](ch:st), `STMatSolve()`
766: @*/
767: PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar coeffs[])
768: {
769: PetscFunctionBegin;
772: STCheckMatrices(st,1);
774: PetscCall(PetscLogEventBegin(ST_MatSetUp,st,0,0,0));
775: PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_FALSE,&st->P));
776: if (st->Psplit) PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
777: PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
778: PetscCall(KSPSetUp(st->ksp));
779: PetscCall(PetscLogEventEnd(ST_MatSetUp,st,0,0,0));
780: PetscFunctionReturn(PETSC_SUCCESS);
781: }
783: /*@
784: STSetWorkVecs - Sets a number of work vectors into the `ST` object.
786: Collective
788: Input Parameters:
789: + st - the spectral transformation context
790: - nw - number of work vectors to allocate
792: Developer Notes:
793: This is `SLEPC_EXTERN` because it may be required by shell `ST`s.
795: Level: developer
797: .seealso: [](ch:st), `STMatCreateVecs()`
798: @*/
799: PetscErrorCode STSetWorkVecs(ST st,PetscInt nw)
800: {
801: PetscInt i;
803: PetscFunctionBegin;
806: PetscCheck(nw>0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"nw must be > 0: nw = %" PetscInt_FMT,nw);
807: if (st->nwork < nw) {
808: PetscCall(VecDestroyVecs(st->nwork,&st->work));
809: st->nwork = nw;
810: PetscCall(PetscMalloc1(nw,&st->work));
811: for (i=0;i<nw;i++) PetscCall(STMatCreateVecs(st,&st->work[i],NULL));
812: }
813: PetscFunctionReturn(PETSC_SUCCESS);
814: }