Ejemplo n.º 1
0
    def initialize_data(self):
        """
        Extract required objects for defining error control
        forms. This will be stored and reused.
        """
        # Developer's note: The UFL-FFC-DOLFIN--PyDOLFIN toolchain for
        # error control is quite fine-tuned. In particular, the order
        # of coefficients in forms is (and almost must be) used for
        # their assignment. This means that the order in which these
        # coefficients are defined matters and should be considered
        # fixed.

        # Primal trial element space
        self._V = self.u.function_space()

        # Primal test space == Dual trial space
        Vhat = self.weak_residual.arguments()[0].function_space()

        # Discontinuous version of primal trial element space
        self._dV = tear(self._V)

        # Extract cell and geometric dimension
        mesh = self._V.mesh()
        dim = mesh.topology().dim()

        # Function representing improved dual
        E = increase_order(Vhat)
        self._Ez_h = Function(E)

        # Function representing cell bubble function
        B = FunctionSpace(mesh, "B", dim + 1)
        self._b_T = Function(B)
        self._b_T.vector()[:] = 1.0

        # Function representing strong cell residual
        self._R_T = Function(self._dV)

        # Function representing cell cone function
        C = FunctionSpace(mesh, "DG", dim)
        self._b_e = Function(C)

        # Function representing strong facet residual
        self._R_dT = Function(self._dV)

        # Function for discrete dual on primal test space
        self._z_h = Function(Vhat)

        # Piecewise constants for assembling indicators
        self._DG0 = FunctionSpace(mesh, "DG", 0)
    def _init_convenience(self, multimesh, family, degree):
        # Check arguments
        self.info = [family, degree]
        if not isinstance(family, string_types):
            cpp.dolfin_error(
                "multimeshfunctionspace.py", "create function space",
                "Illegal argument for finite element family, not a string: " +
                str(family))
        if not isinstance(degree, int):
            cpp.dolfin_error(
                "multimeshfunctionspace.py", "create function space",
                "Illegal argument for degree, not an integer: " + str(degree))
        if not isinstance(multimesh, cpp.mesh.MultiMesh):
            cpp.dolfin_error(
                "functionspace.py", "create multimesh function space",
                "Illegal argument, not a multimesh: " + str(multimesh))

        # Create UFL element
        mesh = multimesh.part(0)
        element = ufl.FiniteElement(family, mesh.ufl_cell(), degree)

        # Create and add individual function spaces
        V = cpp.function.MultiMeshFunctionSpace(multimesh)
        V_parts = []
        for part in range(multimesh.num_parts()):
            V_part = FunctionSpace(multimesh.part(part), element)
            V_parts.append(V_part)
            V.add(V_part)

        # Build multimesh function space
        V.build()

        # Store full function spaces
        self._parts = V_parts
        self._cpp_object = V
Ejemplo n.º 3
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one
        # with the next argument number
        form_arguments = form.arguments()
        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        # NOTE : Mixed-domains problems need to have arg.part() != None
        # if any(arg.part() is not None for arg in form_arguments):
        #     raise RuntimeError("Compute derivative of form, cannot automatically create new Argument using parts, please supply one")
        part = None

        if isinstance(u, Function):
            # u.part() is None except with mixed-domains
            part = u.part()
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, SpatialCoordinate):
            mesh = u.ufl_domain().ufl_cargo()
            element = u.ufl_domain().ufl_coordinate_element()
            V = FunctionSpace(mesh, element)
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(
                isinstance(w, Function) for w in u):
            raise RuntimeError(
                "Taking derivative of form w.r.t. a tuple of Coefficients. Take derivative w.r.t. a single Coefficient on a mixed space instead."
            )
        else:
            raise RuntimeError(
                "Computing derivative of form w.r.t. '{}'. Supply Function as a Coefficient"
                .format(u))
    return ufl.derivative(form, u, du, coefficient_derivatives)
