예제 #1
0
파일: norms.py 프로젝트: zxdhpc/firedrake
def errornorm(u, uh, norm_type="L2", degree_rise=None, mesh=None):
    """Compute the error :math:`e = u - u_h` in the specified norm.

    :arg u: a :class:`.Function` or UFL expression containing an "exact" solution
    :arg uh: a :class:`.Function` containing the approximate solution
    :arg norm_type: the type of norm to compute, see :func:`.norm` for
         details of supported norm types.
    :arg degree_rise: ignored.
    :arg mesh: an optional mesh on which to compute the error norm
         (currently ignored).
    """
    urank = len(u.ufl_shape)
    uhrank = len(uh.ufl_shape)

    if urank != uhrank:
        raise RuntimeError("Mismatching rank between u and uh")

    if not isinstance(uh, function.Function):
        raise ValueError("uh should be a Function, is a %r", type(uh))

    if isinstance(u, function.Function):
        degree_u = u.function_space().ufl_element().degree()
        degree_uh = uh.function_space().ufl_element().degree()
        if degree_uh > degree_u:
            warning("Degree of exact solution less than approximation degree")

    return norm(u - uh, norm_type=norm_type, mesh=mesh)
예제 #2
0
def _form_string_kernel(body, measure, args, **kwargs):
    kargs = []
    if body.find("][") >= 0:
        warning("""Your kernel body contains a double indirection.\n"""
                """You should update it to single indirections.\n"""
                """\n"""
                """Mail [email protected] for advice.\n""")
    for var, (func, intent) in args.items():
        if isinstance(func, constant.Constant):
            if intent is not READ:
                raise RuntimeError("Only READ access is allowed to Constant")
            # Constants modelled as Globals, so no need for double
            # indirection
            ndof = func.dat.cdim
            kargs.append(ast.Decl(ScalarType_c, ast.Symbol(var, (ndof, )),
                                  qualifiers=["const"]))
        else:
            # Do we have a component of a mixed function?
            if isinstance(func, Indexed):
                c, i = func.ufl_operands
                idx = i._indices[0]._value
                ndof = c.function_space()[idx].finat_element.space_dimension()
            else:
                if len(func.function_space()) > 1:
                    raise NotImplementedError("Must index mixed function in par_loop.")
                ndof = func.function_space().finat_element.space_dimension()
            if measure.integral_type() == 'interior_facet':
                ndof *= 2
            kargs.append(ast.Decl(ScalarType_c, ast.Symbol(var, (ndof, ))))
        body = body.replace(var+".dofs", str(ndof))

    return pyop2.Kernel(ast.FunDecl("void", "par_loop_kernel", kargs,
                                    ast.FlatBlock(body),
                                    pred=["static"]),
                        "par_loop_kernel", **kwargs)
예제 #3
0
def _form_string_kernel(body, measure, args, **kwargs):
    kargs = []
    if body.find("][") >= 0:
        warning("""Your kernel body contains a double indirection.\n"""
                """You should update it to single indirections.\n"""
                """\n"""
                """Mail [email protected] for advice.\n""")
    for var, (func, intent) in args.items():
        if isinstance(func, constant.Constant):
            if intent is not READ:
                raise RuntimeError("Only READ access is allowed to Constant")
            # Constants modelled as Globals, so no need for double
            # indirection
            ndof = func.dat.cdim
            kargs.append(ast.Decl("double", ast.Symbol(var, (ndof, )),
                                  qualifiers=["const"]))
        else:
            # Do we have a component of a mixed function?
            if isinstance(func, Indexed):
                c, i = func.ufl_operands
                idx = i._indices[0]._value
                ndof = c.function_space()[idx].finat_element.space_dimension()
            else:
                if len(func.function_space()) > 1:
                    raise NotImplementedError("Must index mixed function in par_loop.")
                ndof = func.function_space().finat_element.space_dimension()
            if measure.integral_type() == 'interior_facet':
                ndof *= 2
            kargs.append(ast.Decl("double", ast.Symbol(var, (ndof, ))))
        body = body.replace(var+".dofs", str(ndof))

    return pyop2.Kernel(ast.FunDecl("void", "par_loop_kernel", kargs,
                                    ast.FlatBlock(body),
                                    pred=["static"]),
                        "par_loop_kernel", **kwargs)
예제 #4
0
def TensorFunctionSpaceHierarchy(mesh_hierarchy, *args, **kwargs):
    from firedrake.logging import warning, RED
    warning(
        RED %
        "TensorFunctionSpaceHierarchy is obsolete. Just build a FunctionSpace on the relevant mesh"
    )

    return tuple(
        firedrake.TensorFunctionSpace(mesh, *args, **kwargs)
        for mesh in mesh_hierarchy)
