Пример #1
0
    class CHProblem(NonlinearProblem):
        """Class for interfacing with :py:class:`dolfin.NewtonSolver`."""
        def __init__(self, F, bcs, J):
            super(SemiDecoupled.CHProblem, self).__init__()

            # Assembler for Newton system
            self.assembler = SystemAssembler(J, F, bcs)

            # Store forms for later
            self.forms = {
                "F": F,
                "J": J,
            }

        def function_space(self):
            return self.forms["F"].arguments()[0].function_space()

        def form(self, A, P, b, x):
            if A.empty():
                matA = as_backend_type(A).mat()
                assert not matA.isAssembled()
                bs = self.function_space().dofmap().block_size()
                matA.setBlockSize(bs)
                # matP = as_backend_type(P).mat()
                # assert not matP.isAssembled()
                # matP.setBlockSize(bs)

        def F(self, b, x):
            self.assembler.assemble(b, x)

        def J(self, A, x):
            # matA = as_backend_type(A).mat()
            # bs = self.function_space().dofmap().block_size()
            # assert matA.getBlockSize() == bs
            self.assembler.assemble(A)
Пример #2
0
    def __init__(self, F, bcs, J, J_pc=None):
        """Return subclass of :py:class:`dolfin.NonlinearProblem`
        suitable for :py:class:`NewtonSolver` in combination with
        :py:class:`muflon.solving.solvers.SemiDecoupled`.
        """
        super(CHNonlinearProblem, self).__init__()

        # Assembler for Newton system
        self.assembler = SystemAssembler(J, F, bcs)

        # Assembler for preconditioner
        if J_pc is not None:
            self.assembler_pc = SystemAssembler(J_pc, F, bcs)
        else:
            self.assembler_pc = None

        # Store bcs
        self._bcs = bcs

        # Store forms for later
        self.forms = {
            "F": F,
            "J": J,
            "J_pc": J_pc,
        }
Пример #3
0
 def __init__(self, a, L, bcs, a_pc=None):
     self.assembler = SystemAssembler(a, L, bcs)
     if a_pc is not None:
         self.assembler_pc = SystemAssembler(a_pc, L, bcs)
     else:
         self.assembler_pc = None
     self._bcs = bcs
Пример #4
0
        def __init__(self, F, bcs, J):
            super(SemiDecoupled.CHProblem, self).__init__()

            # Assembler for Newton system
            self.assembler = SystemAssembler(J, F, bcs)

            # Store forms for later
            self.forms = {
                "F": F,
                "J": J,
            }
Пример #5
0
    def __init__(self, problem, parameters={}, lb=None):
        super(DamageSolverSNES, self).__init__()
        self.problem = problem
        self.energy = problem.energy
        self.state = problem.state
        self.alpha = problem.state['alpha']
        self.alpha_dvec = as_backend_type(self.alpha.vector())
        self.alpha_pvec = self.alpha_dvec.vec()

        self.bcs = problem.bcs
        self.parameters = parameters
        comm = self.alpha.function_space().mesh().mpi_comm()
        self.comm = comm
        V = self.alpha.function_space()
        self.V = V
        self.Ealpha = derivative(
            self.energy, self.alpha,
            dolfin.TestFunction(self.alpha.ufl_function_space()))
        self.dm = self.alpha.function_space().dofmap()
        solver = PETScSNESSolver()
        snes = solver.snes()

        if lb == None:
            lb = interpolate(Constant(0.), V)
        ub = interpolate(Constant(1.), V)

        prefix = "damage_"
        snes.setOptionsPrefix(prefix)
        for option, value in self.parameters["snes"].items():
            PETScOptions.set(prefix + option, value)
            log(LogLevel.DEBUG,
                "DEBUG: Set: {} = {}".format(prefix + option, value))

        snes.setFromOptions()

        (J, F, bcs_alpha) = (problem.J, problem.F, problem.bcs)
        self.ass = SystemAssembler(J, F, bcs_alpha)
        self.b = self.init_residual()
        snes.setFunction(self.residual, self.b.vec())
        self.A = self.init_jacobian()
        snes.setJacobian(self.jacobian, self.A.mat())
        snes.ksp.setOperators(self.A.mat())

        snes.setVariableBounds(self.problem.lb.vec(), self.problem.ub.vec())  #

        # snes.solve(None, Function(V).vector().vec())

        self.solver = snes