Ejemplo n.º 4
0
def set_poisson_eq_2d(n=8):
    '''
    Basic example where only the mesh refinement is controlled.
    '''

    # mesh
    mesh = UnitSquareMesh(n, n)

    # function space
    V = FunctionSpace(mesh, 'P', 1)

    # bcs
    u_D = Expression('1 + x[0]*x[0] + 2*x[1]*x[1]', degree=2)

    def boundary(x, on_boundary):
        return on_boundary

    bc = DirichletBC(V, u_D, boundary)

    # variational problem
    u = TrialFunction(V)
    v = TestFunction(V)
    f = Constant(-6.0)
    a = dot(grad(u), grad(v)) * dx
    L = f * v * dx

    # define unknown
    u = Function(V)

    return a, L, u, bc
Ejemplo n.º 5
0
def increase_order(V):
    """For a given function space, return the same space, but with a
    higher polynomial degree

    """
    mesh = V.mesh()
    element = ufl.algorithms.elementtransformations.increase_order(V.ufl_element())
    constrained_domain = V.dofmap().constrained_domain
    return FunctionSpace(mesh, element, constrained_domain=constrained_domain)
Ejemplo n.º 6
0
def set_linear_dirichlet_constant(mesh,
                                  dt,
                                  var_name='Temperature',
                                  bc_temperature=1300.,
                                  temperature=300.,
                                  source_value=0.,
                                  axis=1,
                                  right=True,
                                  tol=1e-4,
                                  conductivity=1.,
                                  density=1.,
                                  specific_heat=1.):
    '''
    Heat equation problem where an edge/surface is set at a given temperature
    and everything else at another.

    Parameters
    ----------
    axis : int
        Controls boundary to which Dirichlet bc is applied.
    right : bool
        Dirichlet bc is applied to the planar and perpendicular face found in
        the max (True) or min (False) coordinate.
    '''

    # function space
    V = FunctionSpace(mesh, 'Lagrange', 1)

    # boundary conditions
    bcs = [
        set_dirichlet_bc_lim(V,
                             value=bc_temperature,
                             axis=axis,
                             right=right,
                             tol=tol)
    ]

    # initial condition
    u_initial = Constant(temperature)
    u_n = Function(V, name=var_name)
    u_n.interpolate(u_initial)

    # problem formulation
    f = Constant(source_value)
    u_n, a, L = get_formulation_constant_props(V,
                                               u_initial,
                                               f,
                                               dt,
                                               conductivity,
                                               density,
                                               specific_heat,
                                               var_name=var_name)

    u = Function(V, name=var_name)

    return u_n, a, L, u, bcs
Ejemplo n.º 7
0
def change_regularity(V, family):
    """For a given function space, return the corresponding space with
    the finite elements specified by 'family'. Possible families are
    the families supported by the form compiler

    """
    mesh = V.mesh()
    element = ufl.algorithms.elementtransformations.change_regularity(V.ufl_element(), family)
    constrained_domain = V.dofmap().constrained_domain
    return FunctionSpace(mesh, element, constrained_domain=constrained_domain)
Ejemplo n.º 8
0
def set_linear_equal_opposite(mesh,
                              dt,
                              var_name='Temperature',
                              axis=0,
                              bc_temperature=300.,
                              source_value=0.,
                              conductivity=1.,
                              density=1.,
                              specific_heat=1.,
                              V=None):
    '''
    Heat equation problem where two opposite edges/faces are set at the same
    temperature and the points in between follow a quadratic variation.

    Notes
    -----
    * assumes opposite faces of interest are planar and perpendicular to the
    axis.
    '''

    # function space
    if V is None:
        V = FunctionSpace(mesh, 'Lagrange', 1)

    # boundary conditions
    x_min, x_max = get_mesh_axis_lims(mesh, axis)
    bcs = [
        set_dirichlet_bc(V, x, bc_temperature, axis) for x in [x_min, x_max]
    ]

    # initial condition
    c = (x_max - x_min) / 2
    param = bc_temperature / (c**2)
    u_initial = Expression('param * (x[axis] - c) * (x[axis] - c)',
                           degree=2,
                           param=param,
                           c=c,
                           name='T',
                           axis=axis)

    # problem formulation
    f = Constant(source_value)
    u_n, a, L = get_formulation_constant_props(V,
                                               u_initial,
                                               f,
                                               dt,
                                               conductivity,
                                               density,
                                               specific_heat,
                                               var_name=var_name)

    u = Function(V, name=var_name)

    return u_n, a, L, u, bcs
