Exemple #1
0
    def configure_pmg(self, snes, pdm):
        odm = snes.getDM()
        psnes = PETSc.SNES().create(comm=snes.comm)
        psnes.setOptionsPrefix(snes.getOptionsPrefix() + "pfas_")
        psnes.setType("fas")
        psnes.setDM(pdm)
        psnes.incrementTabLevel(1, parent=snes)

        (f, residual) = snes.getFunction()
        assert residual is not None
        (fun, args, kargs) = residual
        psnes.setFunction(fun, f.duplicate(), args=args, kargs=kargs)

        pdm.setGlobalVector(f.duplicate())
        self.dummy = f.duplicate()
        psnes.setSolution(f.duplicate())

        # PETSc unfortunately requires us to make an ugly hack.
        # We would like to use GMG for the coarse solve, at least
        # sometimes. But PETSc will use this p-DM's getRefineLevels()
        # instead of the getRefineLevels() of the MeshHierarchy to
        # decide how many levels it should use for PCMG applied to
        # the p-MG's coarse problem. So we need to set an option
        # for the user, if they haven't already; I don't know any
        # other way to get PETSc to know this at the right time.
        opts = PETSc.Options(snes.getOptionsPrefix() + "pfas_")
        if "fas_coarse_pc_mg_levels" not in opts:
            opts["fas_coarse_pc_mg_levels"] = odm.getRefineLevel() + 1
        if "fas_coarse_snes_fas_levels" not in opts:
            opts["fas_coarse_snes_fas_levels"] = odm.getRefineLevel() + 1

        return psnes
    def __init__(self, problem, **kwargs):
        r"""
        :arg problem: A :class:`NonlinearVariationalProblem` to solve.
        :kwarg nullspace: an optional :class:`.VectorSpaceBasis` (or
               :class:`.MixedVectorSpaceBasis`) spanning the null
               space of the operator.
        :kwarg transpose_nullspace: as for the nullspace, but used to
               make the right hand side consistent.
        :kwarg near_nullspace: as for the nullspace, but used to
               specify the near nullspace (for multigrid solvers).
        :kwarg solver_parameters: Solver parameters to pass to PETSc.
               This should be a dict mapping PETSc options to values.
        :kwarg appctx: A dictionary containing application context that
               is passed to the preconditioner if matrix-free.
        :kwarg options_prefix: an optional prefix used to distinguish
               PETSc options.  If not provided a unique prefix will be
               created.  Use this option if you want to pass options
               to the solver from the command line in addition to
               through the ``solver_parameters`` dict.
        :kwarg pre_jacobian_callback: A user-defined function that will
               be called immediately before Jacobian assembly. This can
               be used, for example, to update a coefficient function
               that has a complicated dependence on the unknown solution.
        :kwarg pre_function_callback: As above, but called immediately
               before residual assembly

        Example usage of the ``solver_parameters`` option: to set the
        nonlinear solver type to just use a linear solver, use

        .. code-block:: python

            {'snes_type': 'ksponly'}

        PETSc flag options (where the presence of the option means something) should
        be specified with ``None``.
        For example:

        .. code-block:: python

            {'snes_monitor': None}

        To use the ``pre_jacobian_callback`` or ``pre_function_callback``
        functionality, the user-defined function must accept the current
        solution as a petsc4py Vec. Example usage is given below:

        .. code-block:: python

            def update_diffusivity(current_solution):
                with cursol.dat.vec_wo as v:
                    current_solution.copy(v)
                solve(trial*test*dx == dot(grad(cursol), grad(test))*dx, diffusivity)

            solver = NonlinearVariationalSolver(problem,
                                                pre_jacobian_callback=update_diffusivity)

        """
        assert isinstance(problem, NonlinearVariationalProblem)

        parameters = kwargs.get("solver_parameters")
        if "parameters" in kwargs:
            raise TypeError("Use solver_parameters, not parameters")
        nullspace = kwargs.get("nullspace")
        nullspace_T = kwargs.get("transpose_nullspace")
        near_nullspace = kwargs.get("near_nullspace")
        options_prefix = kwargs.get("options_prefix")
        pre_j_callback = kwargs.get("pre_jacobian_callback")
        pre_f_callback = kwargs.get("pre_function_callback")

        super(NonlinearVariationalSolver,
              self).__init__(parameters, options_prefix)

        # Allow anything, interpret "matfree" as matrix_free.
        mat_type = self.parameters.get("mat_type")
        pmat_type = self.parameters.get("pmat_type")
        matfree = mat_type == "matfree"
        pmatfree = pmat_type == "matfree"

        appctx = kwargs.get("appctx")

        ctx = solving_utils._SNESContext(problem,
                                         mat_type=mat_type,
                                         pmat_type=pmat_type,
                                         appctx=appctx,
                                         pre_jacobian_callback=pre_j_callback,
                                         pre_function_callback=pre_f_callback,
                                         options_prefix=self.options_prefix)

        # No preconditioner by default for matrix-free
        if (problem.Jp is not None and pmatfree) or matfree:
            self.set_default_parameter("pc_type", "none")
        elif ctx.is_mixed:
            # Mixed problem, use jacobi pc if user has not supplied
            # one.
            self.set_default_parameter("pc_type", "jacobi")

        self.snes = PETSc.SNES().create(comm=problem.dm.comm)

        self._problem = problem

        self._ctx = ctx
        self._work = problem.u.dof_dset.layout_vec.duplicate()
        self.snes.setDM(problem.dm)

        ctx.set_function(self.snes)
        ctx.set_jacobian(self.snes)
        ctx.set_nullspace(nullspace,
                          problem.J.arguments()[0].function_space()._ises,
                          transpose=False,
                          near=False)
        ctx.set_nullspace(nullspace_T,
                          problem.J.arguments()[1].function_space()._ises,
                          transpose=True,
                          near=False)
        ctx.set_nullspace(near_nullspace,
                          problem.J.arguments()[0].function_space()._ises,
                          transpose=False,
                          near=True)
        ctx._nullspace = nullspace
        ctx._nullspace_T = nullspace_T
        ctx._near_nullspace = near_nullspace

        # Set from options now, so that people who want to noodle with
        # the snes object directly (mostly Patrick), can.  We need the
        # DM with an app context in place so that if the DM is active
        # on a subKSP the context is available.
        dm = self.snes.getDM()
        with dmhooks.appctx(dm, self._ctx):
            self.set_from_options(self.snes)

        # Used for custom grid transfer.
        self._transfer_operators = ()
        self._setup = False
    def __init__(self, problem, **kwargs):
        """
        :arg problem: A :class:`NonlinearVariationalProblem` to solve.
        :kwarg nullspace: an optional :class:`.VectorSpaceBasis` (or
               :class:`.MixedVectorSpaceBasis`) spanning the null
               space of the operator.
        :kwarg solver_parameters: Solver parameters to pass to PETSc.
            This should be a dict mapping PETSc options to values.  For
            example, to set the nonlinear solver type to just use a linear
            solver:
        :kwarg options_prefix: an optional prefix used to distinguish
               PETSc options.  If not provided a unique prefix will be
               created.  Use this option if you want to pass options
               to the solver from the command line in addition to
               through the ``solver_parameters`` dict.

        .. code-block:: python

            {'snes_type': 'ksponly'}

        PETSc flag options should be specified with `bool` values. For example:

        .. code-block:: python

            {'snes_monitor': True}
        """
        parameters, nullspace, options_prefix = solving_utils._extract_kwargs(
            **kwargs)

        # Do this first so __del__ doesn't barf horribly if we get an
        # error in __init__
        if options_prefix is not None:
            self._opt_prefix = options_prefix
            self._auto_prefix = False
        else:
            self._opt_prefix = 'firedrake_snes_%d_' % NonlinearVariationalSolver._id
            self._auto_prefix = True
            NonlinearVariationalSolver._id += 1

        assert isinstance(problem, NonlinearVariationalProblem)

        ctx = solving_utils._SNESContext(problem)

        self.snes = PETSc.SNES().create()

        self.snes.setOptionsPrefix(self._opt_prefix)

        # Mixed problem, use jacobi pc if user has not supplied one.
        if ctx.is_mixed:
            parameters.setdefault('pc_type', 'jacobi')

        # Allow command-line arguments to override dict parameters
        opts = PETSc.Options()
        for k, v in opts.getAll().iteritems():
            if k.startswith(self._opt_prefix):
                parameters[k[len(self._opt_prefix):]] = v

        self._problem = problem

        self._ctx = ctx
        self.snes.setDM(problem.dm)

        ctx.set_function(self.snes)
        ctx.set_jacobian(self.snes)
        ctx.set_nullspace(nullspace,
                          problem.J.arguments()[0].function_space()._ises)

        self.parameters = parameters