Пример #6
0
    class Problem(NonlinearProblem):
        """
        Class for interfacing with :py:class:`NewtonSolver`.
        """
        def __init__(self, F, bcs, J, null_space=None):
            super(Monolithic.Problem, self).__init__()
            self.assembler = SystemAssembler(J, F, bcs)
            self.null_space = null_space

        def F(self, b, x):
            self.assembler.assemble(b, x)
            if self.null_space:
                # Orthogonalize RHS vector b with respect to the null space
                self.null_space.orthogonalize(b)

        def J(self, A, x):
            self.assembler.assemble(A)
            if self.null_space:
                # Attach null space to PETSc matrix
                as_backend_type(A).set_nullspace(self.null_space)
Пример #7
0
class CHNonlinearProblem(NonlinearProblem):
    """Class for interfacing with :py:class:`CHNewtonSolver`."""
    def __init__(self, F, bcs, J, J_pc=None):
        """Return subclass of :py:class:`dolfin.NonlinearProblem`
        suitable for :py:class:`NewtonSolver` in combination with
        :py:class:`muflon.solving.solvers.SemiDecoupled`.
        """
        super(CHNonlinearProblem, self).__init__()

        # Assembler for Newton system
        self.assembler = SystemAssembler(J, F, bcs)

        # Assembler for preconditioner
        if J_pc is not None:
            self.assembler_pc = SystemAssembler(J_pc, F, bcs)
        else:
            self.assembler_pc = None

        # Store bcs
        self._bcs = bcs

        # Store forms for later
        self.forms = {
            "F": F,
            "J": J,
            "J_pc": J_pc,
        }

    def get_form(self, key):
        form = self.forms.get(key)
        if form is None:
            raise AttributeError("Form '%s' not available" % key)
        return form

    def function_space(self):
        return self.forms["F"].arguments()[0].function_space()

    def form(self, A, P, b, x):
        if A.empty():
            matA = as_backend_type(A).mat()
            assert not matA.isAssembled()
            bs = self.function_space().dofmap().block_size()
            matA.setBlockSize(bs)
            if self.assembler_pc is not None and P.empty():
                matP = as_backend_type(P).mat()
                assert not matP.isAssembled()
                matP.setBlockSize(bs)

    def F(self, b, x):
        self.assembler.assemble(b, x)

    def J(self, A, x):
        self.assembler.assemble(A)

    def J_pc(self, P, x):
        if self.assembler_pc is not None:
            self.assembler_pc.assemble(P)
Пример #8
0
class rmtursAssembler(object):
    def __init__(self, a, L, bcs, a_pc=None):
        self.assembler = SystemAssembler(a, L, bcs)
        if a_pc is not None:
            self.assembler_pc = SystemAssembler(a_pc, L, bcs)
        else:
            self.assembler_pc = None
        self._bcs = bcs

    def rhs_vector(self, b, x=None):
        if x is not None:
            self.assembler.assemble(b, x)
        else:
            self.assembler.assemble(b)

    def system_matrix(self, A):
        self.assembler.assemble(A)

    def pc_matrix(self, P):
        if self.assembler_pc is not None:
            self.assembler_pc.assemble(P)
Пример #9
0
 def __init__(self, F, bcs, J, null_space=None):
     super(Monolithic.Problem, self).__init__()
     self.assembler = SystemAssembler(J, F, bcs)
     self.null_space = null_space