Ejemplo n.º 9
0
def formulate_laplacian(mesh, V=None):

    if V is None:
        V = FunctionSpace(mesh, 'CG', 1)

    u_h = TrialFunction(V)
    v = TestFunction(V)

    a = inner(grad(u_h), grad(v)) * dx
    b = inner(u_h, v) * dx
    dummy = inner(1., v) * dx

    return V, a, b, dummy
Ejemplo n.º 10
0
def _extract_function_space(expression, mesh):
    """Try to extract a suitable function space for projection of given
    expression.

    """

    # Get mesh from expression
    if mesh is None:
        domain = expression.ufl_domain()
        if domain is not None:
            mesh = domain.ufl_cargo()

    # Extract mesh from functions
    if mesh is None:
        # (Not sure if this code is relevant anymore, the above code
        # should cover this)
        # Extract functions
        functions = ufl.algorithms.extract_coefficients(expression)
        for f in functions:
            if isinstance(f, Function):
                mesh = f.function_space().mesh()
                if mesh is not None:
                    break

    if mesh is None:
        cpp.dolfin_error(
            "projection.py", "extract function space",
            "Unable to project expression, can't find "
            "a suitable mesh.")

    # Create function space
    shape = expression.ufl_shape
    if shape == ():
        V = FunctionSpace(mesh, "Lagrange", 1)
    elif len(shape) == 1:
        V = VectorFunctionSpace(mesh, "Lagrange", 1, dim=shape[0])
    elif len(shape) == 2:
        V = TensorFunctionSpace(mesh, "Lagrange", 1, shape=shape)
    else:
        cpp.dolfin_error("projection.py", "extract function space",
                         "Unhandled rank, shape is %s." % (shape, ))

    return V
Ejemplo n.º 11
0
    def __init_from_ufl(self, multimesh, element):
        self.info = [element]
        if not isinstance(element, ufl.FiniteElementBase):
            cpp.dolfin_error(
                "multimeshfunctionspace.py", "create function space",
                "Illegal argument, not a finite element: " + str(element))
        # Create and add individual function spaces
        V = cpp.function.MultiMeshFunctionSpace(multimesh)
        V_parts = []
        for part in range(multimesh.num_parts()):
            V_part = FunctionSpace(multimesh.part(part), element)
            V_parts.append(V_part)
            V.add(V_part)

        # Build multimesh function space
        V.build()

        # Store full function spaces
        self._parts = V_parts
        self._cpp_object = V
Ejemplo n.º 12
0
    def __init__(self,
                 V: functionspace.FunctionSpace,
                 x: typing.Optional[PETSc.Vec] = None,
                 name: typing.Optional[str] = None):
        """Initialize finite element Function."""

        # Create cpp Function
        if x is not None:
            self._cpp_object = cpp.function.Function(V._cpp_object, x)
        else:
            self._cpp_object = cpp.function.Function(V._cpp_object)

        # Initialize the ufl.FunctionSpace
        super().__init__(V.ufl_function_space(), count=self._cpp_object.id)

        # Set name
        if name is None:
            self.rename("f_{}".format(self.count()))
        else:
            self.rename(name)

        # Store DOLFIN FunctionSpace object
        self._V = V
