1: /*
2: Implements the ST class for preconditioned eigenvalue methods.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
10: SLEPc is free software: you can redistribute it and/or modify it under the
11: terms of version 3 of the GNU Lesser General Public License as published by
12: the Free Software Foundation.
14: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
15: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17: more details.
19: You should have received a copy of the GNU Lesser General Public License
20: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
21: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22: */
24: #include <slepc/private/stimpl.h> /*I "slepcst.h" I*/
26: typedef struct {
27: PetscBool setmat;
28: } ST_PRECOND;
32: static PetscErrorCode STSetDefaultPrecond(ST st) 33: {
35: PC pc;
36: PCType pctype;
37: Mat P;
38: PetscBool t0,t1;
39: KSP ksp;
42: STGetKSP(st,&ksp);
43: KSPGetPC(ksp,&pc);
44: PetscObjectGetType((PetscObject)pc,&pctype);
45: STPrecondGetMatForPC(st,&P);
46: if (!pctype && st->A && st->A[0]) {
47: if (P || st->shift_matrix == ST_MATMODE_SHELL) {
48: PCSetType(pc,PCJACOBI);
49: } else {
50: MatHasOperation(st->A[0],MATOP_DUPLICATE,&t0);
51: if (st->nmat>1) {
52: MatHasOperation(st->A[0],MATOP_AXPY,&t1);
53: } else t1 = PETSC_TRUE;
54: PCSetType(pc,(t0 && t1)?PCJACOBI:PCNONE);
55: }
56: }
57: return(0);
58: }
62: PetscErrorCode STSetFromOptions_Precond(PetscOptionItems *PetscOptionsObject,ST st) 63: {
67: STSetDefaultPrecond(st);
68: return(0);
69: }
73: PetscErrorCode STSetUp_Precond(ST st) 74: {
75: Mat P;
76: PC pc;
77: PetscBool t0,setmat,destroyP=PETSC_FALSE,builtP;
81: /* if the user did not set the shift, use the target value */
82: if (!st->sigma_set) st->sigma = st->defsigma;
84: /* If either pc is none and no matrix has to be set, or pc is shell , exit */
85: STSetDefaultPrecond(st);
86: if (!st->ksp) { STGetKSP(st,&st->ksp); }
87: KSPGetPC(st->ksp,&pc);
88: PetscObjectTypeCompare((PetscObject)pc,PCSHELL,&t0);
89: if (t0) return(0);
90: PetscObjectTypeCompare((PetscObject)pc,PCNONE,&t0);
91: STPrecondGetKSPHasMat(st,&setmat);
92: if (t0 && !setmat) return(0);
94: /* Check if a user matrix is set */
95: STPrecondGetMatForPC(st,&P);
97: /* If not, create A - shift*B */
98: if (P) {
99: builtP = PETSC_FALSE;
100: destroyP = PETSC_TRUE;
101: PetscObjectReference((PetscObject)P);
102: } else {
103: builtP = PETSC_TRUE;
105: if (!(PetscAbsScalar(st->sigma) < PETSC_MAX_REAL) && st->nmat>1) {
106: P = st->A[1];
107: destroyP = PETSC_FALSE;
108: } else if (st->sigma == 0.0) {
109: P = st->A[0];
110: destroyP = PETSC_FALSE;
111: } else if (PetscAbsScalar(st->sigma) < PETSC_MAX_REAL && st->shift_matrix != ST_MATMODE_SHELL) {
112: if (st->shift_matrix == ST_MATMODE_INPLACE) {
113: P = st->A[0];
114: destroyP = PETSC_FALSE;
115: } else {
116: MatDuplicate(st->A[0],MAT_COPY_VALUES,&P);
117: destroyP = PETSC_TRUE;
118: }
119: if (st->nmat>1) {
120: MatAXPY(P,-st->sigma,st->A[1],st->str);
121: } else {
122: MatShift(P,-st->sigma);
123: }
124: /* TODO: in case of ST_MATMODE_INPLACE should keep the Hermitian flag of st->A and restore at the end */
125: STMatSetHermitian(st,P);
126: } else builtP = PETSC_FALSE;
127: }
129: /* If P was not possible to obtain, set pc to PCNONE */
130: if (!P) {
131: PCSetType(pc,PCNONE);
133: /* If some matrix has to be set to ksp, a shell matrix is created */
134: if (setmat) {
135: STMatShellCreate(st,-st->sigma,0,NULL,NULL,&P);
136: STMatSetHermitian(st,P);
137: destroyP = PETSC_TRUE;
138: }
139: }
141: KSPSetOperators(st->ksp,setmat?P:NULL,P);
143: if (destroyP) {
144: MatDestroy(&P);
145: } else if (st->shift_matrix == ST_MATMODE_INPLACE && builtP) {
146: if (st->sigma != 0.0 && PetscAbsScalar(st->sigma) < PETSC_MAX_REAL) {
147: if (st->nmat>1) {
148: MatAXPY(st->A[0],st->sigma,st->A[1],st->str);
149: } else {
150: MatShift(st->A[0],st->sigma);
151: }
152: }
153: }
154: return(0);
155: }
159: PetscErrorCode STSetShift_Precond(ST st,PetscScalar newshift)160: {
164: /* Nothing to be done if STSetUp has not been called yet */
165: if (!st->state) return(0);
166: st->sigma = newshift;
167: if (st->shift_matrix != ST_MATMODE_SHELL) {
168: STSetUp_Precond(st);
169: }
170: return(0);
171: }
175: static PetscErrorCode STPrecondGetMatForPC_Precond(ST st,Mat *mat)176: {
178: PC pc;
179: PetscBool flag;
182: if (!st->ksp) { STGetKSP(st,&st->ksp); }
183: KSPGetPC(st->ksp,&pc);
184: PCGetOperatorsSet(pc,NULL,&flag);
185: if (flag) {
186: PCGetOperators(pc,NULL,mat);
187: } else *mat = NULL;
188: return(0);
189: }
193: /*@
194: STPrecondGetMatForPC - Returns the matrix previously set by STPrecondSetMatForPC().
196: Not Collective, but the Mat is shared by all processors that share the ST198: Input Parameter:
199: . st - the spectral transformation context
201: Output Parameter:
202: . mat - the matrix that will be used in constructing the preconditioner or
203: NULL if no matrix was set by STPrecondSetMatForPC().
205: Level: advanced
207: .seealso: STPrecondSetMatForPC()
208: @*/
209: PetscErrorCode STPrecondGetMatForPC(ST st,Mat *mat)210: {
216: PetscUseMethod(st,"STPrecondGetMatForPC_C",(ST,Mat*),(st,mat));
217: return(0);
218: }
222: static PetscErrorCode STPrecondSetMatForPC_Precond(ST st,Mat mat)223: {
224: PC pc;
225: Mat A;
226: PetscBool flag;
230: if (!st->ksp) { STGetKSP(st,&st->ksp); }
231: KSPGetPC(st->ksp,&pc);
232: /* Yes, all these lines are needed to safely set mat as the preconditioner
233: matrix in pc */
234: PCGetOperatorsSet(pc,&flag,NULL);
235: if (flag) {
236: PCGetOperators(pc,&A,NULL);
237: PetscObjectReference((PetscObject)A);
238: } else A = NULL;
239: PetscObjectReference((PetscObject)mat);
240: PCSetOperators(pc,A,mat);
241: MatDestroy(&A);
242: MatDestroy(&mat);
243: STPrecondSetKSPHasMat(st,PETSC_TRUE);
244: return(0);
245: }
249: /*@
250: STPrecondSetMatForPC - Sets the matrix that must be used to build the preconditioner.
252: Logically Collective on ST and Mat
254: Input Parameter:
255: + st - the spectral transformation context
256: - mat - the matrix that will be used in constructing the preconditioner
258: Level: advanced
260: Notes:
261: This matrix will be passed to the KSP object (via KSPSetOperators) as
262: the matrix to be used when constructing the preconditioner.
263: If no matrix is set or mat is set to NULL, A - sigma*B will
264: be used to build the preconditioner, being sigma the value set by STSetShift().
266: .seealso: STPrecondSetMatForPC(), STSetShift()
267: @*/
268: PetscErrorCode STPrecondSetMatForPC(ST st,Mat mat)269: {
276: PetscTryMethod(st,"STPrecondSetMatForPC_C",(ST,Mat),(st,mat));
277: return(0);
278: }
282: static PetscErrorCode STPrecondSetKSPHasMat_Precond(ST st,PetscBool setmat)283: {
284: ST_PRECOND *data = (ST_PRECOND*)st->data;
287: data->setmat = setmat;
288: return(0);
289: }
293: /*@
294: STPrecondSetKSPHasMat - Sets a flag indicating that during STSetUp the coefficient
295: matrix of the KSP linear system (A) must be set to be the same matrix as the
296: preconditioner (P).
298: Collective on ST300: Input Parameter:
301: + st - the spectral transformation context
302: - setmat - the flag
304: Notes:
305: In most cases, the preconditioner matrix is used only in the PC object, but
306: in external solvers this matrix must be provided also as the A-matrix in
307: the KSP object.
309: Level: developer
311: .seealso: STPrecondGetKSPHasMat(), STSetShift()
312: @*/
313: PetscErrorCode STPrecondSetKSPHasMat(ST st,PetscBool setmat)314: {
320: PetscTryMethod(st,"STPrecondSetKSPHasMat_C",(ST,PetscBool),(st,setmat));
321: return(0);
322: }
326: static PetscErrorCode STPrecondGetKSPHasMat_Precond(ST st,PetscBool *setmat)327: {
328: ST_PRECOND *data = (ST_PRECOND*)st->data;
331: *setmat = data->setmat;
332: return(0);
333: }
337: /*@
338: STPrecondGetKSPHasMat - Returns the flag indicating if the coefficient
339: matrix of the KSP linear system (A) is set to be the same matrix as the
340: preconditioner (P).
342: Not Collective
344: Input Parameter:
345: . st - the spectral transformation context
347: Output Parameter:
348: . setmat - the flag
350: Level: developer
352: .seealso: STPrecondSetKSPHasMat(), STSetShift()
353: @*/
354: PetscErrorCode STPrecondGetKSPHasMat(ST st,PetscBool *setmat)355: {
361: PetscUseMethod(st,"STPrecondGetKSPHasMat_C",(ST,PetscBool*),(st,setmat));
362: return(0);
363: }
367: PetscErrorCode STDestroy_Precond(ST st)368: {
372: PetscFree(st->data);
373: PetscObjectComposeFunction((PetscObject)st,"STPrecondGetMatForPC_C",NULL);
374: PetscObjectComposeFunction((PetscObject)st,"STPrecondSetMatForPC_C",NULL);
375: PetscObjectComposeFunction((PetscObject)st,"STPrecondGetKSPHasMat_C",NULL);
376: PetscObjectComposeFunction((PetscObject)st,"STPrecondSetKSPHasMat_C",NULL);
377: return(0);
378: }
382: PETSC_EXTERN PetscErrorCode STCreate_Precond(ST st)383: {
385: ST_PRECOND *ctx;
388: PetscNewLog(st,&ctx);
389: st->data = (void*)ctx;
391: st->ops->getbilinearform = STGetBilinearForm_Default;
392: st->ops->setup = STSetUp_Precond;
393: st->ops->setshift = STSetShift_Precond;
394: st->ops->destroy = STDestroy_Precond;
395: st->ops->setfromoptions = STSetFromOptions_Precond;
397: PetscObjectComposeFunction((PetscObject)st,"STPrecondGetMatForPC_C",STPrecondGetMatForPC_Precond);
398: PetscObjectComposeFunction((PetscObject)st,"STPrecondSetMatForPC_C",STPrecondSetMatForPC_Precond);
399: PetscObjectComposeFunction((PetscObject)st,"STPrecondGetKSPHasMat_C",STPrecondGetKSPHasMat_Precond);
400: PetscObjectComposeFunction((PetscObject)st,"STPrecondSetKSPHasMat_C",STPrecondSetKSPHasMat_Precond);
402: STPrecondSetKSPHasMat_Precond(st,PETSC_TRUE);
403: return(0);
404: }