xref: /petsc/src/ksp/pc/impls/eisens/eisen.c (revision a9e2c90a5e8c53bd20246e894f8ac58374066acf)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith    Defines a  Eisenstat trick SSOR  preconditioner. This uses about
44b9ad928SBarry Smith  %50 of the usual amount of floating point ops used for SSOR + Krylov
54b9ad928SBarry Smith  method. But it requires actually solving the preconditioned problem
64b9ad928SBarry Smith  with both left and right preconditioning.
74b9ad928SBarry Smith */
8af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
94b9ad928SBarry Smith 
104b9ad928SBarry Smith typedef struct {
114b9ad928SBarry Smith   Mat       shell, A;
1278c391d7SBarry Smith   Vec       b[2], diag; /* temporary storage for true right hand side */
134b9ad928SBarry Smith   PetscReal omega;
14ace3abfcSBarry Smith   PetscBool usediag; /* indicates preconditioner should include diagonal scaling*/
154b9ad928SBarry Smith } PC_Eisenstat;
164b9ad928SBarry Smith 
179371c9d4SSatish Balay static PetscErrorCode PCMult_Eisenstat(Mat mat, Vec b, Vec x) {
184b9ad928SBarry Smith   PC            pc;
194b9ad928SBarry Smith   PC_Eisenstat *eis;
204b9ad928SBarry Smith 
214b9ad928SBarry Smith   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(mat, &pc));
234b9ad928SBarry Smith   eis = (PC_Eisenstat *)pc->data;
249566063dSJacob Faibussowitsch   PetscCall(MatSOR(eis->A, b, eis->omega, SOR_EISENSTAT, 0.0, 1, 1, x));
254b9ad928SBarry Smith   PetscFunctionReturn(0);
264b9ad928SBarry Smith }
274b9ad928SBarry Smith 
28*a9e2c90aSJose E. Roman static PetscErrorCode PCNorm_Eisenstat(Mat mat, NormType type, PetscReal *nrm) {
29*a9e2c90aSJose E. Roman   PC            pc;
30*a9e2c90aSJose E. Roman   PC_Eisenstat *eis;
31*a9e2c90aSJose E. Roman 
32*a9e2c90aSJose E. Roman   PetscFunctionBegin;
33*a9e2c90aSJose E. Roman   PetscCall(MatShellGetContext(mat, &pc));
34*a9e2c90aSJose E. Roman   eis = (PC_Eisenstat *)pc->data;
35*a9e2c90aSJose E. Roman   PetscCall(MatNorm(eis->A, type, nrm));
36*a9e2c90aSJose E. Roman   PetscFunctionReturn(0);
37*a9e2c90aSJose E. Roman }
38*a9e2c90aSJose E. Roman 
399371c9d4SSatish Balay static PetscErrorCode PCApply_Eisenstat(PC pc, Vec x, Vec y) {
404b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
41ace3abfcSBarry Smith   PetscBool     hasop;
424b9ad928SBarry Smith 
434b9ad928SBarry Smith   PetscFunctionBegin;
4489c6957cSBarry Smith   if (eis->usediag) {
459566063dSJacob Faibussowitsch     PetscCall(MatHasOperation(pc->pmat, MATOP_MULT_DIAGONAL_BLOCK, &hasop));
4689c6957cSBarry Smith     if (hasop) {
479566063dSJacob Faibussowitsch       PetscCall(MatMultDiagonalBlock(pc->pmat, x, y));
4889c6957cSBarry Smith     } else {
499566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(y, x, eis->diag));
5089c6957cSBarry Smith     }
519566063dSJacob Faibussowitsch   } else PetscCall(VecCopy(x, y));
524b9ad928SBarry Smith   PetscFunctionReturn(0);
534b9ad928SBarry Smith }
544b9ad928SBarry Smith 
559371c9d4SSatish Balay static PetscErrorCode PCPreSolve_Eisenstat(PC pc, KSP ksp, Vec b, Vec x) {
564b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
57ace3abfcSBarry Smith   PetscBool     nonzero;
584b9ad928SBarry Smith 
594b9ad928SBarry Smith   PetscFunctionBegin;
6078c391d7SBarry Smith   if (pc->presolvedone < 2) {
6108401ef6SPierre Jolivet     PetscCheck(pc->mat == pc->pmat, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot have different mat and pmat");
624b9ad928SBarry Smith     /* swap shell matrix and true matrix */
634b9ad928SBarry Smith     eis->A  = pc->mat;
644b9ad928SBarry Smith     pc->mat = eis->shell;
654b9ad928SBarry Smith   }
664b9ad928SBarry Smith 
6778c391d7SBarry Smith   if (!eis->b[pc->presolvedone - 1]) {
689566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(b, &eis->b[pc->presolvedone - 1]));
699566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)eis->b[pc->presolvedone - 1]));
7078c391d7SBarry Smith   }
714b9ad928SBarry Smith 
724b9ad928SBarry Smith   /* if nonzero initial guess, modify x */
739566063dSJacob Faibussowitsch   PetscCall(KSPGetInitialGuessNonzero(ksp, &nonzero));
744b9ad928SBarry Smith   if (nonzero) {
759566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, eis->b[pc->presolvedone - 1]));
769566063dSJacob Faibussowitsch     PetscCall(MatSOR(eis->A, eis->b[pc->presolvedone - 1], eis->omega, SOR_APPLY_UPPER, 0.0, 1, 1, x));
774b9ad928SBarry Smith   }
784b9ad928SBarry Smith 
79121471adSBarry Smith   /* save true b, other option is to swap pointers */
809566063dSJacob Faibussowitsch   PetscCall(VecCopy(b, eis->b[pc->presolvedone - 1]));
81121471adSBarry Smith 
825c99c7daSBarry Smith   /* modify b by (L + D/omega)^{-1} */
839566063dSJacob Faibussowitsch   PetscCall(MatSOR(eis->A, eis->b[pc->presolvedone - 1], eis->omega, (MatSORType)(SOR_ZERO_INITIAL_GUESS | SOR_LOCAL_FORWARD_SWEEP), 0.0, 1, 1, b));
844b9ad928SBarry Smith   PetscFunctionReturn(0);
854b9ad928SBarry Smith }
864b9ad928SBarry Smith 
879371c9d4SSatish Balay static PetscErrorCode PCPostSolve_Eisenstat(PC pc, KSP ksp, Vec b, Vec x) {
884b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
894b9ad928SBarry Smith 
904b9ad928SBarry Smith   PetscFunctionBegin;
914b9ad928SBarry Smith   /* get back true b */
929566063dSJacob Faibussowitsch   PetscCall(VecCopy(eis->b[pc->presolvedone], b));
93121471adSBarry Smith 
94121471adSBarry Smith   /* modify x by (U + D/omega)^{-1} */
959566063dSJacob Faibussowitsch   PetscCall(VecCopy(x, eis->b[pc->presolvedone]));
969566063dSJacob Faibussowitsch   PetscCall(MatSOR(eis->A, eis->b[pc->presolvedone], eis->omega, (MatSORType)(SOR_ZERO_INITIAL_GUESS | SOR_LOCAL_BACKWARD_SWEEP), 0.0, 1, 1, x));
972fa5cd67SKarl Rupp   if (!pc->presolvedone) pc->mat = eis->A;
984b9ad928SBarry Smith   PetscFunctionReturn(0);
994b9ad928SBarry Smith }
1004b9ad928SBarry Smith 
1019371c9d4SSatish Balay static PetscErrorCode PCReset_Eisenstat(PC pc) {
1024b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
1034b9ad928SBarry Smith 
1044b9ad928SBarry Smith   PetscFunctionBegin;
1059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&eis->b[0]));
1069566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&eis->b[1]));
1079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&eis->shell));
1089566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&eis->diag));
10969d2c0f9SBarry Smith   PetscFunctionReturn(0);
11069d2c0f9SBarry Smith }
11169d2c0f9SBarry Smith 
1129371c9d4SSatish Balay static PetscErrorCode PCDestroy_Eisenstat(PC pc) {
11369d2c0f9SBarry Smith   PetscFunctionBegin;
1149566063dSJacob Faibussowitsch   PetscCall(PCReset_Eisenstat(pc));
1152e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatSetOmega_C", NULL));
1162e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatSetNoDiagonalScaling_C", NULL));
1172e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatGetOmega_C", NULL));
1182e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatGetNoDiagonalScaling_C", NULL));
1192e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", NULL));
1209566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1214b9ad928SBarry Smith   PetscFunctionReturn(0);
1224b9ad928SBarry Smith }
1234b9ad928SBarry Smith 
1249371c9d4SSatish Balay static PetscErrorCode PCSetFromOptions_Eisenstat(PC pc, PetscOptionItems *PetscOptionsObject) {
1254b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
1268afaa268SBarry Smith   PetscBool     set, flg;
1274b9ad928SBarry Smith 
1284b9ad928SBarry Smith   PetscFunctionBegin;
129d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Eisenstat SSOR options");
1309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_eisenstat_omega", "Relaxation factor 0 < omega < 2", "PCEisenstatSetOmega", eis->omega, &eis->omega, NULL));
1319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_eisenstat_no_diagonal_scaling", "Do not use standard diagonal scaling", "PCEisenstatSetNoDiagonalScaling", eis->usediag ? PETSC_FALSE : PETSC_TRUE, &flg, &set));
1321baa6e33SBarry Smith   if (set) PetscCall(PCEisenstatSetNoDiagonalScaling(pc, flg));
133d0609cedSBarry Smith   PetscOptionsHeadEnd();
1344b9ad928SBarry Smith   PetscFunctionReturn(0);
1354b9ad928SBarry Smith }
1364b9ad928SBarry Smith 
1379371c9d4SSatish Balay static PetscErrorCode PCView_Eisenstat(PC pc, PetscViewer viewer) {
1384b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
139ace3abfcSBarry Smith   PetscBool     iascii;
1404b9ad928SBarry Smith 
1414b9ad928SBarry Smith   PetscFunctionBegin;
1429566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
14332077d6dSBarry Smith   if (iascii) {
1449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  omega = %g\n", (double)eis->omega));
1454b9ad928SBarry Smith     if (eis->usediag) {
1469566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Using diagonal scaling (default)\n"));
1474b9ad928SBarry Smith     } else {
1489566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Not using diagonal scaling\n"));
1494b9ad928SBarry Smith     }
1504b9ad928SBarry Smith   }
1514b9ad928SBarry Smith   PetscFunctionReturn(0);
1524b9ad928SBarry Smith }
1534b9ad928SBarry Smith 
1549371c9d4SSatish Balay static PetscErrorCode PCSetUp_Eisenstat(PC pc) {
15513f74950SBarry Smith   PetscInt      M, N, m, n;
1564b9ad928SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
1574b9ad928SBarry Smith 
1584b9ad928SBarry Smith   PetscFunctionBegin;
1594b9ad928SBarry Smith   if (!pc->setupcalled) {
1609566063dSJacob Faibussowitsch     PetscCall(MatGetSize(pc->mat, &M, &N));
1619566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(pc->mat, &m, &n));
1629566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &eis->shell));
1639566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(eis->shell, m, n, M, N));
1649566063dSJacob Faibussowitsch     PetscCall(MatSetType(eis->shell, MATSHELL));
1659566063dSJacob Faibussowitsch     PetscCall(MatSetUp(eis->shell));
1669566063dSJacob Faibussowitsch     PetscCall(MatShellSetContext(eis->shell, pc));
1679566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)eis->shell));
1689566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(eis->shell, MATOP_MULT, (void (*)(void))PCMult_Eisenstat));
169*a9e2c90aSJose E. Roman     PetscCall(MatShellSetOperation(eis->shell, MATOP_NORM, (void (*)(void))PCNorm_Eisenstat));
1704b9ad928SBarry Smith   }
1714b9ad928SBarry Smith   if (!eis->usediag) PetscFunctionReturn(0);
1724b9ad928SBarry Smith   if (!pc->setupcalled) {
1739566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(pc->pmat, &eis->diag, NULL));
1749566063dSJacob Faibussowitsch     PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)eis->diag));
1754b9ad928SBarry Smith   }
1769566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(pc->pmat, eis->diag));
1774b9ad928SBarry Smith   PetscFunctionReturn(0);
1784b9ad928SBarry Smith }
1794b9ad928SBarry Smith 
1804b9ad928SBarry Smith /* --------------------------------------------------------------------*/
1814b9ad928SBarry Smith 
1829371c9d4SSatish Balay static PetscErrorCode PCEisenstatSetOmega_Eisenstat(PC pc, PetscReal omega) {
183c60c7ad4SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
1844b9ad928SBarry Smith 
1854b9ad928SBarry Smith   PetscFunctionBegin;
1862472a847SBarry Smith   PetscCheck(omega > 0.0 && omega < 2.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Relaxation out of range");
1874b9ad928SBarry Smith   eis->omega = omega;
1884b9ad928SBarry Smith   PetscFunctionReturn(0);
1894b9ad928SBarry Smith }
1904b9ad928SBarry Smith 
1919371c9d4SSatish Balay static PetscErrorCode PCEisenstatSetNoDiagonalScaling_Eisenstat(PC pc, PetscBool flg) {
192c60c7ad4SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
1934b9ad928SBarry Smith 
1944b9ad928SBarry Smith   PetscFunctionBegin;
195c60c7ad4SBarry Smith   eis->usediag = flg;
196c60c7ad4SBarry Smith   PetscFunctionReturn(0);
197c60c7ad4SBarry Smith }
198c60c7ad4SBarry Smith 
1999371c9d4SSatish Balay static PetscErrorCode PCEisenstatGetOmega_Eisenstat(PC pc, PetscReal *omega) {
200c60c7ad4SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
201c60c7ad4SBarry Smith 
202c60c7ad4SBarry Smith   PetscFunctionBegin;
203c60c7ad4SBarry Smith   *omega = eis->omega;
204c60c7ad4SBarry Smith   PetscFunctionReturn(0);
205c60c7ad4SBarry Smith }
206c60c7ad4SBarry Smith 
2079371c9d4SSatish Balay static PetscErrorCode PCEisenstatGetNoDiagonalScaling_Eisenstat(PC pc, PetscBool *flg) {
208c60c7ad4SBarry Smith   PC_Eisenstat *eis = (PC_Eisenstat *)pc->data;
209c60c7ad4SBarry Smith 
210c60c7ad4SBarry Smith   PetscFunctionBegin;
211c60c7ad4SBarry Smith   *flg = eis->usediag;
2124b9ad928SBarry Smith   PetscFunctionReturn(0);
2134b9ad928SBarry Smith }
2144b9ad928SBarry Smith 
2154b9ad928SBarry Smith /*@
2164b9ad928SBarry Smith    PCEisenstatSetOmega - Sets the SSOR relaxation coefficient, omega,
2174b9ad928SBarry Smith    to use with Eisenstat's trick (where omega = 1.0 by default).
2184b9ad928SBarry Smith 
219ad4df100SBarry Smith    Logically Collective on PC
2204b9ad928SBarry Smith 
2214b9ad928SBarry Smith    Input Parameters:
2224b9ad928SBarry Smith +  pc - the preconditioner context
2234b9ad928SBarry Smith -  omega - relaxation coefficient (0 < omega < 2)
2244b9ad928SBarry Smith 
2254b9ad928SBarry Smith    Options Database Key:
2264b9ad928SBarry Smith .  -pc_eisenstat_omega <omega> - Sets omega
2274b9ad928SBarry Smith 
2284b9ad928SBarry Smith    Notes:
2294b9ad928SBarry Smith    The Eisenstat trick implementation of SSOR requires about 50% of the
2304b9ad928SBarry Smith    usual amount of floating point operations used for SSOR + Krylov method;
2314b9ad928SBarry Smith    however, the preconditioned problem must be solved with both left
2324b9ad928SBarry Smith    and right preconditioning.
2334b9ad928SBarry Smith 
2344b9ad928SBarry Smith    To use SSOR without the Eisenstat trick, employ the PCSOR preconditioner,
2354b9ad928SBarry Smith    which can be chosen with the database options
2364b9ad928SBarry Smith $    -pc_type  sor  -pc_sor_symmetric
2374b9ad928SBarry Smith 
2384b9ad928SBarry Smith    Level: intermediate
2394b9ad928SBarry Smith 
240db781477SPatrick Sanan .seealso: `PCSORSetOmega()`
2414b9ad928SBarry Smith @*/
2429371c9d4SSatish Balay PetscErrorCode PCEisenstatSetOmega(PC pc, PetscReal omega) {
2434b9ad928SBarry Smith   PetscFunctionBegin;
2440700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
245c5eb9154SBarry Smith   PetscValidLogicalCollectiveReal(pc, omega, 2);
246cac4c232SBarry Smith   PetscTryMethod(pc, "PCEisenstatSetOmega_C", (PC, PetscReal), (pc, omega));
2474b9ad928SBarry Smith   PetscFunctionReturn(0);
2484b9ad928SBarry Smith }
2494b9ad928SBarry Smith 
2504b9ad928SBarry Smith /*@
251c60c7ad4SBarry Smith    PCEisenstatSetNoDiagonalScaling - Causes the Eisenstat preconditioner
2524b9ad928SBarry Smith    not to do additional diagonal preconditioning. For matrices with a constant
2534b9ad928SBarry Smith    along the diagonal, this may save a small amount of work.
2544b9ad928SBarry Smith 
255ad4df100SBarry Smith    Logically Collective on PC
2564b9ad928SBarry Smith 
257c60c7ad4SBarry Smith    Input Parameters:
258c60c7ad4SBarry Smith +  pc - the preconditioner context
259c60c7ad4SBarry Smith -  flg - PETSC_TRUE turns off diagonal scaling inside the algorithm
2604b9ad928SBarry Smith 
2614b9ad928SBarry Smith    Options Database Key:
262c60c7ad4SBarry Smith .  -pc_eisenstat_no_diagonal_scaling - Activates PCEisenstatSetNoDiagonalScaling()
2634b9ad928SBarry Smith 
2644b9ad928SBarry Smith    Level: intermediate
2654b9ad928SBarry Smith 
2664b9ad928SBarry Smith    Note:
267f9ff08acSPierre Jolivet      If you use the KSPSetDiagonalScaling() or -ksp_diagonal_scale option then you will
2686aad120cSJose E. Roman    likely want to use this routine since it will save you some unneeded flops.
2694b9ad928SBarry Smith 
270db781477SPatrick Sanan .seealso: `PCEisenstatSetOmega()`
2714b9ad928SBarry Smith @*/
2729371c9d4SSatish Balay PetscErrorCode PCEisenstatSetNoDiagonalScaling(PC pc, PetscBool flg) {
2734b9ad928SBarry Smith   PetscFunctionBegin;
2740700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
275cac4c232SBarry Smith   PetscTryMethod(pc, "PCEisenstatSetNoDiagonalScaling_C", (PC, PetscBool), (pc, flg));
276c60c7ad4SBarry Smith   PetscFunctionReturn(0);
277c60c7ad4SBarry Smith }
278c60c7ad4SBarry Smith 
279c60c7ad4SBarry Smith /*@
280c60c7ad4SBarry Smith    PCEisenstatGetOmega - Gets the SSOR relaxation coefficient, omega,
281c60c7ad4SBarry Smith    to use with Eisenstat's trick (where omega = 1.0 by default).
282c60c7ad4SBarry Smith 
283c60c7ad4SBarry Smith    Logically Collective on PC
284c60c7ad4SBarry Smith 
285c60c7ad4SBarry Smith    Input Parameter:
286c60c7ad4SBarry Smith .  pc - the preconditioner context
287c60c7ad4SBarry Smith 
288c60c7ad4SBarry Smith    Output Parameter:
289c60c7ad4SBarry Smith .  omega - relaxation coefficient (0 < omega < 2)
290c60c7ad4SBarry Smith 
291c60c7ad4SBarry Smith    Options Database Key:
292c60c7ad4SBarry Smith .  -pc_eisenstat_omega <omega> - Sets omega
293c60c7ad4SBarry Smith 
294c60c7ad4SBarry Smith    Notes:
295c60c7ad4SBarry Smith    The Eisenstat trick implementation of SSOR requires about 50% of the
296c60c7ad4SBarry Smith    usual amount of floating point operations used for SSOR + Krylov method;
297c60c7ad4SBarry Smith    however, the preconditioned problem must be solved with both left
298c60c7ad4SBarry Smith    and right preconditioning.
299c60c7ad4SBarry Smith 
300c60c7ad4SBarry Smith    To use SSOR without the Eisenstat trick, employ the PCSOR preconditioner,
301c60c7ad4SBarry Smith    which can be chosen with the database options
302c60c7ad4SBarry Smith $    -pc_type  sor  -pc_sor_symmetric
303c60c7ad4SBarry Smith 
304c60c7ad4SBarry Smith    Level: intermediate
305c60c7ad4SBarry Smith 
306db781477SPatrick Sanan .seealso: `PCSORGetOmega()`, `PCEisenstatSetOmega()`
307c60c7ad4SBarry Smith @*/
3089371c9d4SSatish Balay PetscErrorCode PCEisenstatGetOmega(PC pc, PetscReal *omega) {
309c60c7ad4SBarry Smith   PetscFunctionBegin;
310c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
311cac4c232SBarry Smith   PetscUseMethod(pc, "PCEisenstatGetOmega_C", (PC, PetscReal *), (pc, omega));
312c60c7ad4SBarry Smith   PetscFunctionReturn(0);
313c60c7ad4SBarry Smith }
314c60c7ad4SBarry Smith 
315c60c7ad4SBarry Smith /*@
316163d334eSBarry Smith    PCEisenstatGetNoDiagonalScaling - Tells if the Eisenstat preconditioner
317c60c7ad4SBarry Smith    not to do additional diagonal preconditioning. For matrices with a constant
318c60c7ad4SBarry Smith    along the diagonal, this may save a small amount of work.
319c60c7ad4SBarry Smith 
320c60c7ad4SBarry Smith    Logically Collective on PC
321c60c7ad4SBarry Smith 
322c60c7ad4SBarry Smith    Input Parameter:
323c60c7ad4SBarry Smith .  pc - the preconditioner context
324c60c7ad4SBarry Smith 
325c60c7ad4SBarry Smith    Output Parameter:
326c60c7ad4SBarry Smith .  flg - PETSC_TRUE means there is no diagonal scaling applied
327c60c7ad4SBarry Smith 
328c60c7ad4SBarry Smith    Options Database Key:
329c60c7ad4SBarry Smith .  -pc_eisenstat_no_diagonal_scaling - Activates PCEisenstatSetNoDiagonalScaling()
330c60c7ad4SBarry Smith 
331c60c7ad4SBarry Smith    Level: intermediate
332c60c7ad4SBarry Smith 
333c60c7ad4SBarry Smith    Note:
334f9ff08acSPierre Jolivet      If you use the KSPSetDiagonalScaling() or -ksp_diagonal_scale option then you will
3356aad120cSJose E. Roman    likely want to use this routine since it will save you some unneeded flops.
336c60c7ad4SBarry Smith 
337db781477SPatrick Sanan .seealso: `PCEisenstatGetOmega()`
338c60c7ad4SBarry Smith @*/
3399371c9d4SSatish Balay PetscErrorCode PCEisenstatGetNoDiagonalScaling(PC pc, PetscBool *flg) {
340c60c7ad4SBarry Smith   PetscFunctionBegin;
341c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
342cac4c232SBarry Smith   PetscUseMethod(pc, "PCEisenstatGetNoDiagonalScaling_C", (PC, PetscBool *), (pc, flg));
3434b9ad928SBarry Smith   PetscFunctionReturn(0);
3444b9ad928SBarry Smith }
3454b9ad928SBarry Smith 
3469371c9d4SSatish Balay static PetscErrorCode PCPreSolveChangeRHS_Eisenstat(PC pc, PetscBool *change) {
3478066bbecSBarry Smith   PetscFunctionBegin;
3488066bbecSBarry Smith   *change = PETSC_TRUE;
3498066bbecSBarry Smith   PetscFunctionReturn(0);
3508066bbecSBarry Smith }
3518066bbecSBarry Smith 
3524b9ad928SBarry Smith /* --------------------------------------------------------------------*/
3534b9ad928SBarry Smith 
3544b9ad928SBarry Smith /*MC
3554b9ad928SBarry Smith      PCEISENSTAT - An implementation of SSOR (symmetric successive over relaxation, symmetric Gauss-Seidel)
3564b9ad928SBarry Smith            preconditioning that incorporates Eisenstat's trick to reduce the amount of computation needed.
3574b9ad928SBarry Smith 
3584b9ad928SBarry Smith    Options Database Keys:
3594b9ad928SBarry Smith +  -pc_eisenstat_omega <omega> - Sets omega
360c60c7ad4SBarry Smith -  -pc_eisenstat_no_diagonal_scaling - Activates PCEisenstatSetNoDiagonalScaling()
3614b9ad928SBarry Smith 
3624b9ad928SBarry Smith    Level: beginner
3634b9ad928SBarry Smith 
36495452b02SPatrick Sanan    Notes:
36595452b02SPatrick Sanan     Only implemented for the SeqAIJ matrix format.
3664b9ad928SBarry Smith           Not a true parallel SOR, in parallel this implementation corresponds to block
3674b9ad928SBarry Smith           Jacobi with SOR on each block.
3684b9ad928SBarry Smith 
369db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
370db781477SPatrick Sanan           `PCEisenstatSetNoDiagonalScaling()`, `PCEisenstatSetOmega()`, `PCSOR`
3714b9ad928SBarry Smith M*/
3724b9ad928SBarry Smith 
3739371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_Eisenstat(PC pc) {
3744b9ad928SBarry Smith   PC_Eisenstat *eis;
3754b9ad928SBarry Smith 
3764b9ad928SBarry Smith   PetscFunctionBegin;
3779566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &eis));
3784b9ad928SBarry Smith 
3794b9ad928SBarry Smith   pc->ops->apply           = PCApply_Eisenstat;
380dc231df0SBarry Smith   pc->ops->presolve        = PCPreSolve_Eisenstat;
381dc231df0SBarry Smith   pc->ops->postsolve       = PCPostSolve_Eisenstat;
3820a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
3834b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_Eisenstat;
3844b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_Eisenstat;
38569d2c0f9SBarry Smith   pc->ops->reset           = PCReset_Eisenstat;
3864b9ad928SBarry Smith   pc->ops->view            = PCView_Eisenstat;
3874b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_Eisenstat;
3884b9ad928SBarry Smith 
3893ec1f749SStefano Zampini   pc->data     = eis;
3904b9ad928SBarry Smith   eis->omega   = 1.0;
3910a545947SLisandro Dalcin   eis->b[0]    = NULL;
3920a545947SLisandro Dalcin   eis->b[1]    = NULL;
3930a545947SLisandro Dalcin   eis->diag    = NULL;
3944b9ad928SBarry Smith   eis->usediag = PETSC_TRUE;
3954b9ad928SBarry Smith 
3969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatSetOmega_C", PCEisenstatSetOmega_Eisenstat));
3979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatSetNoDiagonalScaling_C", PCEisenstatSetNoDiagonalScaling_Eisenstat));
3989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatGetOmega_C", PCEisenstatGetOmega_Eisenstat));
3999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCEisenstatGetNoDiagonalScaling_C", PCEisenstatGetNoDiagonalScaling_Eisenstat));
4009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCPreSolveChangeRHS_C", PCPreSolveChangeRHS_Eisenstat));
4014b9ad928SBarry Smith   PetscFunctionReturn(0);
4024b9ad928SBarry Smith }
403