Ejemplo n.º 13
0
def errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None):
    """
    Compute and return the error :math:`e = u - u_h` in the given norm.

    *Arguments*
        u, uh
            :py:class:`Functions <dolfin.functions.function.Function>`
        norm_type
            Type of norm. The :math:`L^2` -norm is default.
            For other norms, see :py:func:`norm <dolfin.fem.norms.norm>`.
        degree_rise
            The number of degrees above that of u_h used in the
            interpolation; i.e. the degree of piecewise polynomials used
            to approximate :math:`u` and :math:`u_h` will be the degree
            of :math:`u_h` + degree_raise.
        mesh
            Optional :py:class:`Mesh <dolfin.cpp.Mesh>` on
            which to compute the error norm.

    In simple cases, one may just define

    .. code-block:: python

        e = u - uh

    and evalute for example the square of the error in the :math:`L^2` -norm by

    .. code-block:: python

        assemble(e**2*dx(mesh))

    However, this is not stable w.r.t. round-off errors considering that
    the form compiler may expand(#) the expression above to::

        e**2*dx = u**2*dx - 2*u*uh*dx + uh**2*dx

    and this might get further expanded into thousands of terms for
    higher order elements. Thus, the error will be evaluated by adding
    a large number of terms which should sum up to something close to
    zero (if the error is small).

    This module computes the error by first interpolating both
    :math:`u` and :math:`u_h` to a common space (of high accuracy),
    then subtracting the two fields (which is easy since they are
    expressed in the same basis) and then evaluating the integral.

    (#) If using the tensor representation optimizations.
    The quadrature represenation does not suffer from this problem.
    """

    # Check argument
    # if not isinstance(u, cpp.function.GenericFunction):
    #     cpp.dolfin_error("norms.py",
    #                      "compute error norm",
    #                      "Expecting a Function or Expression for u")
    # if not isinstance(uh, cpp.function.Function):
    #     cpp.dolfin_error("norms.py",
    #                      "compute error norm",
    #                      "Expecting a Function for uh")

    # Get mesh
    if isinstance(u, cpp.function.Function) and mesh is None:
        mesh = u.function_space().mesh()
    if isinstance(uh, cpp.function.Function) and mesh is None:
        mesh = uh.function_space().mesh()
    if hasattr(uh, "_cpp_object") and mesh is None:
        mesh = uh._cpp_object.function_space().mesh()
    if hasattr(u, "_cpp_object") and mesh is None:
        mesh = u._cpp_object.function_space().mesh()
    if mesh is None:
        cpp.dolfin_error("norms.py",
                         "compute error norm",
                         "Missing mesh")

    # Get rank
    if not u.ufl_shape == uh.ufl_shape:
        cpp.dolfin_error("norms.py",
                         "compute error norm",
                         "Value shapes don't match")
    shape = u.ufl_shape
    rank = len(shape)

    # Check that uh is associated with a finite element
    if uh.ufl_element().degree() is None:
        cpp.dolfin_error("norms.py",
                         "compute error norm",
                         "Function uh must have a finite element")

    # Degree for interpolation space. Raise degree with respect to uh.
    degree = uh.ufl_element().degree() + degree_rise

    # Check degree of 'exact' solution u
    degree_u = u.ufl_element().degree()
    if degree_u is not None and degree_u < degree:
        cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.")

    # Create function space
    if rank == 0:
        V = FunctionSpace(mesh, "Discontinuous Lagrange", degree)
    elif rank == 1:
        V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree,
                                dim=shape[0])
    elif rank > 1:
        V = TensorFunctionSpace(mesh, "Discontinuous Lagrange", degree,
                                shape=shape)

    # Interpolate functions into finite element space
    pi_u = interpolate(u, V)
    pi_uh = interpolate(uh, V)

    # Compute the difference
    e = Function(V)
    e.assign(pi_u)
    e.vector().axpy(-1.0, pi_uh.vector())

    # Compute norm
    return norm(e, norm_type=norm_type, mesh=mesh)