Пример #10
0
class DamageSolverSNES:
    """docstring for DamageSolverSNES"""
    def __init__(self, problem, parameters={}, lb=None):
        super(DamageSolverSNES, self).__init__()
        self.problem = problem
        self.energy = problem.energy
        self.state = problem.state
        self.alpha = problem.state['alpha']
        self.alpha_dvec = as_backend_type(self.alpha.vector())
        self.alpha_pvec = self.alpha_dvec.vec()

        self.bcs = problem.bcs
        self.parameters = parameters
        comm = self.alpha.function_space().mesh().mpi_comm()
        self.comm = comm
        V = self.alpha.function_space()
        self.V = V
        self.Ealpha = derivative(
            self.energy, self.alpha,
            dolfin.TestFunction(self.alpha.ufl_function_space()))
        self.dm = self.alpha.function_space().dofmap()
        solver = PETScSNESSolver()
        snes = solver.snes()

        if lb == None:
            lb = interpolate(Constant(0.), V)
        ub = interpolate(Constant(1.), V)

        prefix = "damage_"
        snes.setOptionsPrefix(prefix)
        for option, value in self.parameters["snes"].items():
            PETScOptions.set(prefix + option, value)
            log(LogLevel.DEBUG,
                "DEBUG: Set: {} = {}".format(prefix + option, value))

        snes.setFromOptions()

        (J, F, bcs_alpha) = (problem.J, problem.F, problem.bcs)
        self.ass = SystemAssembler(J, F, bcs_alpha)
        self.b = self.init_residual()
        snes.setFunction(self.residual, self.b.vec())
        self.A = self.init_jacobian()
        snes.setJacobian(self.jacobian, self.A.mat())
        snes.ksp.setOperators(self.A.mat())

        snes.setVariableBounds(self.problem.lb.vec(), self.problem.ub.vec())  #

        # snes.solve(None, Function(V).vector().vec())

        self.solver = snes

    def update_x(self, x):
        """
        Given a PETSc Vec x, update the storage of our solution function alpha.
        """
        x.copy(self.alpha_pvec)
        self.alpha_dvec.update_ghost_values()

    def init_residual(self):
        alpha = self.problem.state["alpha"]
        b = as_backend_type(Function(alpha.function_space()).vector())
        return b

    def init_jacobian(self):
        A = PETScMatrix(self.comm)
        self.ass.init_global_tensor(A, Form(self.problem.J))
        return A

    def residual(self, snes, x, b):
        self.update_x(x)
        b_wrap = PETScVector(b)
        self.ass.assemble(b_wrap, self.alpha_dvec)

    def jacobian(self, snes, x, A, P):
        self.update_x(x)
        A_wrap = PETScMatrix(A)
        self.ass.assemble(A_wrap)

    def solve(self):
        alpha = self.problem.state["alpha"]
        # Need a copy for line searches etc. to work correctly.
        x = alpha.copy(deepcopy=True)
        xv = as_backend_type(x.vector()).vec()
        # Solve the problem
        self.solver.solve(None, xv)

    def inactive_set_indicator(self, tol=1.0e-5):
        Ealpha = assemble(self.Ealpha)

        mask_grad = Ealpha[:] < tol
        mask_ub = self.alpha.vector()[:] < 1. - tol
        mask_lb = self.alpha.vector()[:] > self.problem.lb[:] + tol

        local_inactive_set_alpha = set(np.where(mask_ub == True)[0])    \
            & set(np.where(mask_grad == True)[0])                       \
            & set(np.where(mask_lb == True)[0])

        _set_alpha = [
            self.dm.local_to_global_index(k) for k in local_inactive_set_alpha
        ]
        inactive_set_alpha = set(_set_alpha) | set(self.dm.dofs())

        index_set = petsc4py.PETSc.IS()
        index_set.createGeneral(list(inactive_set_alpha))

        return index_set