Exemple #4
0
    def __init__(self, problem, **kwargs):
        """
        Solve a :class:`NonlinearVariationalProblem` on a hierarchy of meshes.

        :arg problem: A :class:`NonlinearVariationalProblem` or
             iterable thereof (if specifying the problem on each level
             by hand).
        :kwarg nullspace: an optional :class:`.VectorSpaceBasis` (or
             :class:`MixedVectorSpaceBasis`) spanning the null space of the
             operator.
        :kwarg solver_parameters: Solver parameters to pass to PETSc.
            This should be a dict mapping PETSc options to values.
            PETSc flag options should be specified with `bool`
            values (:data:`True` for on, :data:`False` for off).
        :kwarg options_prefix: an optional prefix used to distinguish
               PETSc options.  If not provided a unique prefix will be
               created.  Use this option if you want to pass options
               to the solver from the command line in addition to
               through the :data:`solver_parameters` dict.

        .. note::

           This solver is set up for use with geometric multigrid,
           that is you can use :data:`"snes_type": "fas"` or
           :data:`"pc_type": "mg"` transparently.
        """
        # Do this first so __del__ doesn't barf horribly if we get an
        # error in __init__
        parameters, nullspace, options_prefix \
            = firedrake.solving_utils._extract_kwargs(**kwargs)

        if options_prefix is not None:
            self._opt_prefix = options_prefix
            self._auto_prefix = False
        else:
            self._opt_prefix = "firedrake_nlvsh_%d_" % NLVSHierarchy._id
            self._auto_prefix = True
            NLVSHierarchy._id += 1

        if isinstance(problem, firedrake.NonlinearVariationalProblem):
            # We just got a single problem so coarsen up the hierarchy
            problems = []
            while True:
                if problem:
                    problems.append(problem)
                else:
                    break
                problem = coarsen_problem(problem)
            problems.reverse()
        else:
            # User has provided list of problems
            problems = problem
        ctx = firedrake.solving_utils._SNESContext(problems)

        if nullspace is not None:
            raise NotImplementedError(
                "Coarsening nullspaces no yet implemented")
        snes = PETSc.SNES().create()

        snes.setDM(problems[-1].dm)
        self.problems = problems
        self.snes = snes
        self.ctx = ctx
        self.ctx.set_function(self.snes)
        self.ctx.set_jacobian(self.snes)

        self.snes.setOptionsPrefix(self._opt_prefix)

        # Allow command-line arguments to override dict parameters
        opts = PETSc.Options()
        for k, v in opts.getAll().iteritems():
            if k.startswith(self._opt_prefix):
                parameters[k[len(self._opt_prefix):]] = v

        self.parameters = parameters