예제 #5
0
    def get_patches(self, V):
        mesh = V._mesh
        mesh_dm = mesh.topology_dm
        if mesh.layers:
            warning("applying ASMVankaPC on an extruded mesh")

        # Obtain the topological entities to use to construct the stars
        depth = PETSc.Options().getInt(self.prefix + "construct_dim", default=-1)
        height = PETSc.Options().getInt(self.prefix + "construct_codim", default=-1)
        if (depth == -1 and height == -1) or (depth != -1 and height != -1):
            raise ValueError(f"Must set exactly one of {self.prefix}construct_dim or {self.prefix}construct_codim")

        # Accessing .indices causes the allocation of a global array,
        # so we need to cache these for efficiency
        V_local_ises_indices = []
        for (i, W) in enumerate(V):
            V_local_ises_indices.append(V.dof_dset.local_ises[i].indices)

        # Build index sets for the patches
        ises = []
        if depth != -1:
            (start, end) = mesh_dm.getDepthStratum(depth)
        else:
            (start, end) = mesh_dm.getHeightStratum(height)

        for seed in range(start, end):
            # Only build patches over owned DoFs
            if mesh_dm.getLabelValue("pyop2_ghost", seed) != -1:
                continue

            # Create point list from mesh DM
            star, _ = mesh_dm.getTransitiveClosure(seed, useCone=False)
            pt_array = set()
            for pt in star.tolist():
                closure, _ = mesh_dm.getTransitiveClosure(seed, useCone=True)
                pt_array.update(closure.tolist())

            # Get DoF indices for patch
            indices = []
            for (i, W) in enumerate(V):
                section = W.dm.getDefaultSection()
                for p in pt_array:
                    dof = section.getDof(p)
                    if dof <= 0:
                        continue
                    off = section.getOffset(p)
                    # Local indices within W
                    W_indices = numpy.arange(off*W.value_size, W.value_size * (off + dof), dtype=IntType)
                    indices.extend(V_local_ises_indices[i][W_indices])
            iset = PETSc.IS().createGeneral(indices, comm=COMM_SELF)
            ises.append(iset)

        return ises
예제 #6
0
파일: norms.py 프로젝트: chawkm/firedrake
def errornorm(u, uh, norm_type="L2", degree_rise=3, mesh=None):
    """Compute the error :math:`e = u - u_h` in the specified norm.

    :arg u: a :class:`.Function` containing an "exact" solution
    :arg uh: a :class:`.Function` containing the approximate solution
    :arg norm_type: the type of norm to compute, see :func:`.norm` for
         details of supported norm types.
    :arg degree_rise: increase in polynomial degree to use as the
         approximation space for computing the error.
    :arg mesh: an optional mesh on which to compute the error norm
         (currently ignored).

    This function works by :func:`.project`\ing ``u`` and ``uh`` into
    a space of degree ``degree_rise`` higher than the degree of ``uh``
    and computing the error there.
    """
    urank = len(u.ufl_shape)
    uhrank = len(uh.ufl_shape)

    rank = urank
    if urank != uhrank:
        raise RuntimeError("Mismatching rank between u and uh")

    degree = uh.function_space().ufl_element().degree()
    if isinstance(degree, tuple):
        degree = max(degree) + degree_rise
    else:
        degree += degree_rise

    # The exact solution might be an expression, in which case this test is irrelevant.
    if isinstance(u, function.Function):
        degree_u = u.function_space().ufl_element().degree()
        if degree > degree_u:
            warning("Degree of exact solution less than approximation degree")

    mesh = uh.function_space().mesh()
    if rank == 0:
        V = functionspace.FunctionSpace(mesh, 'DG', degree)
    elif rank == 1:
        V = functionspace.VectorFunctionSpace(mesh, 'DG', degree,
                                              dim=u.ufl_shape[0])
    else:
        raise RuntimeError("Don't know how to compute error norm for tensor valued functions")

    u_ = projection.project(u, V)
    uh_ = projection.project(uh, V)

    uh_ -= u_

    return norm(uh_, norm_type=norm_type, mesh=mesh)
예제 #7
0
def _extract_kwargs(**kwargs):
    parameters = kwargs.get('solver_parameters', None)
    if 'parameters' in kwargs:
        warning(RED % "The 'parameters' keyword is deprecated, use 'solver_parameters' instead.")
        parameters = kwargs['parameters']
        if 'solver_parameters' in kwargs:
            warning(RED % "'parameters' and 'solver_parameters' passed, using the latter")
            parameters = kwargs['solver_parameters']

    # Make sure we don't stomp on a dict the user has passed in.
    parameters = parameters.copy() if parameters is not None else {}
    nullspace = kwargs.get('nullspace', None)
    tnullspace = kwargs.get('transpose_nullspace', None)
    options_prefix = kwargs.get('options_prefix', None)

    return parameters, nullspace, tnullspace, options_prefix
예제 #8
0
def FunctionHierarchy(fs_hierarchy, functions=None):
    """ outdated and returns warning & list of functions corresponding to each level
    of a functionspace hierarchy

        :arg fs_hierarchy: the :class:`~.FunctionSpaceHierarchy` to build on.
        :arg functions: optional :class:`~.Function` for each level.

    """
    from firedrake.logging import warning, RED
    warning(RED % "FunctionHierarchy is obsolete. Falls back by returning list of functions")

    if functions is not None:
        assert len(functions) == len(fs_hierarchy)
        for f, V in zip(functions, fs_hierarchy):
            assert f.function_space() == V
        return tuple(functions)
    else:
        return tuple([firedrake.Function(f) for f in fs_hierarchy])
예제 #9
0
def FunctionHierarchy(fs_hierarchy, functions=None):
    """ outdated and returns warning & list of functions corresponding to each level
    of a functionspace hierarchy

        :arg fs_hierarchy: the :class:`~.FunctionSpaceHierarchy` to build on.
        :arg functions: optional :class:`~.Function` for each level.

    """
    from firedrake.logging import warning, RED
    warning(RED % "FunctionHierarchy is obsolete. Falls back by returning list of functions")

    if functions is not None:
        assert len(functions) == len(fs_hierarchy)
        for f, V in zip(functions, fs_hierarchy):
            assert f.function_space() == V
        return tuple(functions)
    else:
        return tuple([firedrake.Function(f) for f in fs_hierarchy])