Пример #11
0
    def __init__(self, a, L, bcs, a_pc=None,
                 mp=None, mu=None, ap=None, fp=None, kp=None, gp=None,
                 bcs_pcd=[]):
        """Collect individual variational forms and boundary conditions
        defining a linear problem (system matrix + RHS vector) on the one side
        and preconditioning operators on the other side.

        *Arguments*
            a (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear form representing a system matrix.
            L (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Linear form representing a right hand side vector.
            bcs (:py:class:`list` of :py:class:`dolfin.DirichletBC`)
                Boundary conditions applied to ``a``, ``L``, and ``a_pc``.
            a_pc (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear form representing a matrix optionally passed to
                preconditioner instead of ``a``. In case of PCD, stabilized
                00-block can be passed to 00-KSP solver.
            mp, mu, ap, fp, kp, gp (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear forms which (some of them) might be used by a
                particular PCD(R) preconditioner. Typically they represent "mass
                matrix" on pressure, "mass matrix" on velocity, minus Laplacian
                operator on pressure, pressure convection-diffusion operator,
                pressure convection operator and pressure gradient respectively.
            bcs_pcd (:py:class:`list` of :py:class:`dolfin.DirichletBC`)
                Artificial boundary conditions used by PCD preconditioner.

        All the arguments should be given on the common mixed function space.

        All the forms are wrapped using :py:class:`PCDForm` so that each of
        them can be endowed with additional set of properties.

        By default, ``mp``, ``mu``, ``ap`` and ``gp`` are assumed to be
        constant if the preconditioner is used repeatedly in some outer
        iterative process (e.g Newton-Raphson method, time-stepping).
        As such, the corresponding operators are assembled only once.
        On the other hand, ``fp`` and ``kp`` are updated in every
        outer iteration.

        Also note that ``gp`` is the only form that is by default in a *phantom
        mode*. It means that the corresponding operator (if needed) is not
        obtained by assembling the form, but it is extracted as the 01-block of
        the system matrix.

        The default setting can be modified by accessing
        a :py:class:`PCDForm` instance via :py:meth:`PCDAssembler.get_pcd_form`
        and changing the properties directly.
        """

        # Assembler for the linear system of algebraic equations
        self.assembler = SystemAssembler(a, L, bcs)

        # Assembler for preconditioner
        if a_pc is not None:
            self.assembler_pc = SystemAssembler(a_pc, L, bcs)
        else:
            self.assembler_pc = None

        # Store bcs
        self._bcs = bcs
        self._bcs_pcd = bcs_pcd

        # Store and initialize forms
        self._forms = {
            "L": PCDForm(L),
            "ap": PCDForm(ap, const=True),
            "mp": PCDForm(mp, const=True),
            "mu": PCDForm(mu, const=True),
            "fp": PCDForm(fp),
            "kp": PCDForm(kp),
            "gp": PCDForm(gp, const=True, phantom=True),
        }
