From dd914bcea7354d95a2928520bea28b0ad9d2e3f7 Mon Sep 17 00:00:00 2001 From: Jonathan Guyer Date: Sat, 11 Nov 2023 12:44:55 -0500 Subject: [PATCH] Harmonize preconditioners --- fipy/solvers/petsc/linearLUSolver.py | 2 +- fipy/solvers/petsc/petscKrylovSolver.py | 4 +- .../preconditioners/defaultPreconditioner.py | 7 +- .../petsc/preconditioners/icPreconditioner.py | 8 +-- .../preconditioners/iluPreconditioner.py | 8 +-- .../preconditioners/jacobiPreconditioner.py | 8 +-- .../petsc/preconditioners/luPreconditioner.py | 7 +- ...econditioner.py => petscPreconditioner.py} | 10 +-- .../preconditioners/ssorPreconditioner.py | 6 +- fipy/solvers/preconditioner.py | 57 +++++++++++++++ .../smoothedAggregationPreconditioner.py | 12 ++-- fipy/solvers/pyamgx/preconditioners.py | 71 +++++++++---------- fipy/solvers/pyamgx/pyAMGXSolver.py | 10 ++- fipy/solvers/pyamgx/smoothers.py | 7 +- fipy/solvers/pysparse/linearCGSSolver.py | 2 +- fipy/solvers/pysparse/linearLUSolver.py | 2 +- .../pysparse/preconditioners/__init__.py | 8 ++- .../preconditioners/jacobiPreconditioner.py | 18 +++-- .../preconditioners/preconditioner.py | 19 ----- .../preconditioners/pysparsePreconditioner.py | 15 ++++ .../preconditioners/ssorPreconditioner.py | 20 +++--- .../preconditioners/iluPreconditioner.py | 18 ++--- .../preconditioners/jacobiPreconditioner.py | 19 ++--- .../scipy/preconditioners/preconditioner.py | 17 ----- .../preconditioners/scipyPreconditioner.py | 16 +++++ fipy/solvers/scipy/scipyKrylovSolver.py | 6 +- fipy/solvers/scipy/scipySolver.py | 4 +- fipy/solvers/solver.py | 2 +- .../trilinos/preconditioners/__init__.py | 23 ++++-- .../domDecompPreconditioner.py | 8 +-- .../preconditioners/icPreconditioner.py | 8 +-- .../preconditioners/iluPreconditioner.py | 4 +- .../preconditioners/jacobiPreconditioner.py | 8 +-- .../multilevelDDMLPreconditioner.py | 66 ++++++++--------- .../multilevelDDPreconditioner.py | 65 +++++++++-------- .../multilevelNSSAPreconditioner.py | 54 ++++++-------- .../multilevelPreconditioner.py | 48 +++++++++++++ .../multilevelSAPreconditioner.py | 61 +++++++--------- .../multilevelSGSPreconditioner.py | 32 +++------ .../multilevelSolverSmootherPreconditioner.py | 32 +++------ .../preconditioners/preconditioner.py | 17 ----- .../preconditioners/trilinosPreconditioner.py | 16 +++++ 42 files changed, 443 insertions(+), 382 deletions(-) rename fipy/solvers/petsc/preconditioners/{preconditioner.py => petscPreconditioner.py} (57%) create mode 100644 fipy/solvers/preconditioner.py delete mode 100644 fipy/solvers/pysparse/preconditioners/preconditioner.py create mode 100644 fipy/solvers/pysparse/preconditioners/pysparsePreconditioner.py delete mode 100644 fipy/solvers/scipy/preconditioners/preconditioner.py create mode 100644 fipy/solvers/scipy/preconditioners/scipyPreconditioner.py create mode 100644 fipy/solvers/trilinos/preconditioners/multilevelPreconditioner.py delete mode 100644 fipy/solvers/trilinos/preconditioners/preconditioner.py create mode 100644 fipy/solvers/trilinos/preconditioners/trilinosPreconditioner.py diff --git a/fipy/solvers/petsc/linearLUSolver.py b/fipy/solvers/petsc/linearLUSolver.py index 9a6d8c6028..a2b4cfceb1 100644 --- a/fipy/solvers/petsc/linearLUSolver.py +++ b/fipy/solvers/petsc/linearLUSolver.py @@ -30,7 +30,7 @@ def __init__(self, tolerance="default", criterion="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon : ~fipy.solvers.petsc.preconditioners.preconditioner.Preconditioner + precon *ignored* """ super(LinearLUSolver, self).__init__(tolerance=tolerance, diff --git a/fipy/solvers/petsc/petscKrylovSolver.py b/fipy/solvers/petsc/petscKrylovSolver.py index 3e24c05513..7dc1cbaf8e 100644 --- a/fipy/solvers/petsc/petscKrylovSolver.py +++ b/fipy/solvers/petsc/petscKrylovSolver.py @@ -39,10 +39,10 @@ def __init__(self, tolerance="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon : ~fipy.solvers.petsc.preconditioners.preconditioner.Preconditioner, optional + precon : ~fipy.solvers.petsc.preconditioners.petscPreconditioner.PETScPreconditioner, optional Preconditioner to apply to the matrix. A value of None means to perform an unpreconditioned solve. (default: - ~fipy.solvers.petsc.preconditioners.defaultPreconditioner.DefaultPreconditioner). + :class:`~fipy.solvers.petsc.preconditioners.defaultPreconditioner.DefaultPreconditioner`). """ if self.__class__ is PETScKrylovSolver: raise NotImplementedError("can't instantiate abstract base class") diff --git a/fipy/solvers/petsc/preconditioners/defaultPreconditioner.py b/fipy/solvers/petsc/preconditioners/defaultPreconditioner.py index a911c1198b..658be5daba 100644 --- a/fipy/solvers/petsc/preconditioners/defaultPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/defaultPreconditioner.py @@ -1,15 +1,14 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["DefaultPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class DefaultPreconditioner(Preconditioner): - """ - Apply PETSc's default preconditioning. +class DefaultPreconditioner(PETScPreconditioner): + """Apply PETSc's default preconditioning to :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. "The default preconditioner for sparse matrices is PCILU or PCICC with 0 fill on one process and block Jacobi (PCBJACOBI) with PCILU or PCICC diff --git a/fipy/solvers/petsc/preconditioners/icPreconditioner.py b/fipy/solvers/petsc/preconditioners/icPreconditioner.py index 03175da9d1..71bf5137e1 100644 --- a/fipy/solvers/petsc/preconditioners/icPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/icPreconditioner.py @@ -1,16 +1,14 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["ICPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class ICPreconditioner(Preconditioner): - """ - Incomplete Choleski Preconditioner for PETSc solvers. - +class ICPreconditioner(PETScPreconditioner): + """Incomplete Choleski preconditioner for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. """ pctype = "icc" diff --git a/fipy/solvers/petsc/preconditioners/iluPreconditioner.py b/fipy/solvers/petsc/preconditioners/iluPreconditioner.py index 4882ca5a2c..fdd5b311d6 100644 --- a/fipy/solvers/petsc/preconditioners/iluPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/iluPreconditioner.py @@ -1,16 +1,14 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["ILUPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class ILUPreconditioner(Preconditioner): - """ - ILU Preconditioner for PETSc solvers. - +class ILUPreconditioner(PETScPreconditioner): + """ILU preconditioner for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. """ pctype = "ilu" diff --git a/fipy/solvers/petsc/preconditioners/jacobiPreconditioner.py b/fipy/solvers/petsc/preconditioners/jacobiPreconditioner.py index 589514e49b..05a34ef3f1 100644 --- a/fipy/solvers/petsc/preconditioners/jacobiPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/jacobiPreconditioner.py @@ -1,16 +1,14 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["JacobiPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class JacobiPreconditioner(Preconditioner): - """ - Jacobi Preconditioner for PETSc solvers. - +class JacobiPreconditioner(PETScPreconditioner): + """Jacobi preconditioner for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. """ pctype = "jacobi" diff --git a/fipy/solvers/petsc/preconditioners/luPreconditioner.py b/fipy/solvers/petsc/preconditioners/luPreconditioner.py index eefa5fe3f7..8871419d77 100644 --- a/fipy/solvers/petsc/preconditioners/luPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/luPreconditioner.py @@ -1,15 +1,14 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["LUPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class LUPreconditioner(Preconditioner): - """ - LU Preconditioner for PETSc solvers. +class LUPreconditioner(PETScPreconditioner): + """LU preconditioner for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. """ diff --git a/fipy/solvers/petsc/preconditioners/preconditioner.py b/fipy/solvers/petsc/preconditioners/petscPreconditioner.py similarity index 57% rename from fipy/solvers/petsc/preconditioners/preconditioner.py rename to fipy/solvers/petsc/preconditioners/petscPreconditioner.py index 90c8366b07..0722dbf0bf 100644 --- a/fipy/solvers/petsc/preconditioners/preconditioner.py +++ b/fipy/solvers/petsc/preconditioners/petscPreconditioner.py @@ -1,14 +1,14 @@ from __future__ import unicode_literals -from builtins import object __docformat__ = 'restructuredtext' -__all__ = ["Preconditioner"] +from fipy.solvers.preconditioner import SolverModifyingPreconditioner + +__all__ = ["PETScPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class Preconditioner(object): - """ - The base Preconditioner class. +class PETScPreconditioner(SolverModifyingPreconditioner): + """Base class preconditioners of for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. .. attention:: This class is abstract. Always create one of its subclasses. """ diff --git a/fipy/solvers/petsc/preconditioners/ssorPreconditioner.py b/fipy/solvers/petsc/preconditioners/ssorPreconditioner.py index 16d8266fd0..5d0888967a 100644 --- a/fipy/solvers/petsc/preconditioners/ssorPreconditioner.py +++ b/fipy/solvers/petsc/preconditioners/ssorPreconditioner.py @@ -1,15 +1,15 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from .preconditioner import Preconditioner +from .petscPreconditioner import PETScPreconditioner __all__ = ["SSORPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class SSORPreconditioner(Preconditioner): +class SSORPreconditioner(PETScPreconditioner): """ - SSOR Preconditioner for PETSc solvers. + SSOR preconditioner for :class:`~fipy.solvers.petsc.petscSolver.PETScSolver`. """ diff --git a/fipy/solvers/preconditioner.py b/fipy/solvers/preconditioner.py new file mode 100644 index 0000000000..487b2c2a8c --- /dev/null +++ b/fipy/solvers/preconditioner.py @@ -0,0 +1,57 @@ +from __future__ import unicode_literals +from builtins import object +__docformat__ = 'restructuredtext' + +__all__ = ["Preconditioner", + "SolverModifyingPreconditioner", + "MatrixModifyingPreconditioner"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +class Preconditioner(object): + """Base class for solver preconditioners. + + .. attention:: This class is abstract. Always create one of its subclasses. + """ + + pass + + +class SolverModifyingPreconditioner(Preconditioner): + """Base class for preconditioners that modify a :class:`~fipy.solvers.solver.Solver`. + """ + + def _applyToSolver(self, solver, matrix): + """Modify `solver` to apply preconditioning to `matrix`. + + Parameters + ---------- + solver + The solver to modify with preconditioner. + matrix + The matrix the preconditioner applies to. + + Returns + ------- + None + """ + raise NotImplementedError + + +class MatrixModifyingPreconditioner(Preconditioner): + """Base class for preconditioners that modify a :class:`~fipy.matrices.sparseMatrix.SparseMatrix`. + """ + + def _applyToMatrix(self, matrix): + """Create a preconditioner for `matrix`. + + Returns + ------- + preconditioner : object + Preconditioning object appropriate for this solver suite. + matrix : :class:`~fipy.matrices.sparseMatrix.SparseMatrix` + Matrix, possibly restructured to facilitate applying + preconditioner. + """ + raise NotImplementedError + diff --git a/fipy/solvers/pyAMG/preconditioners/smoothedAggregationPreconditioner.py b/fipy/solvers/pyAMG/preconditioners/smoothedAggregationPreconditioner.py index 3c4ebf57b7..a4f3f55c2e 100644 --- a/fipy/solvers/pyAMG/preconditioners/smoothedAggregationPreconditioner.py +++ b/fipy/solvers/pyAMG/preconditioners/smoothedAggregationPreconditioner.py @@ -3,18 +3,20 @@ from pyamg import smoothed_aggregation_solver -from ...scipy.preconditioners.preconditioner import Preconditioner +from ...scipy.preconditioners.scipyPreconditioner import ScipyPreconditioner __all__ = ["SmoothedAggregationPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class SmoothedAggregationPreconditioner(Preconditioner): - """Preconditioner based on `PyAMG smoothed_aggregation_solver `_ +class SmoothedAggregationPreconditioner(ScipyPreconditioner): + """Preconditioner based on `PyAMG smoothed_aggregation_solver`_ for :class:`~fipy.solvers.scipy.scipySolver.ScipySolver`. + + .. _PyAMG smoothed_aggregation_solver: https://pyamg.readthedocs.io/en/latest/generated/pyamg.aggregation.html#pyamg.aggregation.smoothed_aggregation_solver """ def __init__(self): pass - def _applyToMatrix(self, A): - return smoothed_aggregation_solver(A).aspreconditioner(cycle='V') + def _applyToMatrix(self, matrix): + return smoothed_aggregation_solver(matrix).aspreconditioner(cycle='V'), None diff --git a/fipy/solvers/pyamgx/preconditioners.py b/fipy/solvers/pyamgx/preconditioners.py index 471bde750c..b4f132b93f 100644 --- a/fipy/solvers/pyamgx/preconditioners.py +++ b/fipy/solvers/pyamgx/preconditioners.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals -from builtins import object -import copy + +from fipy.solvers.preconditioner import SolverModifyingPreconditioner __all__ = ["AMGPreconditioner", "AggregationAMGPreconditioner", @@ -12,96 +12,91 @@ "ILUPreconditioner", "JacobiPreconditioner", "PolynomialPreconditioner", - "Preconditioner"] + "PyAMGXPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class Preconditioner(object): - """Interface to pyamgx_ `preconditioner configuration`_. +class PyAMGXPreconditioner(SolverModifyingPreconditioner): + """Interface to pyamgx_ `preconditioner configuration`_ for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. .. _pyamgx: https://pyamgx.readthedocs.io .. _preconditioner configuration: https://pyamgx.readthedocs.io/en/latest/basic.html#config-objects """ def __init__(self, **kwargs): + """ + Parameters + ---------- + **kwargs : dict, optional + Extra arguments to preconditioner: refer to `preconditioner + configuration`_ for information about possible arguments. + """ self.config_dict = { "solver": self.pctype, "max_iters": 1 } self.config_dict.update(kwargs) - def __call__(self, **kwargs): - config_dict = self.config_dict.copy() - config_dict.update(kwargs) - return config_dict + def _applyToSolver(self, solver, matrix=None): + solver["preconditioner"] = self.config_dict.copy() -class AMGPreconditioner(Preconditioner): +class AMGPreconditioner(PyAMGXPreconditioner): + """Adaptive Multigrid preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Adaptive Multigrid Preconditioner for pyamgx solvers. - """ pctype = "AMG" class AggregationAMGPreconditioner(AMGPreconditioner): + """Aggregation Adaptive Multigrid preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Aggregation Adaptive Multigrid Preconditioner for pyamgx solvers. - """ def __init__(self): super(ClassicalAMGPreconditioner, self).__init__(algorithm="AGGREGATION", selector="SIZE_2") -class BiCGStabPreconditioner(Preconditioner): +class BiCGStabPreconditioner(PyAMGXPreconditioner): + """Biconjugate Gradient Stabilized preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Biconjugate Gradient Stabilized Preconditioner for pyamgx solvers. - """ pctype = "PCIBCGSTAB" -class CGPreconditioner(Preconditioner): +class CGPreconditioner(PyAMGXPreconditioner): + """Conjugate Gradient preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Conjugate Gradient Preconditioner for pyamgx solvers. - """ pctype = "PCG" -class DILUPreconditioner(Preconditioner): +class DILUPreconditioner(PyAMGXPreconditioner): + """DILU preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - DILU Preconditioner for pyamgx solvers. - """ pctype = "MULTICOLOR_DILU" -class FGMRESPreconditioner(Preconditioner): +class FGMRESPreconditioner(PyAMGXPreconditioner): + """Flexible Generalized Mimumal Residual preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Flexible Generalized Mimumal Residual Preconditioner for pyamgx solvers. - """ pctype = "FGMRES" -class GaussSeidelPreconditioner(Preconditioner): +class GaussSeidelPreconditioner(PyAMGXPreconditioner): + """Gauss-Seidel preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Gauss-Seidel Preconditioner for pyamgx solvers. - """ pctype = "MULTICOLOR_GS" -class ILUPreconditioner(Preconditioner): +class ILUPreconditioner(PyAMGXPreconditioner): + """ILU preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - ILU Preconditioner for pyamgx solvers. - """ pctype = "MULTICOLOR_GS" -class JacobiPreconditioner(Preconditioner): +class JacobiPreconditioner(PyAMGXPreconditioner): + """Block Jacobi preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Block Jacobi Preconditioner for pyamgx solvers. - """ pctype = "BLOCK_JACOBI" -class PolynomialPreconditioner(Preconditioner): +class PolynomialPreconditioner(PyAMGXPreconditioner): + """Polynomial preconditioner for :class:`~fipy.solvers.pyamgx.pyAMGXSolver.PyAMGXSolver`. """ - Polynomial Preconditioner for pyamgx solvers. - """ pctype = "POLYNOMIAL" diff --git a/fipy/solvers/pyamgx/pyAMGXSolver.py b/fipy/solvers/pyamgx/pyAMGXSolver.py index 2a261fbc8d..10b646fb05 100644 --- a/fipy/solvers/pyamgx/pyAMGXSolver.py +++ b/fipy/solvers/pyamgx/pyAMGXSolver.py @@ -17,6 +17,7 @@ class PyAMGXSolver(Solver): # AMGX configuration options CONFIG_DICT = {} + #: Default smoother to apply to the ??? DEFAULT_SMOOTHER = None def __init__(self, tolerance="default", criterion="default", @@ -31,7 +32,7 @@ def __init__(self, tolerance="default", criterion="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon : ~fipy.solvers.pyamgx.preconditioners.Preconditioner, optional + precon : ~fipy.solvers.pyamgx.preconditioners.PyAMGXPreconditioner, optional smoother : ~fipy.solvers.pyamgx.smoothers.Smoother, optional **kwargs Other AMGX solver options @@ -42,11 +43,14 @@ def __init__(self, tolerance="default", criterion="default", self.config_dict = self.CONFIG_DICT.copy() self.config_dict["solver"]["max_iters"] = self.iterations + if self.precon is not None: - self.config_dict["solver"]["preconditioner"] = self.precon() + self.precon._applyToSolver(self.config_dict["solver"]) + smoother = self.value_or_default(smoother, self.default_smoother) if smoother is not None: - self.config_dict["solver"]["smoother"] = smoother + smoother._applyToSolver(self.config_dict["solver"]) + self.config_dict["solver"].update(kwargs) # create AMGX objects: diff --git a/fipy/solvers/pyamgx/smoothers.py b/fipy/solvers/pyamgx/smoothers.py index fff51140e8..5168c68bb2 100644 --- a/fipy/solvers/pyamgx/smoothers.py +++ b/fipy/solvers/pyamgx/smoothers.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals from builtins import object -import copy __all__ = ["BlockJacobiSmoother", "MultiColorDILUSmoother", @@ -22,9 +21,9 @@ def __init__(self, smoother_type): "solver": smoother_type, "max_iters": 1 } - def __call__(self, **kwargs): - self.config_dict.update(kwargs) - return copy.copy(self.config_dict) + + def _applyToSolver(self, solver): + solver["smoother"] = self.config_dict.copy() BlockJacobiSmoother = Smoother("BLOCK_JACOBI") MultiColorDILUSmoother = Smoother("MULTICOLOR_DILU") diff --git a/fipy/solvers/pysparse/linearCGSSolver.py b/fipy/solvers/pysparse/linearCGSSolver.py index 36afa26708..d908933dc8 100644 --- a/fipy/solvers/pysparse/linearCGSSolver.py +++ b/fipy/solvers/pysparse/linearCGSSolver.py @@ -44,7 +44,7 @@ def __init__(self, tolerance="default", criterion="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon : ~fipy.solvers.pysparse.preconditioners.preconditioner.Preconditioner + precon : ~fipy.solvers.pysparse.preconditioners.pysparsePreconditioner.PysparsePreconditioner Preconditioner to use. """ warnings.warn("The Pysparse CGS solver may return incorrect results for some matrices", UserWarning) diff --git a/fipy/solvers/pysparse/linearLUSolver.py b/fipy/solvers/pysparse/linearLUSolver.py index cd7e6fe691..cebbf3c854 100644 --- a/fipy/solvers/pysparse/linearLUSolver.py +++ b/fipy/solvers/pysparse/linearLUSolver.py @@ -41,7 +41,7 @@ def __init__(self, tolerance="default", criterion="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon : ~fipy.solvers.pysparse.preconditioners.preconditioner.Preconditioner + precon *ignored* """ super(LinearLUSolver, self).__init__(tolerance=tolerance, criterion=criterion, diff --git a/fipy/solvers/pysparse/preconditioners/__init__.py b/fipy/solvers/pysparse/preconditioners/__init__.py index 9aa77d6b4f..9f1e453425 100644 --- a/fipy/solvers/pysparse/preconditioners/__init__.py +++ b/fipy/solvers/pysparse/preconditioners/__init__.py @@ -1,3 +1,7 @@ from __future__ import unicode_literals -from fipy.solvers.pysparse.preconditioners.jacobiPreconditioner import * -from fipy.solvers.pysparse.preconditioners.ssorPreconditioner import * +from .jacobiPreconditioner import * +from .ssorPreconditioner import * + +__all__ = [] +__all__.extend(jacobiPreconditioner.__all__) +__all__.extend(ssorPreconditioner.__all__) diff --git a/fipy/solvers/pysparse/preconditioners/jacobiPreconditioner.py b/fipy/solvers/pysparse/preconditioners/jacobiPreconditioner.py index 764fbf29b7..efe5d0ab41 100644 --- a/fipy/solvers/pysparse/preconditioners/jacobiPreconditioner.py +++ b/fipy/solvers/pysparse/preconditioners/jacobiPreconditioner.py @@ -1,19 +1,17 @@ from __future__ import unicode_literals from pysparse.precon import precon -from fipy.solvers.pysparse.preconditioners.preconditioner import Preconditioner +from fipy.solvers.pysparse.preconditioners.pysparsePreconditioner import PysparsePreconditioner __all__ = ["JacobiPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class JacobiPreconditioner(Preconditioner): - """ - Jacobi preconditioner for Pysparse. - Really just a wrapper class for `pysparse.precon.jacobi`. +class JacobiPreconditioner(PysparsePreconditioner): + """Jacobi preconditioner for :class:`~fipy.solvers.pysparse.pysparseSolver.PysparseSolver`. + + Wrapper class for :func:`pysparse.precon.jacobi`. """ - def _applyToMatrix(self, A): - """ - Returns (preconditioning matrix, resulting matrix) - """ - return precon.jacobi(A), A.to_csr() + + def _applyToMatrix(self, matrix): + return precon.jacobi(matrix), matrix.to_csr() diff --git a/fipy/solvers/pysparse/preconditioners/preconditioner.py b/fipy/solvers/pysparse/preconditioners/preconditioner.py deleted file mode 100644 index fb329eb284..0000000000 --- a/fipy/solvers/pysparse/preconditioners/preconditioner.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals -from builtins import object -__all__ = ["Preconditioner"] -from future.utils import text_to_native_str -__all__ = [text_to_native_str(n) for n in __all__] - -class Preconditioner(object): - """ - Base preconditioner class - - .. attention:: This class is abstract. Always create one of its subclasses. - """ - - def _applyToMatrix(self, A): - """ - Returns the function used for Pysparse - preconditioning. - """ - raise NotImplementedError diff --git a/fipy/solvers/pysparse/preconditioners/pysparsePreconditioner.py b/fipy/solvers/pysparse/preconditioners/pysparsePreconditioner.py new file mode 100644 index 0000000000..0a1497b536 --- /dev/null +++ b/fipy/solvers/pysparse/preconditioners/pysparsePreconditioner.py @@ -0,0 +1,15 @@ +from __future__ import unicode_literals + +from fipy.solvers.preconditioner import MatrixModifyingPreconditioner + +__all__ = ["PysparsePreconditioner"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +class PysparsePreconditioner(MatrixModifyingPreconditioner): + """Base class for preconditioners of :class:`~fipy.solvers.pysparse.pysparseSolver.PysparseSolver`. + + .. attention:: This class is abstract. Always create one of its subclasses. + """ + + pass diff --git a/fipy/solvers/pysparse/preconditioners/ssorPreconditioner.py b/fipy/solvers/pysparse/preconditioners/ssorPreconditioner.py index 759cd82ed0..9beabb8d82 100644 --- a/fipy/solvers/pysparse/preconditioners/ssorPreconditioner.py +++ b/fipy/solvers/pysparse/preconditioners/ssorPreconditioner.py @@ -1,20 +1,18 @@ from __future__ import unicode_literals from pysparse.precon import precon -from fipy.solvers.pysparse.preconditioners.preconditioner import Preconditioner +from fipy.solvers.pysparse.preconditioners.pysparsePreconditioner import PysparsePreconditioner __all__ = ["SSORPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class SSORPreconditioner(Preconditioner): - """ - SSOR preconditioner for Pysparse. - Really just a wrapper class for `pysparse.precon.ssor`. +class SSORPreconditioner(PysparsePreconditioner): + """SSOR preconditioner for :class:`~fipy.solvers.pysparse.pysparseSolver.PysparseSolver`. + + Wrapper class for :func:`pysparse.precon.ssor`. """ - def _applyToMatrix(self, A): - """ - Returns (preconditioning matrix, resulting matrix) - """ - A = A.to_sss() - return precon.ssor(A), A + + def _applyToMatrix(self, matrix): + matrix = matrix.to_sss() + return precon.ssor(matrix), matrix diff --git a/fipy/solvers/scipy/preconditioners/iluPreconditioner.py b/fipy/solvers/scipy/preconditioners/iluPreconditioner.py index 519577cb0e..6fb01b6202 100644 --- a/fipy/solvers/scipy/preconditioners/iluPreconditioner.py +++ b/fipy/solvers/scipy/preconditioners/iluPreconditioner.py @@ -1,7 +1,4 @@ -# Adapted from https://stackoverflow.com/q/46876951/2019542 - from __future__ import unicode_literals -from builtins import object __docformat__ = 'restructuredtext' __all__ = ["ILUPreconditioner"] @@ -10,12 +7,17 @@ from scipy.sparse.linalg import LinearOperator, spilu -from .preconditioner import Preconditioner +from .scipyPreconditioner import ScipyPreconditioner + +class ILUPreconditioner(ScipyPreconditioner): + """ILU preconditioner for :class:`~fipy.solvers.scipy.scipySolver.ScipySolver`. -class ILUPreconditioner(Preconditioner): + Wrapper class for :func:`scipy.sparse.linalg.spilu`. + Adapted from https://stackoverflow.com/q/46876951/2019542. + """ - def _applyToMatrix(self, A): - ilu = spilu(A.tocsc()) + def _applyToMatrix(self, matrix): + ilu = spilu(matrix.tocsc()) Mx = lambda x: ilu.solve(x) - return LinearOperator(A.shape, Mx) + return LinearOperator(matrix.shape, Mx), matrix diff --git a/fipy/solvers/scipy/preconditioners/jacobiPreconditioner.py b/fipy/solvers/scipy/preconditioners/jacobiPreconditioner.py index c4074ffdc5..578fc9645d 100644 --- a/fipy/solvers/scipy/preconditioners/jacobiPreconditioner.py +++ b/fipy/solvers/scipy/preconditioners/jacobiPreconditioner.py @@ -1,7 +1,4 @@ -# Adapted from https://stackoverflow.com/q/46876951/2019542 - from __future__ import unicode_literals -from builtins import object __docformat__ = 'restructuredtext' __all__ = ["JacobiPreconditioner"] @@ -11,12 +8,18 @@ from scipy.sparse import diags from scipy.sparse.linalg import LinearOperator, spsolve -from .preconditioner import Preconditioner +from .scipyPreconditioner import ScipyPreconditioner + +class JacobiPreconditioner(ScipyPreconditioner): + """Jacobi preconditioner for :class:`~fipy.solvers.scipy.scipySolver.ScipySolver`. -class JacobiPreconditioner(Preconditioner): + Wrapper class for :func:`scipy.sparse.linalg.spsolve` with `matrix` + diagonal. + Adapted from https://stackoverflow.com/q/46876951/2019542. + """ - def _applyToMatrix(self, A): - P = diags(A.diagonal()).tocsc() + def _applyToMatrix(self, matrix): + P = diags(matrix.diagonal()).tocsc() Mx = lambda x: spsolve(P, x) - return LinearOperator(A.shape, Mx) + return LinearOperator(matrix.shape, Mx), matrix diff --git a/fipy/solvers/scipy/preconditioners/preconditioner.py b/fipy/solvers/scipy/preconditioners/preconditioner.py deleted file mode 100644 index 9f8f38d92a..0000000000 --- a/fipy/solvers/scipy/preconditioners/preconditioner.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -from builtins import object -__docformat__ = 'restructuredtext' - -__all__ = ["Preconditioner"] -from future.utils import text_to_native_str -__all__ = [text_to_native_str(n) for n in __all__] - -class Preconditioner(object): - """ - The base Preconditioner class. - - .. attention:: This class is abstract. Always create one of its subclasses. - """ - - def _applyToMatrix(self, A): - raise NotImplementedError diff --git a/fipy/solvers/scipy/preconditioners/scipyPreconditioner.py b/fipy/solvers/scipy/preconditioners/scipyPreconditioner.py new file mode 100644 index 0000000000..226d9f5d1f --- /dev/null +++ b/fipy/solvers/scipy/preconditioners/scipyPreconditioner.py @@ -0,0 +1,16 @@ +from __future__ import unicode_literals +__docformat__ = 'restructuredtext' + +from fipy.solvers.preconditioner import MatrixModifyingPreconditioner + +__all__ = ["ScipyPreconditioner"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +class ScipyPreconditioner(MatrixModifyingPreconditioner): + """Base class for preconditioners for :class:`~fipy.solvers.scipy.scipySolver.ScipySolver`. + + .. attention:: This class is abstract. Always create one of its subclasses. + """ + + pass diff --git a/fipy/solvers/scipy/scipyKrylovSolver.py b/fipy/solvers/scipy/scipyKrylovSolver.py index 80157f021f..0efb5e2011 100644 --- a/fipy/solvers/scipy/scipyKrylovSolver.py +++ b/fipy/solvers/scipy/scipyKrylovSolver.py @@ -1,7 +1,9 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -__all__ = [] +__all__ = ["ScipyKrylovSolver"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] import os import warnings @@ -42,7 +44,7 @@ def _solve_(self, L, x, b): if self.preconditioner is None: M = None else: - M = self.preconditioner._applyToMatrix(A) + M, _ = self.preconditioner._applyToMatrix(A) tolerance_scale, _ = self._adaptTolerance(L, x, b) diff --git a/fipy/solvers/scipy/scipySolver.py b/fipy/solvers/scipy/scipySolver.py index b22027925d..78bcb785be 100644 --- a/fipy/solvers/scipy/scipySolver.py +++ b/fipy/solvers/scipy/scipySolver.py @@ -1,7 +1,9 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -__all__ = [] +__all__ = ["ScipySolver"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] from scipy.sparse import linalg diff --git a/fipy/solvers/solver.py b/fipy/solvers/solver.py index c5d5950426..6eabc7822a 100644 --- a/fipy/solvers/solver.py +++ b/fipy/solvers/solver.py @@ -127,7 +127,7 @@ def __init__(self, tolerance="default", criterion="default", See :ref:`CONVERGENCE` for more information. iterations : int Maximum number of iterative steps to perform. - precon + precon : ~fipy.solvers.preconditioner.Preconditioner Preconditioner to use. Not all solver suites support preconditioners. """ diff --git a/fipy/solvers/trilinos/preconditioners/__init__.py b/fipy/solvers/trilinos/preconditioners/__init__.py index 64799f88e8..129d479c34 100644 --- a/fipy/solvers/trilinos/preconditioners/__init__.py +++ b/fipy/solvers/trilinos/preconditioners/__init__.py @@ -1,12 +1,25 @@ from __future__ import unicode_literals +from .domDecompPreconditioner import * +from .icPreconditioner import * +from .iluPreconditioner import * +from .jacobiPreconditioner import * from .multilevelDDPreconditioner import * -from .multilevelSAPreconditioner import * from .multilevelDDMLPreconditioner import * from .multilevelNSSAPreconditioner import * -from .jacobiPreconditioner import * -from .icPreconditioner import * -from .domDecompPreconditioner import * +from .multilevelSAPreconditioner import * from .multilevelSGSPreconditioner import * from .multilevelSolverSmootherPreconditioner import * -from .iluPreconditioner import * + +__all__ = [] +__all__.extend(domDecompPreconditioner.__all__) +__all__.extend(icPreconditioner.__all__) +__all__.extend(iluPreconditioner.__all__) +__all__.extend(jacobiPreconditioner.__all__) +__all__.extend(icPreconditioner.__all__) +__all__.extend(multilevelDDPreconditioner.__all__) +__all__.extend(multilevelDDMLPreconditioner.__all__) +__all__.extend(multilevelNSSAPreconditioner.__all__) +__all__.extend(multilevelSAPreconditioner.__all__) +__all__.extend(multilevelSGSPreconditioner.__all__) +__all__.extend(multilevelSolverSmootherPreconditioner.__all__) diff --git a/fipy/solvers/trilinos/preconditioners/domDecompPreconditioner.py b/fipy/solvers/trilinos/preconditioners/domDecompPreconditioner.py index cbb5e2dd0a..24feb88548 100644 --- a/fipy/solvers/trilinos/preconditioners/domDecompPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/domDecompPreconditioner.py @@ -3,16 +3,14 @@ from PyTrilinos import AztecOO -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .trilinosPreconditioner import TrilinosPreconditioner __all__ = ["DomDecompPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class DomDecompPreconditioner(Preconditioner): - """ - Domain Decomposition preconditioner for Trilinos solvers. - +class DomDecompPreconditioner(TrilinosPreconditioner): + """Domain Decomposition preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ def _applyToSolver(self, solver, matrix): diff --git a/fipy/solvers/trilinos/preconditioners/icPreconditioner.py b/fipy/solvers/trilinos/preconditioners/icPreconditioner.py index 82f4fc2faa..adf4c985d7 100644 --- a/fipy/solvers/trilinos/preconditioners/icPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/icPreconditioner.py @@ -3,16 +3,14 @@ from PyTrilinos import IFPACK -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .trilinosPreconditioner import TrilinosPreconditioner __all__ = ["ICPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class ICPreconditioner(Preconditioner): - """ - Incomplete Cholesky Preconditioner from IFPACK for Trilinos Solvers. - +class ICPreconditioner(TrilinosPreconditioner): + """Incomplete Cholesky Preconditioner from IFPACK for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ def _applyToSolver(self, solver, matrix): diff --git a/fipy/solvers/trilinos/preconditioners/iluPreconditioner.py b/fipy/solvers/trilinos/preconditioners/iluPreconditioner.py index 354e33c16a..3ef401ef59 100644 --- a/fipy/solvers/trilinos/preconditioners/iluPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/iluPreconditioner.py @@ -10,9 +10,7 @@ __all__ = [text_to_native_str(n) for n in __all__] class ILUPreconditioner(DomDecompPreconditioner): - """ - ILU Domain Decomposition preconditioner for Trilinos solvers. - + """ILU Domain Decomposition preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ def _applyToSolver(self, solver, matrix): diff --git a/fipy/solvers/trilinos/preconditioners/jacobiPreconditioner.py b/fipy/solvers/trilinos/preconditioners/jacobiPreconditioner.py index b4ea2912e9..ff074a90c7 100644 --- a/fipy/solvers/trilinos/preconditioners/jacobiPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/jacobiPreconditioner.py @@ -3,16 +3,14 @@ from PyTrilinos import AztecOO -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .trilinosPreconditioner import TrilinosPreconditioner __all__ = ["JacobiPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class JacobiPreconditioner(Preconditioner): - """ - Jacobi Preconditioner for Trilinos solvers. - +class JacobiPreconditioner(TrilinosPreconditioner): + """Jacobi preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ def _applyToSolver(self, solver, matrix): diff --git a/fipy/solvers/trilinos/preconditioners/multilevelDDMLPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelDDMLPreconditioner.py index b7b7a9d583..4e31696295 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelDDMLPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelDDMLPreconditioner.py @@ -1,43 +1,43 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from PyTrilinos import ML - -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelDDMLPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelDDMLPreconditioner(Preconditioner): - """ - Multilevel preconditioner for Trilinos solvers. 3-level algebraic domain decomposition. +class MultilevelDDMLPreconditioner(MultilevelPreconditioner): + """3-level algebraic domain decomposition multilevel preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return - - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - - self.Prec.SetParameterList({text_to_native_str("output"): 0, - text_to_native_str("max levels") : 3, - text_to_native_str("prec type") : text_to_native_str("MGV"), - text_to_native_str("increasing or decreasing") : text_to_native_str("increasing"), - text_to_native_str("aggregation: type") : text_to_native_str("METIS"), - text_to_native_str("aggregation: nodes per aggregate") : 512, - text_to_native_str("aggregation: next-level aggregates per process") : 128, - text_to_native_str("aggregation: damping factor") : 4. / 3., - text_to_native_str("eigen-analysis: type") : text_to_native_str("power-method"), - text_to_native_str("eigen-analysis: iterations") : 20, - text_to_native_str("smoother: sweeps") : 1, - text_to_native_str("smoother: pre or post") : text_to_native_str("both"), - text_to_native_str("smoother: type") : text_to_native_str("Aztec"), - text_to_native_str("smoother: Aztec as solver") : False, - text_to_native_str("coarse: type") : text_to_native_str("Amesos-KLU"), - text_to_native_str("coarse: max size") : 128 - }) - - self.Prec.ComputePreconditioner() - - solver.SetPrecOperator(self.Prec) + def __init__(self, levels=3): + """ + + Parameters + ---------- + levels : int + Maximum number of levels + """ + self.levels = levels + + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "prec type": "MGV", + "increasing or decreasing": "increasing", + "aggregation: type": "METIS", + "aggregation: nodes per aggregate": 512, + "aggregation: next-level aggregates per process": 128, + "aggregation: damping factor" : 4. / 3., + "eigen-analysis: type": "power-method", + "eigen-analysis: iterations": 20, + "smoother: sweeps": 1, + "smoother: pre or post": "both", + "smoother: type": "Aztec", + "smoother: Aztec as solver": False, + "coarse: type": "Amesos-KLU", + "coarse: max size": 128 + } diff --git a/fipy/solvers/trilinos/preconditioners/multilevelDDPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelDDPreconditioner.py index 2dcd19e4ce..81394a5ef2 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelDDPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelDDPreconditioner.py @@ -1,43 +1,42 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from PyTrilinos import ML - -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelDDPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelDDPreconditioner(Preconditioner): - """ - Multilevel preconditioner for Trilinos solvers. A classical smoothed - aggregation-based 2-level domain decomposition. +class MultilevelDDPreconditioner(MultilevelPreconditioner): + """Classical smoothed aggregation-based 2-level domain decomposition preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return - - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - - self.Prec.SetParameterList({text_to_native_str("output"): 0, - text_to_native_str("max levels") : 2, - text_to_native_str("prec type") : text_to_native_str("MGV"), - text_to_native_str("increasing or decreasing") : text_to_native_str("increasing"), - text_to_native_str("aggregation: type") : text_to_native_str("METIS"), - text_to_native_str("aggregation: local aggregates") : 1, - text_to_native_str("aggregation: damping factor") : 4. / 3., - text_to_native_str("eigen-analysis: type") : text_to_native_str("power-method"), - text_to_native_str("eigen-analysis: iterations") : 20, - text_to_native_str("smoother: sweeps") : 1, - text_to_native_str("smoother: pre or post") : text_to_native_str("both"), - text_to_native_str("smoother: type") : text_to_native_str("Aztec"), - text_to_native_str("smoother: Aztec as solver") : False, - text_to_native_str("coarse: type") : text_to_native_str("Amesos-KLU"), - text_to_native_str("coarse: max size") : 128 - }) - - self.Prec.ComputePreconditioner() - - solver.SetPrecOperator(self.Prec) + def __init__(self, levels=2): + """ + + Parameters + ---------- + levels : int + Maximum number of levels + """ + self.levels = levels + + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "prec type": "MGV", + "increasing or decreasing": "increasing", + "aggregation: type": "METIS", + "aggregation: local aggregates": 1, + "aggregation: damping factor" : 4. / 3., + "eigen-analysis: type": "power-method", + "eigen-analysis: iterations": 20, + "smoother: sweeps": 1, + "smoother: pre or post": "both", + "smoother: type": "Aztec", + "smoother: Aztec as solver": False, + "coarse: type": "Amesos-KLU", + "coarse: max size": 128 + } diff --git a/fipy/solvers/trilinos/preconditioners/multilevelNSSAPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelNSSAPreconditioner.py index 5c3bc24b44..8e7a64dc66 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelNSSAPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelNSSAPreconditioner.py @@ -1,41 +1,33 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from PyTrilinos import ML - -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelNSSAPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelNSSAPreconditioner(Preconditioner): - """ - Energy-based minimizing smoothed aggregation suitable for highly - convective non-symmetric fluid flow problems. - """ - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return - - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - - self.Prec.SetParameterList({text_to_native_str("output"): 0, - text_to_native_str("max levels") : 10, - text_to_native_str("prec type") : text_to_native_str("MGW"), - text_to_native_str("increasing or decreasing") : text_to_native_str("increasing"), - text_to_native_str("aggregation: type") : text_to_native_str("Uncoupled-MIS"), - text_to_native_str("energy minimization: enable") : True, - text_to_native_str("eigen-analysis: type") : text_to_native_str("power-method"), - text_to_native_str("eigen-analysis: iterations") : 20, - text_to_native_str("smoother: sweeps") : 4, - text_to_native_str("smoother: damping factor") : 0.67, - text_to_native_str("smoother: pre or post") : text_to_native_str("post"), - text_to_native_str("smoother: type") : text_to_native_str("symmetric Gauss-Seidel"), - text_to_native_str("coarse: type") : text_to_native_str("Amesos-KLU"), - text_to_native_str("coarse: max size") : 256 - }) +class MultilevelNSSAPreconditioner(MultilevelPreconditioner): + """Energy-based minimizing smoothed aggregation preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. - self.Prec.ComputePreconditioner() + Suitable for highly convective non-symmetric fluid flow problems. + """ - solver.SetPrecOperator(self.Prec) + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "prec type": "MGW", + "increasing or decreasing": "increasing", + "aggregation: type": "Uncoupled-MIS", + "energy minimization: enable": True, + "eigen-analysis: type": "power-method", + "eigen-analysis: iterations": 20, + "smoother: sweeps": 4, + "smoother: damping factor": 0.67, + "smoother: pre or post": "post", + "smoother: type": "symmetric Gauss-Seidel", + "coarse: type": "Amesos-KLU", + "coarse: max size": 256 + } diff --git a/fipy/solvers/trilinos/preconditioners/multilevelPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelPreconditioner.py new file mode 100644 index 0000000000..395b5e8bc4 --- /dev/null +++ b/fipy/solvers/trilinos/preconditioners/multilevelPreconditioner.py @@ -0,0 +1,48 @@ +from __future__ import unicode_literals +__docformat__ = 'restructuredtext' + +from PyTrilinos import ML + +from .trilinosPreconditioner import TrilinosPreconditioner + +__all__ = ["MultilevelPreconditioner"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +class MultilevelPreconditioner(TrilinosPreconditioner): + """Base class for multilevel preconditioners for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. + """ + + def __init__(self, levels=10): + """ + Parameters + ---------- + levels : int + Maximum number of levels + """ + self.levels = levels + + @property + def _parameterList(self): + """Trilinos preconditioner parameters. + + Implemented as a property to avoid + `side-effects `_. + + Returns + ------- + dict + """ + raise NotImplementedError + + def _applyToSolver(self, solver, matrix): + if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): + return + + self.Prec = ML.MultiLevelPreconditioner(matrix, False) + + self.Prec.SetParameterList(self._parameterList) + + self.Prec.ComputePreconditioner() + + solver.SetPrecOperator(self.Prec) diff --git a/fipy/solvers/trilinos/preconditioners/multilevelSAPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelSAPreconditioner.py index d5442f1e01..18d6c8c2c2 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelSAPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelSAPreconditioner.py @@ -1,47 +1,34 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from PyTrilinos import ML - -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelSAPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelSAPreconditioner(Preconditioner): - """ - Multilevel preconditioner for Trilinos solvers suitable classical - smoothed aggregation for symmetric positive definite or nearly - symmetric positive definite systems. - """ - - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return +class MultilevelSAPreconditioner(MultilevelPreconditioner): + """Classical smoothed aggregation multilevel preconditioner for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - - self.Prec.SetParameterList({text_to_native_str("output"): 0, - text_to_native_str("max levels") : 10, - text_to_native_str("prec type") : text_to_native_str("MGV"), - text_to_native_str("increasing or decreasing") : text_to_native_str("increasing"), - text_to_native_str("aggregation: type") : text_to_native_str("Uncoupled-MIS"), - text_to_native_str("aggregation: damping factor") : 4. / 3., -## "energy minimization: enable" : False, -## "smoother: type" : "Aztec", -## "smoother: type" : "symmetric Gauss-Seidel", -## "eigen-analysis: type" : "power-method", - text_to_native_str("eigen-analysis: type") : text_to_native_str("cg"), - text_to_native_str("eigen-analysis: iterations") : 10, - text_to_native_str("smoother: sweeps") : 2, - text_to_native_str("smoother: damping factor") : 1.0, - text_to_native_str("smoother: pre or post") : text_to_native_str("both"), - text_to_native_str("smoother: type") : text_to_native_str("symmetric Gauss-Seidel"), - text_to_native_str("coarse: type") : text_to_native_str("Amesos-KLU"), - text_to_native_str("coarse: max size") : 128 - }) - - self.Prec.ComputePreconditioner() + Suitable for symmetric positive definite or nearly symmetric positive + definite systems. + """ - solver.SetPrecOperator(self.Prec) + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "prec type": "MGV", + "increasing or decreasing": "increasing", + "aggregation: type": "Uncoupled-MIS", + "aggregation: damping factor" : 4. / 3., + "eigen-analysis: type": "cg", + "eigen-analysis: iterations": 10, + "smoother: sweeps": 2, + "smoother: damping factor": 1.0, + "smoother: pre or post": "both", + "smoother: type": "symmetric Gauss-Seidel", + "coarse: type": "Amesos-KLU", + "coarse: max size": 128 + } diff --git a/fipy/solvers/trilinos/preconditioners/multilevelSGSPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelSGSPreconditioner.py index 96e68c9922..de3c98c848 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelSGSPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelSGSPreconditioner.py @@ -1,32 +1,20 @@ from __future__ import unicode_literals __docformat__ = 'restructuredtext' -from PyTrilinos import ML - -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelSGSPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelSGSPreconditioner(Preconditioner): - """ - Multilevel preconditioner for Trilinos solvers using Symmetric Gauss-Seidel smoothing. - +class MultilevelSGSPreconditioner(MultilevelPreconditioner): + """Multilevel preconditioner using Symmetric Gauss-Seidel smoothing for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ - def __init__(self, levels=10): - """ - Initialize the multilevel preconditioner - - - `levels`: Maximum number of levels - """ - self.levels = levels - - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - self.Prec.SetParameterList({text_to_native_str("output"): 0, text_to_native_str("smoother: type") : text_to_native_str("symmetric Gauss-Seidel")}) - self.Prec.ComputePreconditioner() - solver.SetPrecOperator(self.Prec) + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "smoother: type": "symmetric Gauss-Seidel", + } diff --git a/fipy/solvers/trilinos/preconditioners/multilevelSolverSmootherPreconditioner.py b/fipy/solvers/trilinos/preconditioners/multilevelSolverSmootherPreconditioner.py index 956e7b1b66..254df0e46e 100644 --- a/fipy/solvers/trilinos/preconditioners/multilevelSolverSmootherPreconditioner.py +++ b/fipy/solvers/trilinos/preconditioners/multilevelSolverSmootherPreconditioner.py @@ -3,31 +3,21 @@ from PyTrilinos import ML -from fipy.solvers.trilinos.preconditioners.preconditioner import Preconditioner +from .multilevelPreconditioner import MultilevelPreconditioner __all__ = ["MultilevelSolverSmootherPreconditioner"] from future.utils import text_to_native_str __all__ = [text_to_native_str(n) for n in __all__] -class MultilevelSolverSmootherPreconditioner(Preconditioner): +class MultilevelSolverSmootherPreconditioner(MultilevelPreconditioner): + """Multilevel preconditioner using Aztec solvers as smoothers for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. """ - Multilevel preconditioner for Trilinos solvers using Aztec solvers - as smoothers. - """ - def __init__(self, levels=10): - """ - Initialize the multilevel preconditioner - - - `levels`: Maximum number of levels - """ - self.levels = levels - - def _applyToSolver(self, solver, matrix): - if matrix.NumGlobalNonzeros() <= matrix.NumGlobalRows(): - return - - self.Prec = ML.MultiLevelPreconditioner(matrix, False) - self.Prec.SetParameterList({text_to_native_str("output"): 0, text_to_native_str("smoother: type") : text_to_native_str("Aztec"), text_to_native_str("smoother: Aztec as solver") : True}) - self.Prec.ComputePreconditioner() - solver.SetPrecOperator(self.Prec) + @property + def _parameterList(self): + return { + "output": 0, + "max levels": self.levels, + "smoother: type": "Aztec", + "smoother: Aztec as solver": True + } diff --git a/fipy/solvers/trilinos/preconditioners/preconditioner.py b/fipy/solvers/trilinos/preconditioners/preconditioner.py deleted file mode 100644 index 6e516f7e2c..0000000000 --- a/fipy/solvers/trilinos/preconditioners/preconditioner.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -from builtins import object -__docformat__ = 'restructuredtext' - -__all__ = ["Preconditioner"] -from future.utils import text_to_native_str -__all__ = [text_to_native_str(n) for n in __all__] - -class Preconditioner(object): - """ - The base Preconditioner class. - - .. attention:: This class is abstract. Always create one of its subclasses. - """ - - def _applyToSolver(self, solver, matrix): - raise NotImplementedError diff --git a/fipy/solvers/trilinos/preconditioners/trilinosPreconditioner.py b/fipy/solvers/trilinos/preconditioners/trilinosPreconditioner.py new file mode 100644 index 0000000000..597765e01e --- /dev/null +++ b/fipy/solvers/trilinos/preconditioners/trilinosPreconditioner.py @@ -0,0 +1,16 @@ +from __future__ import unicode_literals +__docformat__ = 'restructuredtext' + +from fipy.solvers.preconditioner import SolverModifyingPreconditioner + +__all__ = ["TrilinosPreconditioner"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +class TrilinosPreconditioner(SolverModifyingPreconditioner): + """Base class of preconditioners for :class:`~fipy.solvers.trilinos.trilinosSolver.TrilinosSolver`. + + .. attention:: This class is abstract. Always create one of its subclasses. + """ + + pass