Actual source code: stsolve.c
slepc-3.19.0 2023-03-31
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 (A - sB)^-1 B 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: 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 (A - sB)^-1 B in the case of the shift-and-invert transformation
79: 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: 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 B^T(A - sB)^-T in the case of the shift-and-invert transformation
121: 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: 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: /*@
154: STApplyHermitianTranspose - Applies the hermitian-transpose of the operator
155: to a vector, for instance B^H(A - sB)^-H in the case of the shift-and-invert
156: transformation and generalized eigenproblem.
158: Collective
160: Input Parameters:
161: + st - the spectral transformation context
162: - x - input vector
164: Output Parameter:
165: . y - output vector
167: Note:
168: Currently implemented via STApplyTranspose() with appropriate conjugation.
170: Level: developer
172: .seealso: STApply(), STApplyTranspose()
173: @*/
174: PetscErrorCode STApplyHermitianTranspose(ST st,Vec x,Vec y)
175: {
176: Mat Op;
178: PetscFunctionBegin;
183: STCheckMatrices(st,1);
184: PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
185: PetscCall(VecSetErrorIfLocked(y,3));
186: PetscCall(STGetOperator_Private(st,&Op));
187: PetscCall(MatMultHermitianTranspose(Op,x,y));
188: PetscFunctionReturn(PETSC_SUCCESS);
189: }
191: /*@
192: STGetBilinearForm - Returns the matrix used in the bilinear form with a
193: generalized problem with semi-definite B.
195: Logically Collective
197: Input Parameters:
198: . st - the spectral transformation context
200: Output Parameter:
201: . B - output matrix
203: Notes:
204: The output matrix B must be destroyed after use. It will be NULL in
205: case of standard eigenproblems.
207: Level: developer
209: .seealso: BVSetMatrix()
210: @*/
211: PetscErrorCode STGetBilinearForm(ST st,Mat *B)
212: {
213: PetscFunctionBegin;
217: STCheckMatrices(st,1);
218: PetscUseTypeMethod(st,getbilinearform,B);
219: PetscFunctionReturn(PETSC_SUCCESS);
220: }
222: PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
223: {
224: PetscFunctionBegin;
225: if (st->nmat==1) *B = NULL;
226: else {
227: *B = st->A[1];
228: PetscCall(PetscObjectReference((PetscObject)*B));
229: }
230: PetscFunctionReturn(PETSC_SUCCESS);
231: }
233: static PetscErrorCode MatMult_STOperator(Mat Op,Vec x,Vec y)
234: {
235: ST st;
237: PetscFunctionBegin;
238: PetscCall(MatShellGetContext(Op,&st));
239: PetscCall(STSetUp(st));
240: PetscCall(PetscLogEventBegin(ST_Apply,st,x,y,0));
241: if (st->D) { /* with balancing */
242: PetscCall(VecPointwiseDivide(st->wb,x,st->D));
243: PetscUseTypeMethod(st,apply,st->wb,y);
244: PetscCall(VecPointwiseMult(y,y,st->D));
245: } else PetscUseTypeMethod(st,apply,x,y);
246: PetscCall(PetscLogEventEnd(ST_Apply,st,x,y,0));
247: PetscFunctionReturn(PETSC_SUCCESS);
248: }
250: static PetscErrorCode MatMultTranspose_STOperator(Mat Op,Vec x,Vec y)
251: {
252: ST st;
254: PetscFunctionBegin;
255: PetscCall(MatShellGetContext(Op,&st));
256: PetscCall(STSetUp(st));
257: PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
258: if (st->D) { /* with balancing */
259: PetscCall(VecPointwiseMult(st->wb,x,st->D));
260: PetscUseTypeMethod(st,applytrans,st->wb,y);
261: PetscCall(VecPointwiseDivide(y,y,st->D));
262: } else PetscUseTypeMethod(st,applytrans,x,y);
263: PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
264: PetscFunctionReturn(PETSC_SUCCESS);
265: }
267: #if defined(PETSC_USE_COMPLEX)
268: static PetscErrorCode MatMultHermitianTranspose_STOperator(Mat Op,Vec x,Vec y)
269: {
270: ST st;
272: PetscFunctionBegin;
273: PetscCall(MatShellGetContext(Op,&st));
274: PetscCall(STSetUp(st));
275: PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
276: if (!st->wht) PetscCall(MatCreateVecs(st->A[0],&st->wht,NULL));
277: PetscCall(VecCopy(x,st->wht));
278: PetscCall(VecConjugate(st->wht));
279: if (st->D) { /* with balancing */
280: PetscCall(VecPointwiseMult(st->wb,st->wht,st->D));
281: PetscUseTypeMethod(st,applytrans,st->wb,y);
282: PetscCall(VecPointwiseDivide(y,y,st->D));
283: } else PetscUseTypeMethod(st,applytrans,st->wht,y);
284: PetscCall(VecConjugate(y));
285: PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
286: PetscFunctionReturn(PETSC_SUCCESS);
287: }
288: #endif
290: static PetscErrorCode MatMatMult_STOperator(Mat Op,Mat B,Mat C,void *ctx)
291: {
292: ST st;
294: PetscFunctionBegin;
295: PetscCall(MatShellGetContext(Op,&st));
296: PetscCall(STSetUp(st));
297: PetscCall(PetscLogEventBegin(ST_Apply,st,B,C,0));
298: PetscCall(STApplyMat_Generic(st,B,C));
299: PetscCall(PetscLogEventEnd(ST_Apply,st,B,C,0));
300: PetscFunctionReturn(PETSC_SUCCESS);
301: }
303: PetscErrorCode STGetOperator_Private(ST st,Mat *Op)
304: {
305: PetscInt m,n,M,N;
306: Vec v;
307: VecType vtype;
309: PetscFunctionBegin;
310: if (!st->Op) {
311: if (Op) *Op = NULL;
312: /* create the shell matrix */
313: PetscCall(MatGetLocalSize(st->A[0],&m,&n));
314: PetscCall(MatGetSize(st->A[0],&M,&N));
315: PetscCall(MatCreateShell(PetscObjectComm((PetscObject)st),m,n,M,N,st,&st->Op));
316: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT,(void(*)(void))MatMult_STOperator));
317: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
318: #if defined(PETSC_USE_COMPLEX)
319: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultHermitianTranspose_STOperator));
320: #else
321: PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
322: #endif
323: if (!st->D && st->ops->apply==STApply_Generic) {
324: PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSE,MATDENSE));
325: PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSECUDA,MATDENSECUDA));
326: }
327: /* make sure the shell matrix generates a vector of the same type as the problem matrices */
328: PetscCall(MatCreateVecs(st->A[0],&v,NULL));
329: PetscCall(VecGetType(v,&vtype));
330: PetscCall(MatShellSetVecType(st->Op,vtype));
331: PetscCall(VecDestroy(&v));
332: /* build the operator matrices */
333: PetscCall(STComputeOperator(st));
334: }
335: if (Op) *Op = st->Op;
336: PetscFunctionReturn(PETSC_SUCCESS);
337: }
339: /*@
340: STGetOperator - Returns a shell matrix that represents the operator of the
341: spectral transformation.
343: Collective
345: Input Parameter:
346: . st - the spectral transformation context
348: Output Parameter:
349: . Op - operator matrix
351: Notes:
352: The operator is defined in linear eigenproblems only, not in polynomial ones,
353: so the call will fail if more than 2 matrices were passed in STSetMatrices().
355: The returned shell matrix is essentially a wrapper to the STApply() and
356: STApplyTranspose() operations. The operator can often be expressed as
358: $ Op = D*inv(K)*M*inv(D)
360: where D is the balancing matrix, and M and K are two matrices corresponding
361: to the numerator and denominator for spectral transformations that represent
362: a rational matrix function. In the case of STSHELL, the inner part inv(K)*M
363: is replaced by the user-provided operation from STShellSetApply().
365: The preconditioner matrix K typically depends on the value of the shift, and
366: its inverse is handled via an internal KSP object. Normal usage does not
367: require explicitly calling STGetOperator(), but it can be used to force the
368: creation of K and M, and then K is passed to the KSP. This is useful for
369: setting options associated with the PCFactor (to set MUMPS options, for instance).
371: The returned matrix must NOT be destroyed by the user. Instead, when no
372: longer needed it must be returned with STRestoreOperator(). In particular,
373: this is required before modifying the ST matrices or the shift.
375: A NULL pointer can be passed in Op in case the matrix is not required but we
376: want to force its creation. In this case, STRestoreOperator() should not be
377: called.
379: Level: advanced
381: .seealso: STApply(), STApplyTranspose(), STSetBalanceMatrix(), STShellSetApply(),
382: STGetKSP(), STSetShift(), STRestoreOperator(), STSetMatrices()
383: @*/
384: PetscErrorCode STGetOperator(ST st,Mat *Op)
385: {
386: PetscFunctionBegin;
389: STCheckMatrices(st,1);
390: STCheckNotSeized(st,1);
391: PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"The operator is not defined in polynomial eigenproblems");
392: PetscCall(STGetOperator_Private(st,Op));
393: if (Op) st->opseized = PETSC_TRUE;
394: PetscFunctionReturn(PETSC_SUCCESS);
395: }
397: /*@
398: STRestoreOperator - Restore the previously seized operator matrix.
400: Logically Collective
402: Input Parameters:
403: + st - the spectral transformation context
404: - Op - operator matrix
406: Notes:
407: The arguments must match the corresponding call to STGetOperator().
409: Level: advanced
411: .seealso: STGetOperator()
412: @*/
413: PetscErrorCode STRestoreOperator(ST st,Mat *Op)
414: {
415: PetscFunctionBegin;
419: PetscCheck(st->opseized,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must be called after STGetOperator()");
420: *Op = NULL;
421: st->opseized = PETSC_FALSE;
422: PetscFunctionReturn(PETSC_SUCCESS);
423: }
425: /*
426: STComputeOperator - Computes the matrices that constitute the operator
428: Op = D*inv(K)*M*inv(D).
430: K and M are computed here (D is user-provided) from the system matrices
431: and the shift sigma (whenever these are changed, this function recomputes
432: K and M). This is used only in linear eigenproblems (nmat<3).
434: K is the "preconditioner matrix": it is the denominator in rational operators,
435: e.g. (A-sigma*B) in shift-and-invert. In non-rational transformations such
436: as STFILTER, K=NULL which means identity. After computing K, it is passed to
437: the internal KSP object via KSPSetOperators.
439: M is the numerator in rational operators. If unused it is set to NULL (e.g.
440: in STPRECOND).
442: STSHELL does not compute anything here, but sets the flag as if it was ready.
443: */
444: PetscErrorCode STComputeOperator(ST st)
445: {
446: PC pc;
448: PetscFunctionBegin;
451: if (!st->opready && st->ops->computeoperator) {
452: PetscCall(PetscInfo(st,"Building the operator matrices\n"));
453: STCheckMatrices(st,1);
454: if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
455: PetscCall(PetscLogEventBegin(ST_ComputeOperator,st,0,0,0));
456: PetscUseTypeMethod(st,computeoperator);
457: PetscCall(PetscLogEventEnd(ST_ComputeOperator,st,0,0,0));
458: if (st->usesksp) {
459: if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
460: if (st->P) {
461: PetscCall(STSetDefaultKSP(st));
462: PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
463: } else {
464: /* STPRECOND defaults to PCNONE if st->P is empty */
465: PetscCall(KSPGetPC(st->ksp,&pc));
466: PetscCall(PCSetType(pc,PCNONE));
467: }
468: }
469: }
470: st->opready = PETSC_TRUE;
471: PetscFunctionReturn(PETSC_SUCCESS);
472: }
474: /*@
475: STSetUp - Prepares for the use of a spectral transformation.
477: Collective
479: Input Parameter:
480: . st - the spectral transformation context
482: Level: advanced
484: .seealso: STCreate(), STApply(), STDestroy()
485: @*/
486: PetscErrorCode STSetUp(ST st)
487: {
488: PetscInt i,n,k;
490: PetscFunctionBegin;
493: STCheckMatrices(st,1);
494: switch (st->state) {
495: case ST_STATE_INITIAL:
496: PetscCall(PetscInfo(st,"Setting up new ST\n"));
497: if (!((PetscObject)st)->type_name) PetscCall(STSetType(st,STSHIFT));
498: break;
499: case ST_STATE_SETUP:
500: PetscFunctionReturn(PETSC_SUCCESS);
501: case ST_STATE_UPDATED:
502: PetscCall(PetscInfo(st,"Setting up updated ST\n"));
503: break;
504: }
505: PetscCall(PetscLogEventBegin(ST_SetUp,st,0,0,0));
506: if (st->state!=ST_STATE_UPDATED) {
507: if (!(st->nmat<3 && st->opready)) {
508: if (st->T) {
509: for (i=0;i<PetscMax(2,st->nmat);i++) PetscCall(MatDestroy(&st->T[i]));
510: }
511: PetscCall(MatDestroy(&st->P));
512: }
513: }
514: if (st->D) {
515: PetscCall(MatGetLocalSize(st->A[0],NULL,&n));
516: PetscCall(VecGetLocalSize(st->D,&k));
517: PetscCheck(n==k,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %" PetscInt_FMT " (should be %" PetscInt_FMT ")",k,n);
518: if (!st->wb) PetscCall(VecDuplicate(st->D,&st->wb));
519: }
520: if (st->nmat<3 && st->transform) PetscCall(STComputeOperator(st));
521: else {
522: if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
523: }
524: PetscTryTypeMethod(st,setup);
525: st->state = ST_STATE_SETUP;
526: PetscCall(PetscLogEventEnd(ST_SetUp,st,0,0,0));
527: PetscFunctionReturn(PETSC_SUCCESS);
528: }
530: /*
531: Computes coefficients for the transformed polynomial,
532: and stores the result in argument S.
534: alpha - value of the parameter of the transformed polynomial
535: beta - value of the previous shift (only used in inplace mode)
536: k - index of first matrix included in the computation
537: coeffs - coefficients of the expansion
538: initial - true if this is the first time
539: precond - whether the preconditioner matrix must be computed
540: */
541: PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,PetscBool precond,Mat *S)
542: {
543: PetscInt *matIdx=NULL,nmat,i,ini=-1;
544: PetscScalar t=1.0,ta,gamma;
545: PetscBool nz=PETSC_FALSE;
546: Mat *A=precond?st->Psplit:st->A;
547: MatStructure str=precond?st->strp:st->str;
549: PetscFunctionBegin;
550: nmat = st->nmat-k;
551: switch (st->matmode) {
552: case ST_MATMODE_INPLACE:
553: PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
554: PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for split preconditioner");
555: if (initial) {
556: PetscCall(PetscObjectReference((PetscObject)A[0]));
557: *S = A[0];
558: gamma = alpha;
559: } else gamma = alpha-beta;
560: if (gamma != 0.0) {
561: if (st->nmat>1) PetscCall(MatAXPY(*S,gamma,A[1],str));
562: else PetscCall(MatShift(*S,gamma));
563: }
564: break;
565: case ST_MATMODE_SHELL:
566: PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_SHELL not supported for split preconditioner");
567: if (initial) {
568: if (st->nmat>2) {
569: PetscCall(PetscMalloc1(nmat,&matIdx));
570: for (i=0;i<nmat;i++) matIdx[i] = k+i;
571: }
572: PetscCall(STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S));
573: if (st->nmat>2) PetscCall(PetscFree(matIdx));
574: } else PetscCall(STMatShellShift(*S,alpha));
575: break;
576: case ST_MATMODE_COPY:
577: if (coeffs) {
578: for (i=0;i<nmat && ini==-1;i++) {
579: if (coeffs[i]!=0.0) ini = i;
580: else t *= alpha;
581: }
582: if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
583: for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
584: } else { nz = PETSC_TRUE; ini = 0; }
585: if ((alpha == 0.0 || !nz) && t==1.0) {
586: PetscCall(PetscObjectReference((PetscObject)A[k+ini]));
587: PetscCall(MatDestroy(S));
588: *S = A[k+ini];
589: } else {
590: if (*S && *S!=A[k+ini]) {
591: PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
592: PetscCall(MatCopy(A[k+ini],*S,DIFFERENT_NONZERO_PATTERN));
593: } else {
594: PetscCall(MatDestroy(S));
595: PetscCall(MatDuplicate(A[k+ini],MAT_COPY_VALUES,S));
596: PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
597: }
598: if (coeffs && coeffs[ini]!=1.0) PetscCall(MatScale(*S,coeffs[ini]));
599: for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
600: t *= alpha;
601: ta = t;
602: if (coeffs) ta *= coeffs[i-k];
603: if (ta!=0.0) {
604: if (st->nmat>1) PetscCall(MatAXPY(*S,ta,A[i],str));
605: else PetscCall(MatShift(*S,ta));
606: }
607: }
608: }
609: }
610: PetscCall(MatSetOption(*S,MAT_SYMMETRIC,st->asymm));
611: PetscCall(MatSetOption(*S,MAT_HERMITIAN,(PetscImaginaryPart(st->sigma)==0.0)?st->aherm:PETSC_FALSE));
612: PetscFunctionReturn(PETSC_SUCCESS);
613: }
615: /*
616: Computes the values of the coefficients required by STMatMAXPY_Private
617: for the case of monomial basis.
618: */
619: PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
620: {
621: PetscInt k,i,ini,inip;
623: PetscFunctionBegin;
624: /* Compute binomial coefficients */
625: ini = (st->nmat*(st->nmat-1))/2;
626: for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
627: for (k=st->nmat-1;k>=1;k--) {
628: inip = ini+1;
629: ini = (k*(k-1))/2;
630: coeffs[ini] = 1.0;
631: for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
632: }
633: PetscFunctionReturn(PETSC_SUCCESS);
634: }
636: /*@
637: STPostSolve - Optional post-solve phase, intended for any actions that must
638: be performed on the ST object after the eigensolver has finished.
640: Collective
642: Input Parameters:
643: . st - the spectral transformation context
645: Level: developer
647: .seealso: EPSSolve()
648: @*/
649: PetscErrorCode STPostSolve(ST st)
650: {
651: PetscFunctionBegin;
654: PetscTryTypeMethod(st,postsolve);
655: PetscFunctionReturn(PETSC_SUCCESS);
656: }
658: /*@
659: STBackTransform - Back-transformation phase, intended for
660: spectral transformations which require to transform the computed
661: eigenvalues back to the original eigenvalue problem.
663: Not Collective
665: Input Parameters:
666: + st - the spectral transformation context
667: . n - number of eigenvalues
668: . eigr - real part of a computed eigenvalues
669: - eigi - imaginary part of a computed eigenvalues
671: Level: developer
673: .seealso: STIsInjective()
674: @*/
675: PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar* eigr,PetscScalar* eigi)
676: {
677: PetscFunctionBegin;
680: PetscTryTypeMethod(st,backtransform,n,eigr,eigi);
681: PetscFunctionReturn(PETSC_SUCCESS);
682: }
684: /*@
685: STIsInjective - Ask if this spectral transformation is injective or not
686: (that is, if it corresponds to a one-to-one mapping). If not, then it
687: does not make sense to call STBackTransform().
689: Not Collective
691: Input Parameter:
692: . st - the spectral transformation context
694: Output Parameter:
695: . is - the answer
697: Level: developer
699: .seealso: STBackTransform()
700: @*/
701: PetscErrorCode STIsInjective(ST st,PetscBool* is)
702: {
703: PetscBool shell;
705: PetscFunctionBegin;
710: PetscCall(PetscObjectTypeCompare((PetscObject)st,STSHELL,&shell));
711: if (shell) PetscCall(STIsInjective_Shell(st,is));
712: else *is = st->ops->backtransform? PETSC_TRUE: PETSC_FALSE;
713: PetscFunctionReturn(PETSC_SUCCESS);
714: }
716: /*@
717: STMatSetUp - Build the preconditioner matrix used in STMatSolve().
719: Collective
721: Input Parameters:
722: + st - the spectral transformation context
723: . sigma - the shift
724: - coeffs - the coefficients (may be NULL)
726: Note:
727: This function is not intended to be called by end users, but by SLEPc
728: solvers that use ST. It builds matrix st->P as follows, then calls KSPSetUp().
729: .vb
730: If (coeffs) st->P = Sum_{i=0..nmat-1} coeffs[i]*sigma^i*A_i
731: else st->P = Sum_{i=0..nmat-1} sigma^i*A_i
732: .ve
734: Level: developer
736: .seealso: STMatSolve()
737: @*/
738: PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar *coeffs)
739: {
740: PetscFunctionBegin;
743: STCheckMatrices(st,1);
745: PetscCall(PetscLogEventBegin(ST_MatSetUp,st,0,0,0));
746: PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_FALSE,&st->P));
747: if (st->Psplit) PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
748: PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
749: PetscCall(KSPSetUp(st->ksp));
750: PetscCall(PetscLogEventEnd(ST_MatSetUp,st,0,0,0));
751: PetscFunctionReturn(PETSC_SUCCESS);
752: }
754: /*@
755: STSetWorkVecs - Sets a number of work vectors into the ST object.
757: Collective
759: Input Parameters:
760: + st - the spectral transformation context
761: - nw - number of work vectors to allocate
763: Developer Notes:
764: This is SLEPC_EXTERN because it may be required by shell STs.
766: Level: developer
768: .seealso: STMatCreateVecs()
769: @*/
770: PetscErrorCode STSetWorkVecs(ST st,PetscInt nw)
771: {
772: PetscInt i;
774: PetscFunctionBegin;
777: PetscCheck(nw>0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"nw must be > 0: nw = %" PetscInt_FMT,nw);
778: if (st->nwork < nw) {
779: PetscCall(VecDestroyVecs(st->nwork,&st->work));
780: st->nwork = nw;
781: PetscCall(PetscMalloc1(nw,&st->work));
782: for (i=0;i<nw;i++) PetscCall(STMatCreateVecs(st,&st->work[i],NULL));
783: }
784: PetscFunctionReturn(PETSC_SUCCESS);
785: }