Пример #12
0
class PCDAssembler(object):
    """Base class for creating linear problems to be solved by application
    of the PCD preconditioning strategy. Users are encouraged to use this class
    for interfacing with :py:class:`fenapack.field_split.PCDKrylovSolver`.
    On request it assembles not only the individual PCD operators but also the
    system matrix and the right hand side vector defining the linear problem.
    """

    def __init__(self, a, L, bcs, a_pc=None,
                 mp=None, mu=None, ap=None, fp=None, kp=None, gp=None,
                 bcs_pcd=[]):
        """Collect individual variational forms and boundary conditions
        defining a linear problem (system matrix + RHS vector) on the one side
        and preconditioning operators on the other side.

        *Arguments*
            a (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear form representing a system matrix.
            L (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Linear form representing a right hand side vector.
            bcs (:py:class:`list` of :py:class:`dolfin.DirichletBC`)
                Boundary conditions applied to ``a``, ``L``, and ``a_pc``.
            a_pc (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear form representing a matrix optionally passed to
                preconditioner instead of ``a``. In case of PCD, stabilized
                00-block can be passed to 00-KSP solver.
            mp, mu, ap, fp, kp, gp (:py:class:`dolfin.Form` or :py:class:`ufl.Form`)
                Bilinear forms which (some of them) might be used by a
                particular PCD(R) preconditioner. Typically they represent "mass
                matrix" on pressure, "mass matrix" on velocity, minus Laplacian
                operator on pressure, pressure convection-diffusion operator,
                pressure convection operator and pressure gradient respectively.
            bcs_pcd (:py:class:`list` of :py:class:`dolfin.DirichletBC`)
                Artificial boundary conditions used by PCD preconditioner.

        All the arguments should be given on the common mixed function space.

        All the forms are wrapped using :py:class:`PCDForm` so that each of
        them can be endowed with additional set of properties.

        By default, ``mp``, ``mu``, ``ap`` and ``gp`` are assumed to be
        constant if the preconditioner is used repeatedly in some outer
        iterative process (e.g Newton-Raphson method, time-stepping).
        As such, the corresponding operators are assembled only once.
        On the other hand, ``fp`` and ``kp`` are updated in every
        outer iteration.

        Also note that ``gp`` is the only form that is by default in a *phantom
        mode*. It means that the corresponding operator (if needed) is not
        obtained by assembling the form, but it is extracted as the 01-block of
        the system matrix.

        The default setting can be modified by accessing
        a :py:class:`PCDForm` instance via :py:meth:`PCDAssembler.get_pcd_form`
        and changing the properties directly.
        """

        # Assembler for the linear system of algebraic equations
        self.assembler = SystemAssembler(a, L, bcs)

        # Assembler for preconditioner
        if a_pc is not None:
            self.assembler_pc = SystemAssembler(a_pc, L, bcs)
        else:
            self.assembler_pc = None

        # Store bcs
        self._bcs = bcs
        self._bcs_pcd = bcs_pcd

        # Store and initialize forms
        self._forms = {
            "L": PCDForm(L),
            "ap": PCDForm(ap, const=True),
            "mp": PCDForm(mp, const=True),
            "mu": PCDForm(mu, const=True),
            "fp": PCDForm(fp),
            "kp": PCDForm(kp),
            "gp": PCDForm(gp, const=True, phantom=True),
        }


    def get_pcd_form(self, key):
        """Return form wrapped in :py:class:`PCDForm`."""
        form = self._forms.get(key)
        if form is None:
            raise AttributeError("Form '%s' requested by PCD not available" % key)
        assert isinstance(form, PCDForm)
        return form


    def get_dolfin_form(self, key):
        """Return form as :py:class:`dolfin.Form` or :py:class:`ufl.Form`."""
        return self.get_pcd_form(key).dolfin_form()


    def function_space(self):
        return self.get_dolfin_form("L").arguments()[0].function_space()


    def rhs_vector(self, b, x=None):
        """Assemble right hand side vector ``b``.

        The version with ``x`` is suitable for use inside
        a (quasi)-Newton solver.
        """
        if x is not None:
            self.assembler.assemble(b, x)
        else:
            self.assembler.assemble(b)

    def system_matrix(self, A):
        """Assemble system matrix ``A``."""
        self.assembler.assemble(A)


    def pc_matrix(self, P):
        """Assemble preconditioning matrix ``P`` whose relevant blocks can be
        passed to actual parts of the ``KSP`` solver.
        """
        if self.assembler_pc is not None:
            self.assembler_pc.assemble(P)


    def ap(self, Ap):
        assembler = SystemAssembler(self.get_dolfin_form("ap"),
                                    self.get_dolfin_form("L"),
                                    self.pcd_bcs())
        assembler.assemble(Ap)


    def mp(self, Mp):
        assemble(self.get_dolfin_form("mp"), tensor=Mp)


    def mu(self, Mu):
        assemble(self.get_dolfin_form("mu"), tensor=Mu)


    def fp(self, Fp):
        assemble(self.get_dolfin_form("fp"), tensor=Fp)


    def kp(self, Kp):
        assemble(self.get_dolfin_form("kp"), tensor=Kp)


    def gp(self, Bt):
        """Assemble discrete pressure gradient. It is crucial to respect any
        constraints placed on the velocity test space by Dirichlet boundary
        conditions."""
        assemble(self.get_dolfin_form("gp"), tensor=Bt)
        for bc in self._bcs:
            bc.apply(Bt)


    # FIXME: Naming
    def pcd_bcs(self):
        try:
            assert self._bcs_pcd is not None
        except (AttributeError, AssertionError):
            raise AttributeError("BCs requested by PCD not available")
        return self._bcs_pcd
Пример #13
0
 def ap(self, Ap):
     assembler = SystemAssembler(self.get_dolfin_form("ap"),
                                 self.get_dolfin_form("L"),
                                 self.pcd_bcs())
     assembler.assemble(Ap)