Ejemplo n.º 14
0
def project(v, V=None, bcs=None, mesh=None,
            function=None,
            solver_type="lu",
            preconditioner_type="default",
            form_compiler_parameters=None):
    """Return projection of given expression *v* onto the finite element
    space *V*.

    *Arguments*
        v
            a :py:class:`Function <dolfin.functions.function.Function>` or
            an :py:class:`Expression <dolfin.functions.expression.Expression>`
        bcs
            Optional argument :py:class:`list of DirichletBC
            <dolfin.fem.bcs.DirichletBC>`
        V
            Optional argument :py:class:`FunctionSpace
            <dolfin.functions.functionspace.FunctionSpace>`
        mesh
            Optional argument :py:class:`mesh <dolfin.cpp.Mesh>`.
        solver_type
            see :py:func:`solve <dolfin.fem.solving.solve>` for options.
        preconditioner_type
            see :py:func:`solve <dolfin.fem.solving.solve>` for options.
        form_compiler_parameters
            see :py:class:`Parameters <dolfin.cpp.Parameters>` for more
            information.

    *Example of usage*

        .. code-block:: python

            v = Expression("sin(pi*x[0])")
            V = FunctionSpace(mesh, "Lagrange", 1)
            Pv = project(v, V)

        This is useful for post-processing functions or expressions
        which are not readily handled by visualization tools (such as
        for example discontinuous functions).

    """

    # Try figuring out a function space if not specified
    if V is None:
        # Create function space based on Expression element if trying
        # to project an Expression
        if isinstance(v, dolfin.function.expression.Expression):
            if mesh is not None and isinstance(mesh, cpp.mesh.Mesh):
                V = FunctionSpace(mesh, v.ufl_element())
            # else:
            #     cpp.dolfin_error("projection.py",
            #                      "perform projection",
            #                      "Expected a mesh when projecting an Expression")
        else:
            # Otherwise try extracting function space from expression
            V = _extract_function_space(v, mesh)

    # Projection into a MultiMeshFunctionSpace
    if isinstance(V, MultiMeshFunctionSpace):

        # Create the measuresum of uncut and cut-cells
        dX = ufl.dx() + ufl.dC()

        # Define variational problem for projection
        w = TestFunction(V)
        Pv = TrialFunction(V)
        a = ufl.inner(w, Pv) * dX
        L = ufl.inner(w, v) * dX

        # Assemble linear system
        A = assemble_multimesh(a, form_compiler_parameters=form_compiler_parameters)
        b = assemble_multimesh(L, form_compiler_parameters=form_compiler_parameters)

        # Solve linear system for projection
        if function is None:
            function = MultiMeshFunction(V)
        cpp.la.solve(A, function.vector(), b, solver_type, preconditioner_type)

        return function

    # Ensure we have a mesh and attach to measure
    if mesh is None:
        mesh = V.mesh()
    dx = ufl.dx(mesh)

    # Define variational problem for projection
    w = TestFunction(V)
    Pv = TrialFunction(V)
    a = ufl.inner(w, Pv) * dx
    L = ufl.inner(w, v) * dx

    # Assemble linear system
    A, b = assemble_system(a, L, bcs=bcs,
                           form_compiler_parameters=form_compiler_parameters)

    # Solve linear system for projection
    if function is None:
        function = Function(V)
    cpp.la.solve(A, function.vector(), b, solver_type, preconditioner_type)

    return function
Ejemplo n.º 15
0
 def leaf_node(self):
     u = self._cpp_object.leaf_node()
     return Function(FunctionSpace(u.function_space()), u.vector())
Ejemplo n.º 16
0
 def function_space(self):
     "Return the FunctionSpace"
     return FunctionSpace(self._cpp_object.function_space())