예제 #10
0
 def inserted_options(self):
     """Context manager inside which the petsc options database
 contains the parameters from this object."""
     from firedrake.logging import warning
     try:
         for k, v in self.parameters.items():
             key = self.options_prefix + k
             if type(v) is bool:
                 if "monitor" in k or "view" in k:
                     warning("""Firedrake will stop translating True/False options soon.\n"""
                             """This is to allow controlling boolean options with a default value of True.\n"""
                             """To obtain the old behaviour you should translate:\n"""
                             """  {%r: True} => {"option": None}\n"""
                             """and\n"""
                             """  {%r: False} => {}\n""" % (k, k))
                 if v:
                     self.options_object[key] = None
             else:
                 self.options_object[key] = v
         yield
     finally:
         for k in self.to_delete:
             del self.options_object[self.options_prefix + k]
예제 #11
0
 def inserted_options(self):
     """Context manager inside which the petsc options database
 contains the parameters from this object."""
     from firedrake.logging import warning
     try:
         for k, v in self.parameters.items():
             key = self.options_prefix + k
             if type(v) is bool:
                 if "monitor" in k or "view" in k:
                     warning(
                         """Firedrake will stop translating True/False options soon.\n"""
                         """This is to allow controlling boolean options with a default value of True.\n"""
                         """To obtain the old behaviour you should translate:\n"""
                         """  {%r: True} => {"option": None}\n"""
                         """and\n"""
                         """  {%r: False} => {}\n""" % (k, k))
                 if v:
                     self.options_object[key] = None
             else:
                 self.options_object[key] = v
         yield
     finally:
         for k in self.to_delete:
             del self.options_object[self.options_prefix + k]