Ejemplo n.º 17
0
def project(v, V=None, func_degree=None, bcs=None, mesh=None,
            function=None,
            solver_type="lu",
            preconditioner_type="default",
            form_compiler_parameters=None):
    """
    This function is a modification of FEniCS's built-in project function that adopts the :math:`r^2dr`
    measure as opposed to the standard Cartesian :math:`dx` measure.

    For documentation and usage, see the 
    `original module <https://bitbucket.org/fenics-project/dolfin/src/master/python/dolfin/fem/projection.py>`_.

    .. note:: Note the extra argument func_degree: this is used to interpolate the :math:`r^2` 
              Expression to the same degree as used in the definition of the Trial and Test function
              spaces.

    """

    # Try figuring out a function space if not specified
    if V is None:
        # Create function space based on Expression element if trying
        # to project an Expression
        if isinstance(v, Expression):
            # FIXME: Add handling of cpp.MultiMesh
            if mesh is not None and isinstance(mesh, cpp.mesh.Mesh):
                V = FunctionSpace(mesh, v.ufl_element())
            # else:
            #     cpp.dolfin_error("projection.py",
            #                      "perform projection",
            #                      "Expected a mesh when projecting an Expression")
        else:
            # Otherwise try extracting function space from expression
            V = _extract_function_space(v, mesh)



    # Ensure we have a mesh and attach to measure
    if mesh is None:
        mesh = V.mesh()
    dx = ufl.dx(mesh)

    # Define variational problem for projection
    
    # DS: HERE IS WHERE I MODIFY
    r2 = Expression('pow(x[0],2)', degree=func_degree)
    
    w = TestFunction(V)
    Pv = TrialFunction(V)
    a = ufl.inner(w, Pv) * r2 * dx
    L = ufl.inner(w, v) * r2 * dx

    # Assemble linear system
    A, b = assemble_system(a, L, bcs=bcs,
                           form_compiler_parameters=form_compiler_parameters)

    # Solve linear system for projection
    if function is None:
        function = Function(V)
    cpp.la.solve(A, function.vector(), b, solver_type, preconditioner_type)

    return function
Ejemplo n.º 18
0
def r2_errornorm(u, uh, norm_type="l2", degree_rise=3, mesh=None ):
    """
    This function is a modification of FEniCS's built-in errornorm function that adopts the :math:`r^2dr`
    measure as opposed to the standard Cartesian :math:`dx` measure.

    For documentation and usage, see the 
    original module <https://bitbucket.org/fenics-project/dolfin/src/master/python/dolfin/fem/norms.py>_.

    """


    # Get mesh
    if isinstance(u, cpp.function.Function) and mesh is None:
        mesh = u.function_space().mesh()
    if isinstance(uh, cpp.function.Function) and mesh is None:
        mesh = uh.function_space().mesh()
    # if isinstance(uh, MultiMeshFunction) and mesh is None:
    #     mesh = uh.function_space().multimesh()
    if hasattr(uh, "_cpp_object") and mesh is None:
        mesh = uh._cpp_object.function_space().mesh()
    if hasattr(u, "_cpp_object") and mesh is None:
        mesh = u._cpp_object.function_space().mesh()
    if mesh is None:
        raise RuntimeError("Cannot compute error norm. Missing mesh.")

    # Get rank
    if not u.ufl_shape == uh.ufl_shape:
        raise RuntimeError("Cannot compute error norm. Value shapes do not match.")
    
    shape = u.ufl_shape
    rank = len(shape)

    # Check that uh is associated with a finite element
    if uh.ufl_element().degree() is None:
        raise RuntimeError("Cannot compute error norm. Function uh must have a finite element.")

    # Degree for interpolation space. Raise degree with respect to uh.
    degree = uh.ufl_element().degree() + degree_rise

    # Check degree of 'exact' solution u
    degree_u = u.ufl_element().degree()
    if degree_u is not None and degree_u < degree:
        cpp.warning("Degree of exact solution may be inadequate for accurate result in errornorm.")

    # Create function space
    if rank == 0:
        V = FunctionSpace(mesh, "Discontinuous Lagrange", degree)
    elif rank == 1:
        V = VectorFunctionSpace(mesh, "Discontinuous Lagrange", degree,
                                dim=shape[0])
    elif rank > 1:
        V = TensorFunctionSpace(mesh, "Discontinuous Lagrange", degree,
                                shape=shape)

    # Interpolate functions into finite element space
    pi_u = interpolate(u, V)
    pi_uh = interpolate(uh, V)

    # Compute the difference
    e = Function(V)
    e.assign(pi_u)
    e.vector().axpy(-1.0, pi_uh.vector())

    # Compute norm
    return r2_norm(e, func_degree=degree, norm_type=norm_type, mesh=mesh )
Ejemplo n.º 19
0
 def __init__(self, V: FunctionSpace, number: int, part: int = None):
     """Create a UFL/DOLFIN Argument"""
     ufl.Argument.__init__(self, V.ufl_function_space(), number, part)
     self._V = V