예제 #12
0
    def stepper(self, t_start, t_end, w, t_visualization):
        """ Timesteps the shallow water equations from t_start to t_end using a 3rd order SSP Runge-Kutta scheme

                :param t_start: start time
                :type t_start: float

                :param t_end: end time
                :type t_end: float

                :param w: Current state vector function

                :param t_visualization: time interval to write the free surface water depth to a .pvd file
                :type t_visualization: float

        """

        self.w = w

        # setup the solver - this is a timed stage for profiling reasons!
        with timed_stage("Setup of forms and solver"):
            self.__solver_setup()

        # used as the original state vector in each RK3 step
        self.w_old = Function(self.V).assign(self.w)

        # initial slope modification
        self.__update_slope_modification()

        hout = Function(self.v_h)
        hout.rename("free surface depth")
        # free surface depth
        hout_file = File("h.pvd")
        # bed depth
        bout = Function(self.v_h).project(self.b_)
        bout.rename("topography")
        bout_file = File("b.pvd")

        self.Project = Projector(
            conditional(self.h <= (self.plot_tol * self.E), self.b_,
                        self.h + self.b_), hout)
        self.Project.project()
        hout_file.write(hout)
        bout_file.write(bout)

        self.t = t_start

        # start counter of how many time dumps
        self.c = 1

        # warning boolean marker
        self.wmark = 0

        while self.t < t_end:

            # find new timestep
            with timed_stage("Finding adaptive time-step"):
                self.dt = self.AT.FindTimestep(self.w)
                self.Dt.assign(self.dt)

            # check that prescribed timestep doesn't fall below minimum timestep
            if self.dt < self.MinTimestep:
                if self.wmark is False:
                    warning(RED % "Minimum timestep has been reached. " +
                            "Simulation might become unstable.")
                    self.wmark = 1
                self.dt = self.MinTimestep
                self.Dt.assign(self.dt)

            # check if remaining time to next time dump is less than timestep
            # correct if neeeded
            if self.dt + self.t > self.c * t_visualization:
                self.dt = (self.c * t_visualization) - self.t
                self.Dt.assign(self.dt)

            # check if remaining time to end time is less than timestep
            # correct if needed
            if (self.t <=
                (self.c + 1) * t_visualization) and (self.dt + self.t > t_end):
                self.dt = t_end - self.t
                self.Dt.assign(self.dt)

            with timed_stage("Runge-Kutta time-stepping scheme"):
                self.solver.solve()

                self.w.assign(self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.solver.solve()

                self.w.assign((3.0 / 4.0) * self.w_old + (1.0 / 4.0) * self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.solver.solve()

                self.w.assign((1.0 / 3.0) * self.w_old + (2.0 / 3.0) * self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.w_old.assign(self.w)

                # timstep complete - dump realisation if needed
                self.t += self.dt

            with timed_stage("Visualization"):
                if self.t == self.c * t_visualization:
                    self.Project.project()
                    hout_file.write(hout)
                    bout_file.write(bout)

                    self.c += 1

                    self.dt = self.initial_dt
                    self.Dt.assign(self.dt)

        # return timestep
        self.dt = self.initial_dt
        self.Dt.assign(self.dt)

        return self.w
예제 #13
0
    def stepper(self, t_start, t_end, w, t_visualization):
        """ Timesteps the shallow water equations from t_start to t_end using a 3rd order SSP Runge-Kutta scheme

                :param t_start: start time
                :type t_start: float

                :param t_end: end time
                :type t_end: float

                :param w: Current state vector function

                :param t_visualization: time interval to write the free surface water depth to a .pvd file
                :type t_visualization: float

        """

        self.w = w

        # setup the solver - this is a timed stage for profiling reasons!
        with timed_stage("Setup of forms and solver"):
            self.__solver_setup()

        # used as the original state vector in each RK3 step
        self.w_old = Function(self.V).assign(self.w)

        # initial slope modification
        self.__update_slope_modification()

        hout = Function(self.v_h)
        hout.rename("free surface depth")
        # free surface depth
        hout_file = File("h.pvd")
        # bed depth
        bout = Function(self.v_h).project(self.b_)
        bout.rename("topography")
        bout_file = File("b.pvd")

        self.Project = Projector(conditional(self.h <= (self.plot_tol * self.E), self.b_, self.h + self.b_), hout)
        self.Project.project()
        hout_file.write(hout)
        bout_file.write(bout)

        self.t = t_start

        # start counter of how many time dumps
        self.c = 1

        # warning boolean marker
        self.wmark = 0

        while self.t < t_end:

            # find new timestep
            with timed_stage("Finding adaptive time-step"):
                self.dt = self.AT.FindTimestep(self.w)
                self.Dt.assign(self.dt)

            # check that prescribed timestep doesn't fall below minimum timestep
            if self.dt < self.MinTimestep:
                if self.wmark is False:
                    warning(RED % "Minimum timestep has been reached. " +
                            "Simulation might become unstable.")
                    self.wmark = 1
                self.dt = self.MinTimestep
                self.Dt.assign(self.dt)

            # check if remaining time to next time dump is less than timestep
            # correct if neeeded
            if self.dt + self.t > self.c * t_visualization:
                self.dt = (self.c * t_visualization) - self.t
                self.Dt.assign(self.dt)

            # check if remaining time to end time is less than timestep
            # correct if needed
            if (self.t <= (self.c + 1) * t_visualization) and (self.dt + self.t > t_end):
                self.dt = t_end - self.t
                self.Dt.assign(self.dt)

            with timed_stage("Runge-Kutta time-stepping scheme"):
                self.solver.solve()

                self.w.assign(self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.solver.solve()

                self.w.assign((3.0 / 4.0) * self.w_old + (1.0 / 4.0) * self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.solver.solve()

                self.w.assign((1.0 / 3.0) * self.w_old + (2.0 / 3.0) * self.w_)

                # slope limiter
                with timed_stage("Slope limiting"):
                    self.__update_slope_limiter()
                # slope modification
                with timed_stage("Slope modification"):
                    self.__update_slope_modification()

                self.w_old.assign(self.w)

                # timstep complete - dump realisation if needed
                self.t += self.dt

            with timed_stage("Visualization"):
                if self.t == self.c * t_visualization:
                    self.Project.project()
                    hout_file.write(hout)
                    bout_file.write(bout)

                    self.c += 1

                    self.dt = self.initial_dt
                    self.Dt.assign(self.dt)

        # return timestep
        self.dt = self.initial_dt
        self.Dt.assign(self.dt)

        return self.w
예제 #14
0
from ufl.indexed import Indexed
from ufl.domain import join_domains

from pyop2 import READ, WRITE, RW, INC, MIN, MAX
import pyop2
import loopy
import coffee.base as ast

from firedrake.logging import warning
from firedrake import constant
from firedrake.utils import ScalarType_c
try:
    from cachetools import LRUCache
    kernel_cache = LRUCache(maxsize=128)
except ImportError:
    warning("cachetools not available, firedrake.par_loop calls will be slowed down")
    kernel_cache = None


__all__ = ['par_loop', 'direct', 'READ', 'WRITE', 'RW', 'INC', 'MIN', 'MAX']


class _DirectLoop(object):
    r"""A singleton object which can be used in a :func:`par_loop` in place
    of the measure in order to indicate that the loop is a direct loop
    over degrees of freedom."""

    def integral_type(self):
        return "direct"

    def __repr__(self):
예제 #15
0
import sys
import ufl
import ctypes
from ctypes import POINTER, c_int, c_double, c_void_p

from pyop2 import op2
from pyop2.datatypes import ScalarType, IntType, as_ctypes

from firedrake import functionspaceimpl
from firedrake.logging import warning
from firedrake import utils
from firedrake import vector
try:
    import cachetools
except ImportError:
    warning(
        "cachetools not available, expression assembly will be slowed down")
    cachetools = None

__all__ = ['Function', 'PointNotInDomainError']


class _CFunction(ctypes.Structure):
    """C struct collecting data from a :class:`Function`"""
    _fields_ = [
        ("n_cols", c_int),
        ("n_layers", c_int),
        ("coords", POINTER(c_double)),
        ("coords_map", POINTER(as_ctypes(IntType))),
        # FIXME: what if f does not have type double?
        ("f", POINTER(c_double)),
        ("f_map", POINTER(as_ctypes(IntType))),
예제 #16
0
def assemble(f, tensor=None, bcs=None, form_compiler_parameters=None,
             inverse=False, mat_type=None, sub_mat_type=None,
             appctx={}, options_prefix=None, **kwargs):
    r"""Evaluate f.

    :arg f: a :class:`~ufl.classes.Form`, :class:`~ufl.classes.Expr` or
            a :class:`~slate.TensorBase` expression.
    :arg tensor: an existing tensor object to place the result in
         (optional).
    :arg bcs: a list of boundary conditions to apply (optional).
    :arg form_compiler_parameters: (optional) dict of parameters to pass to
         the form compiler.  Ignored if not assembling a
         :class:`~ufl.classes.Form`.  Any parameters provided here will be
         overridden by parameters set on the :class:`~ufl.classes.Measure` in the
         form.  For example, if a ``quadrature_degree`` of 4 is
         specified in this argument, but a degree of 3 is requested in
         the measure, the latter will be used.
    :arg inverse: (optional) if f is a 2-form, then assemble the inverse
         of the local matrices.
    :arg mat_type: (optional) string indicating how a 2-form (matrix) should be
         assembled -- either as a monolithic matrix ('aij' or 'baij'), a block matrix
         ('nest'), or left as a :class:`.ImplicitMatrix` giving matrix-free
         actions ('matfree').  If not supplied, the default value in
         ``parameters["default_matrix_type"]`` is used.  BAIJ differs
         from AIJ in that only the block sparsity rather than the dof
         sparsity is constructed.  This can result in some memory
         savings, but does not work with all PETSc preconditioners.
         BAIJ matrices only make sense for non-mixed matrices.
    :arg sub_mat_type: (optional) string indicating the matrix type to
         use *inside* a nested block matrix.  Only makes sense if
         ``mat_type`` is ``nest``.  May be one of 'aij' or 'baij'.  If
         not supplied, defaults to ``parameters["default_sub_matrix_type"]``.
    :arg appctx: Additional information to hang on the assembled
         matrix if an implicit matrix is requested (mat_type "matfree").
    :arg options_prefix: PETSc options prefix to apply to matrices.

    If f is a :class:`~ufl.classes.Form` then this evaluates the corresponding
    integral(s) and returns a :class:`float` for 0-forms, a
    :class:`.Function` for 1-forms and a :class:`.Matrix` or :class:`.ImplicitMatrix`
    for 2-forms.

    If f is an expression other than a form, it will be evaluated
    pointwise on the :class:`.Function`\s in the expression. This will
    only succeed if all the Functions are on the same
    :class:`.FunctionSpace`.

    If f is a Slate tensor expression, then it will be compiled using Slate's
    linear algebra compiler.

    If ``tensor`` is supplied, the assembled result will be placed
    there, otherwise a new object of the appropriate type will be
    returned.

    If ``bcs`` is supplied and ``f`` is a 2-form, the rows and columns
    of the resulting :class:`.Matrix` corresponding to boundary nodes
    will be set to 0 and the diagonal entries to 1. If ``f`` is a
    1-form, the vector entries at boundary nodes are set to the
    boundary condition values.
    """

    if "nest" in kwargs:
        nest = kwargs.pop("nest")
        from firedrake.logging import warning, RED
        warning(RED % "The 'nest' argument is deprecated, please set 'mat_type' instead")
        if nest is not None:
            mat_type = "nest" if nest else "aij"

    collect_loops = kwargs.pop("collect_loops", False)
    allocate_only = kwargs.pop("allocate_only", False)
    if len(kwargs) > 0:
        raise TypeError("Unknown keyword arguments '%s'" % ', '.join(kwargs.keys()))

    if isinstance(f, (ufl.form.Form, slate.TensorBase)):
        loops = _assemble(f, tensor=tensor, bcs=solving._extract_bcs(bcs),
                          form_compiler_parameters=form_compiler_parameters,
                          inverse=inverse, mat_type=mat_type,
                          sub_mat_type=sub_mat_type, appctx=appctx,
                          assemble_now=not collect_loops,
                          allocate_only=allocate_only,
                          options_prefix=options_prefix)
        loops = tuple(loops)
        if collect_loops and not allocate_only:
            # Will this be useful?
            return loops
        else:
            for l in loops:
                m = l()
            return m

    elif isinstance(f, ufl.core.expr.Expr):
        return assemble_expressions.assemble_expression(f)
    else:
        raise TypeError("Unable to assemble: %r" % f)
예제 #17
0
def VectorFunctionSpaceHierarchy(mesh_hierarchy, *args, **kwargs):
    from firedrake.logging import warning, RED
    warning(RED % "VectorFunctionSpaceHierarchy is obsolete. Just build a FunctionSpace on the relevant mesh")

    return tuple(firedrake.VectorFunctionSpace(mesh, *args, **kwargs) for mesh in mesh_hierarchy)
예제 #18
0
def flatten_parameters(parameters, sep="_"):
    """Flatten a nested parameters dict, joining keys with sep.

    :arg parameters: a dict to flatten.
    :arg sep: separator of keys.

    Used to flatten parameter dictionaries with nested structure to a
    flat dict suitable to pass to PETSc.  For example:

    .. code-block:: python

       flatten_parameters({"a": {"b": {"c": 4}, "d": 2}, "e": 1}, sep="_")
       => {"a_b_c": 4, "a_d": 2, "e": 1}

    If a "prefix" key already ends with the provided separator, then
    it is not used to concatenate the keys.  Hence:

    .. code-block:: python

       flatten_parameters({"a_": {"b": {"c": 4}, "d": 2}, "e": 1}, sep="_")
       => {"a_b_c": 4, "a_d": 2, "e": 1}
       # rather than
       => {"a__b_c": 4, "a__d": 2, "e": 1}
    """
    from firedrake.logging import warning
    new = type(parameters)()

    if not len(parameters):
        return new

    def flatten(parameters, *prefixes):
        """Iterate over nested dicts, yielding (*keys, value) pairs."""
        sentinel = object()
        try:
            option = sentinel
            for option, value in parameters.items():
                # Recurse into values to flatten any dicts.
                for pair in flatten(value, option, *prefixes):
                    yield pair
            # Make sure zero-length dicts come back.
            if option is sentinel:
                yield (prefixes, parameters)
        except AttributeError:
            # Non dict values are just returned.
            yield (prefixes, parameters)

    def munge(keys):
        """Ensure that each intermediate key in keys ends in sep.

        Also, reverse the list."""
        for key in reversed(keys[1:]):
            if len(key) and not key.endswith(sep):
                yield key + sep
            else:
                yield key
        else:
            yield keys[0]

    for keys, value in flatten(parameters):
        option = "".join(map(str, munge(keys)))
        if option in new:
            warning("Ignoring duplicate option: %s (existing value %s, new value %s)",
                    option, new[option], value)
        new[option] = value
    return new
예제 #19
0
def MixedFunctionSpaceHierarchy(mesh_hierarchy, *args, **kwargs):
    from firedrake.logging import warning, RED
    warning(RED % "TensorFunctionSpaceHierarchy is obsolete. Just build a FunctionSpace on the relevant mesh")

    kwargs.pop("mesh", None)
    return tuple(firedrake.MixedFunctionSpace(*args, mesh=mesh, **kwargs) for mesh in mesh_hierarchy)
예제 #20
0
def flatten_parameters(parameters, sep="_"):
    """Flatten a nested parameters dict, joining keys with sep.

    :arg parameters: a dict to flatten.
    :arg sep: separator of keys.

    Used to flatten parameter dictionaries with nested structure to a
    flat dict suitable to pass to PETSc.  For example:

    .. code-block:: python

       flatten_parameters({"a": {"b": {"c": 4}, "d": 2}, "e": 1}, sep="_")
       => {"a_b_c": 4, "a_d": 2, "e": 1}

    If a "prefix" key already ends with the provided separator, then
    it is not used to concatenate the keys.  Hence:

    .. code-block:: python

       flatten_parameters({"a_": {"b": {"c": 4}, "d": 2}, "e": 1}, sep="_")
       => {"a_b_c": 4, "a_d": 2, "e": 1}
       # rather than
       => {"a__b_c": 4, "a__d": 2, "e": 1}
    """
    new = type(parameters)()

    if not len(parameters):
        return new

    def flatten(parameters, *prefixes):
        """Iterate over nested dicts, yielding (*keys, value) pairs."""
        sentinel = object()
        try:
            option = sentinel
            for option, value in parameters.items():
                # Recurse into values to flatten any dicts.
                for pair in flatten(value, option, *prefixes):
                    yield pair
            # Make sure zero-length dicts come back.
            if option is sentinel:
                yield (prefixes, parameters)
        except AttributeError:
            # Non dict values are just returned.
            yield (prefixes, parameters)

    def munge(keys):
        """Ensure that each intermediate key in keys ends in sep.

        Also, reverse the list."""
        for key in reversed(keys[1:]):
            if len(key) and not key.endswith(sep):
                yield key + sep
            else:
                yield key
        else:
            yield keys[0]

    for keys, value in flatten(parameters):
        option = "".join(map(str, munge(keys)))
        if option in new:
            warning(
                "Ignoring duplicate option: %s (existing value %s, new value %s)",
                option, new[option], value)
        new[option] = value
    return new
예제 #21
0
def set_defaults(solver_parameters, arguments, *, ksp_defaults={}, snes_defaults={}):
    """Set defaults for solver parameters.

    :arg solver_parameters: dict of user solver parameters to override/extend defaults
    :arg arguments: arguments for the bilinear form (need to know if we have a Real block).
    :arg ksp_defaults: Default KSP parameters.
    :arg snes_defaults: Default SNES parameters."""
    if solver_parameters:
        # User configured something, try and set sensible direct solve
        # defaults for missing bits.
        parameters = solver_parameters.copy()
        for k, v in snes_defaults.items():
            parameters.setdefault(k, v)
        keys = frozenset(parameters.keys())
        ksp_defaults = ksp_defaults.copy()
        skip = set()
        if "pc_type" in keys:
            # Might reasonably expect to get petsc defaults
            skip.update({"pc_factor_mat_solver_type", "ksp_type"})
        if parameters.get("mat_type") in {"matfree", "nest"}:
            # Non-LU defaults.
            ksp_defaults["ksp_type"] = "gmres"
            ksp_defaults["pc_type"] = "jacobi"
        for k, v in ksp_defaults.items():
            if k not in skip:
                parameters.setdefault(k, v)
        return parameters

    # OK, we're in full defaults mode now.
    parameters = dict(chain.from_iterable(
        d.items() for d in (ksp_defaults, snes_defaults)))

    if any(V.ufl_element().family() == "Real"
           for a in arguments for V in a.function_space()):
        test, trial = arguments
        if test.function_space() != trial.function_space():
            # Don't know what to do here. How did it happen?
            raise ValueError("Can't generate defaults for non-square problems with real blocks")

        fields = []
        reals = []
        for i, V_ in enumerate(test.function_space()):
            if V_.ufl_element().family() == "Real":
                reals.append(i)
            else:
                fields.append(i)
        if len(fields) == 0:
            # Just reals, GMRES
            opts = {"ksp_type": "gmres",
                    "pc_type": "none"}
            parameters.update(opts)
        else:
            warning("Real block detected, generating Schur complement elimination PC")
            # Full Schur complement eliminating onto Real blocks.
            opts = {"mat_type": "matfree",
                    "ksp_type": "fgmres",
                    "pc_type": "fieldsplit",
                    "pc_fieldsplit_type": "schur",
                    "pc_fieldsplit_schur_fact_type": "full",
                    "pc_fieldsplit_0_fields": ",".join(map(str, fields)),
                    "pc_fieldsplit_1_fields": ",".join(map(str, reals)),
                    "fieldsplit_0": {
                        "ksp_type": "preonly",
                        "pc_type": "python",
                        "pc_python_type": "firedrake.AssembledPC",
                        "assembled": DEFAULT_KSP_PARAMETERS,
                    },
                    "fieldsplit_1": {
                        "ksp_type": "gmres",
                        "pc_type": "none",
                    }}
            parameters.update(opts)
        return parameters
    else:
        # We can assemble an AIJ matrix, factor it with a sparse
        # direct method.
        return parameters
예제 #22
0
    def evict(self):
        """Run the cache eviction algorithm. This works out the permitted
cache size and deletes objects until it is achieved. Cache values are
assumed to have a ``value`` attribute and eviction occurs in
increasing ``value`` order. Currently ``value`` is an index of
the assembly operation, so older operations are evicted first.

The cache will be evicted down to 90% of permitted size.

The permitted size is either the explicit
``parameters["assembly_cache"]["max_bytes"]`` or it is the amount of
memory per core scaled by ``parameters["assembly_cache"]["max_factor"]``
(by default the scale factor is 0.6).

In MPI parallel, the nbytes of each cache entry is set to the maximum
over all processes, while the available memory is set to the
minimum. This produces a conservative caching policy which is
guaranteed to result in the same evictions on each processor.

        """

        if not parameters["assembly_cache"]["eviction"]:
            return

        max_cache_size = min(parameters["assembly_cache"]["max_bytes"] or float("inf"),
                             (memory or float("inf"))
                             * parameters["assembly_cache"]["max_factor"]
                             )

        if max_cache_size == float("inf"):
            if not self.evictwarned:
                warning("No maximum assembly cache size. Install psutil >= 2.0.0 or risk leaking memory!")
                self.evictwarned = True
            return

        cache_size = self.nbytes
        if cache_size < max_cache_size:
            return

        debug("Cache eviction triggered. %s bytes in cache, %s bytes allowed" %
              (cache_size, max_cache_size))

        # Evict down to 90% full.
        bytes_to_evict = cache_size - 0.9 * max_cache_size

        sorted_cache = sorted(self.cache.items(), key=lambda x: x[1][1].value)

        nbytes = lambda x: x[1][1].nbytes

        candidates = []
        while bytes_to_evict > 0:
            next = sorted_cache.pop(0)
            candidates.append(next)
            bytes_to_evict -= nbytes(next)

        for c in reversed(candidates):
            if bytes_to_evict + nbytes(c) < 0:
                # We may have been overzealous.
                bytes_to_evict += nbytes(c)
            else:
                del self.cache[c[0]]
예제 #23
0
 def __lshift__(self, arg):
     from firedrake.logging import warning, RED
     warning(RED % "The << syntax is deprecated, use File.write")
     self.write(arg)
예제 #24
0
import ufl
import ctypes
from ctypes import POINTER, c_int, c_double, c_void_p

import coffee.base as ast

from pyop2 import op2

from firedrake import functionspaceimpl
from firedrake.logging import warning
from firedrake import utils
from firedrake import vector
try:
    import cachetools
except ImportError:
    warning("cachetools not available, expression assembly will be slowed down")
    cachetools = None


__all__ = ['Function', 'PointNotInDomainError']


valuetype = np.float64


class _CFunction(ctypes.Structure):
    """C struct collecting data from a :class:`Function`"""
    _fields_ = [("n_cols", c_int),
                ("n_layers", c_int),
                ("coords", POINTER(c_double)),
                ("coords_map", POINTER(c_int)),
예제 #25
0
파일: output.py 프로젝트: chawkm/firedrake
 def __lshift__(self, arg):
     from firedrake.logging import warning, RED
     warning(RED % "The << syntax is deprecated, use File.write")
     self.write(arg)
예제 #26
0
파일: assemble.py 프로젝트: tlroy/firedrake
def assemble(f,
             tensor=None,
             bcs=None,
             form_compiler_parameters=None,
             inverse=False,
             mat_type=None,
             sub_mat_type=None,
             appctx={},
             options_prefix=None,
             **kwargs):
    """Evaluate f.

    :arg f: a :class:`~ufl.classes.Form`, :class:`~ufl.classes.Expr` or
            a :class:`~slate.TensorBase` expression.
    :arg tensor: an existing tensor object to place the result in
         (optional).
    :arg bcs: a list of boundary conditions to apply (optional).
    :arg form_compiler_parameters: (optional) dict of parameters to pass to
         the form compiler.  Ignored if not assembling a
         :class:`~ufl.classes.Form`.  Any parameters provided here will be
         overridden by parameters set on the :class:`~ufl.classes.Measure` in the
         form.  For example, if a ``quadrature_degree`` of 4 is
         specified in this argument, but a degree of 3 is requested in
         the measure, the latter will be used.
    :arg inverse: (optional) if f is a 2-form, then assemble the inverse
         of the local matrices.
    :arg mat_type: (optional) string indicating how a 2-form (matrix) should be
         assembled -- either as a monolithic matrix ('aij' or 'baij'), a block matrix
         ('nest'), or left as a :class:`.ImplicitMatrix` giving matrix-free
         actions ('matfree').  If not supplied, the default value in
         ``parameters["default_matrix_type"]`` is used.  BAIJ differs
         from AIJ in that only the block sparsity rather than the dof
         sparsity is constructed.  This can result in some memory
         savings, but does not work with all PETSc preconditioners.
         BAIJ matrices only make sense for non-mixed matrices.
    :arg sub_mat_type: (optional) string indicating the matrix type to
         use *inside* a nested block matrix.  Only makes sense if
         ``mat_type`` is ``nest``.  May be one of 'aij' or 'baij'.  If
         not supplied, defaults to ``parameters["default_sub_matrix_type"]``.
    :arg appctx: Additional information to hang on the assembled
         matrix if an implicit matrix is requested (mat_type "matfree").
    :arg options_prefix: PETSc options prefix to apply to matrices.

    If f is a :class:`~ufl.classes.Form` then this evaluates the corresponding
    integral(s) and returns a :class:`float` for 0-forms, a
    :class:`.Function` for 1-forms and a :class:`.Matrix` or :class:`.ImplicitMatrix`
    for 2-forms.

    If f is an expression other than a form, it will be evaluated
    pointwise on the :class:`.Function`\s in the expression. This will
    only succeed if all the Functions are on the same
    :class:`.FunctionSpace`.

    If f is a Slate tensor expression, then it will be compiled using Slate's
    linear algebra compiler.

    If ``tensor`` is supplied, the assembled result will be placed
    there, otherwise a new object of the appropriate type will be
    returned.

    If ``bcs`` is supplied and ``f`` is a 2-form, the rows and columns
    of the resulting :class:`.Matrix` corresponding to boundary nodes
    will be set to 0 and the diagonal entries to 1. If ``f`` is a
    1-form, the vector entries at boundary nodes are set to the
    boundary condition values.
    """

    if "nest" in kwargs:
        nest = kwargs.pop("nest")
        from firedrake.logging import warning, RED
        warning(
            RED %
            "The 'nest' argument is deprecated, please set 'mat_type' instead")
        if nest is not None:
            mat_type = "nest" if nest else "aij"

    collect_loops = kwargs.pop("collect_loops", False)
    allocate_only = kwargs.pop("allocate_only", False)
    if len(kwargs) > 0:
        raise TypeError("Unknown keyword arguments '%s'" %
                        ', '.join(kwargs.keys()))

    if isinstance(f, (ufl.form.Form, slate.TensorBase)):
        return _assemble(f,
                         tensor=tensor,
                         bcs=solving._extract_bcs(bcs),
                         form_compiler_parameters=form_compiler_parameters,
                         inverse=inverse,
                         mat_type=mat_type,
                         sub_mat_type=sub_mat_type,
                         appctx=appctx,
                         collect_loops=collect_loops,
                         allocate_only=allocate_only,
                         options_prefix=options_prefix)
    elif isinstance(f, ufl.core.expr.Expr):
        return assemble_expressions.assemble_expression(f)
    else:
        raise TypeError("Unable to assemble: %r" % f)
예제 #27
0
    def __init__(self,
                 code=None,
                 element=None,
                 cell=None,
                 degree=None,
                 **kwargs):
        r"""
        :param code: a string C statement, or list of statements.
        :param element: a :class:`~ufl.finiteelement.finiteelement.FiniteElement`, optional
              (currently ignored)
        :param cell: a :class:`~ufl.classes.Cell`, optional (currently ignored)
        :param degree: the degree of quadrature to use for evaluation (currently ignored)
        :param kwargs: user-defined values that are accessible in the
               Expression code.  These values maybe updated by
               accessing the property of the same name.  This can be
               used, for example, to pass in the current timestep to
               an Expression without necessitating recompilation.  For
               example:

               .. code-block:: python

                  f = Function(V)
                  e = Expression('sin(x[0]*t)', t=t)
                  while t < T:
                      f.interpolate(e)
                      ...
                      t += dt
                      e.t = t

        The currently ignored parameters are retained for API compatibility with Dolfin.
        """
        # Init also called in mesh constructor, but expression can be built without mesh
        utils._init()
        self.code = None
        self._shape = ()
        if code is not None:
            warning(
                "C string Expressions will be removed soon! See: https://www.firedrakeproject.org/interpolation.html#c-string-expressions"
            )
            arr = np.array(code)
            self._shape = arr.shape
            # Flatten to something indexable for use.
            self.code = arr.flatten()
            for val in self.code:
                if str(val).strip() == "":
                    raise ValueError("Cannot provide empty expression")
        self.cell = cell
        self.degree = degree
        # These attributes are required by ufl.Coefficient to render the repr
        # of an Expression. Since we don't call the ufl.Coefficient constructor
        # (since we don't yet know the element) we need to set them ourselves
        self._element = element
        self._repr = None
        self._count = 0

        self._user_args = []
        # Changing counter used to record when user changes values
        self._state = 0
        # Save the kwargs so that when we rebuild an expression we can
        # reconstruct the user arguments.
        self._kwargs = {}
        if len(kwargs) == 0:
            # No need for magic, since there are no user arguments.
            return

        # We have to build a new class to add these properties to
        # since properties work on classes not instances and we don't
        # want every Expression to have all the properties of all
        # Expressions.
        cls = type(self.__class__.__name__, (self.__class__, ), {})
        for slot, val in sorted(kwargs.items(), key=itemgetter(0)):
            # Save the argument for later reconstruction
            self._kwargs[slot] = val
            # Scalar arguments have to be treated specially
            val = np.array(val, dtype=np.float64)
            shape = val.shape
            rank = len(shape)
            if rank == 0:
                shape = 1
            val = op2.Global(shape, val, dtype=ScalarType, name=slot)
            # Record the Globals in a known order (for later passing
            # to a par_loop).  Remember their "name" too, so we can
            # construct a kwarg dict when applying python expressions.
            self._user_args.append((slot, val))
            # And save them as an attribute
            setattr(self, '_%s' % slot, val)

            # We have to do this because of the worthlessness of
            # Python's support for closing over variables.
            def make_getx(slot):
                def getx(self):
                    glob = getattr(self, '_%s' % slot)
                    return glob.data_ro

                return getx

            def make_setx(slot):
                def setx(self, value):
                    glob = getattr(self, '_%s' % slot)
                    glob.data = value
                    self._kwargs[slot] = value
                    # Bump state
                    self._state += 1

                return setx

            # Add public properties for the user-defined variables
            prop = property(make_getx(slot), make_setx(slot))
            setattr(cls, slot, prop)
        # Set the class on this instance to the newly built class with
        # properties attached.
        self.__class__ = cls