Ejemplo n.º 1
0
def jit(form, form_compiler_parameters=None, common_cell=None):
    """Just-in-time compile any provided form.

    It uses the jit function from the form compiler registered by
    parameters["form_compiler"]["name"].
    """

    # Check that form is not empty
    if isinstance(form, ufl.Form):
        if form.integrals() == ():
            raise RuntimeError, "Form is empty. Cannot pass to JIT compiler."

    # Import form compiler
    form_compiler_name = cpp.parameters["form_compiler"]["name"]
    try:
        form_compiler = __import__(form_compiler_name)
    except ImportError, message:
        print message
        warning("Could not import %s form compiler, falling back to FFC." % form_compiler_name)
        try:
            form_compiler = __import__("ffc")
        except:
            cpp.dolfin_error("jit.py",
                             "perform just-in-time compilation of form",
                             "Could not import FFC form compiler")
Ejemplo n.º 2
0
def _plot_cpp(object, mesh, kwargs):
    # Convert kwargs to cpp format
    p = cpp.Parameters()
    for key in kwargs:
        try:
            p.add(key, kwargs[key])
        except TypeError:
            cpp.warning("Incompatible type for keyword argument \"%s\". Ignoring." % key)

    if isinstance(object, cpp.Expression):
        plot_object = cpp.plot(object, mesh, p)
    elif isinstance(object, cpp.MultiMesh):
        return cpp.plot_multimesh(object)
    else:
        plot_object = cpp.plot(object, p)

    # Compatibility with book
    plot_object.write_ps = _VTKPlotter_write_ps

    # Avoid premature deletion of plotted objects if they go out of scope
    # before the plot window is closed. The plotter itself is safe, since it's
    # created in the plot() C++ function, not directly from Python. But the
    # Python plotter proxy may disappear, so we can't store the references
    # there.
    global _objects_referenced_from_plot_windows
    _objects_referenced_from_plot_windows[plot_object.key()] = (object, mesh, p)

    return plot_object
Ejemplo n.º 3
0
def _plot_matplotlib(obj, mesh, kwargs):
    if isinstance(obj, (cpp.MultiMesh, cpp.MultiMeshFunction, cpp.MultiMeshDirichletBC)):
        cpp.warning("Don't know how to plot type %s" % type(obj))
        return

    # Avoid importing pyplot until used
    try:
        import matplotlib.pyplot as plt
    except:
        print("*** Warning: matplotlib.pyplot not available, cannot plot")
        return

    gdim = mesh.geometry().dim()
    if gdim == 3 or kwargs.get("mode") in ("warp",):
        # Importing this toolkit has side effects enabling 3d support
        from mpl_toolkits.mplot3d import axes3d
        # Enabling the 3d toolbox requires some additional arguments
        ax = plt.gca(projection='3d')
    else:
        ax = plt.gca()
    ax.set_aspect('equal')

    title = kwargs.pop("title", None)
    if title is not None:
        ax.set_title(title)

    # Translate range_min/max kwargs supported by VTKPlotter
    vmin = kwargs.pop("range_min", None)
    vmax = kwargs.pop("range_max", None)
    if vmin and not "vmin" in kwargs:
        kwargs["vmin"] = vmin
    if vmax and not "vmax" in kwargs:
        kwargs["vmax"] = vmax

    # Let's stays consistent and use mode='color' instead of 'surface'
    if kwargs.get("mode") == "surface":
        cpp.deprecation("plot kwarg mode='surface'", "1.7.0", "1.7.0",
                        "Use mode='color' instead.")
        kwargs["mode"] = "color"

    # Drop unsupported kwargs and inform user
    _unsupported_kwargs = ["interactive", "rescale", "wireframe"]
    for kw in _unsupported_kwargs:
        if kwargs.pop(kw, None):
            cpp.warning("Matplotlib backend does not support '%s' kwarg yet. "
                        "Ignoring it..." % kw)

    if isinstance(obj, cpp.Function):
        return mplot_function(ax, obj, **kwargs)
    elif isinstance(obj, cpp.Expression):
        return mplot_expression(ax, obj, mesh, **kwargs)
    elif isinstance(obj, cpp.Mesh):
        return mplot_mesh(ax, obj, **kwargs)
    elif isinstance(obj, cpp.DirichletBC):
        return mplot_dirichletbc(ax, obj, **kwargs)
    elif isinstance(obj, _meshfunction_types):
        return mplot_meshfunction(ax, obj, **kwargs)
    else:
        raise AttributeError('Failed to plot %s' % type(obj))
Ejemplo n.º 4
0
def _plot_matplotlib(obj, mesh, kwargs):
    if not isinstance(obj, _matplotlib_plottable_types):
        print("Don't know how to plot type %s." % type(obj))
        return

    # Plotting is not working with all ufl cells
    if mesh.ufl_cell().cellname() not in ['interval', 'triangle', 'tetrahedron']:
        raise AttributeError(("Matplotlib plotting backend doesn't handle %s mesh.\n"
                              "Possible options are saving the output to XDMF file "
                              "or using 'x3dom' backend.") % mesh.ufl_cell().cellname())

    # Avoid importing pyplot until used
    try:
        import matplotlib.pyplot as plt
    except Exception:
        cpp.warning("matplotlib.pyplot not available, cannot plot.")
        return

    gdim = mesh.geometry().dim()
    if gdim == 3 or kwargs.get("mode") in ("warp",):
        # Importing this toolkit has side effects enabling 3d support
        from mpl_toolkits.mplot3d import axes3d  # noqa
        # Enabling the 3d toolbox requires some additional arguments
        ax = plt.gca(projection='3d')
    else:
        ax = plt.gca()
    ax.set_aspect('equal')

    title = kwargs.pop("title", None)
    if title is not None:
        ax.set_title(title)

    # Translate range_min/max kwargs supported by VTKPlotter
    vmin = kwargs.pop("range_min", None)
    vmax = kwargs.pop("range_max", None)
    if vmin and "vmin" not in kwargs:
        kwargs["vmin"] = vmin
    if vmax and "vmax" not in kwargs:
        kwargs["vmax"] = vmax

    # Drop unsupported kwargs and inform user
    _unsupported_kwargs = ["rescale", "wireframe"]
    for kw in _unsupported_kwargs:
        if kwargs.pop(kw, None):
            cpp.warning("Matplotlib backend does not support '%s' kwarg yet. "
                        "Ignoring it..." % kw)

    if isinstance(obj, cpp.function.Function):
        return mplot_function(ax, obj, **kwargs)
    elif isinstance(obj, cpp.function.Expression):
        return mplot_expression(ax, obj, mesh, **kwargs)
    elif isinstance(obj, cpp.mesh.Mesh):
        return mplot_mesh(ax, obj, **kwargs)
    elif isinstance(obj, cpp.fem.DirichletBC):
        return mplot_dirichletbc(ax, obj, **kwargs)
    elif isinstance(obj, _meshfunction_types):
        return mplot_meshfunction(ax, obj, **kwargs)
    else:
        raise AttributeError('Failed to plot %s' % type(obj))
Ejemplo n.º 5
0
def _plot_x3dom(obj, kwargs):
    if not isinstance(obj, _x3dom_plottable_types):
        cpp.warning("Don't know how to plot type %s." % type(obj))
        return

    x3dom = dolfin.X3DOM()
    out = x3dom.html(obj)

    return out
Ejemplo n.º 6
0
def _plot_matplotlib(obj, mesh, kwargs):
    if isinstance(
            obj,
        (cpp.MultiMesh, cpp.MultiMeshFunction, cpp.MultiMeshDirichletBC)):
        cpp.warning("Don't know how to plot type %s" % type(obj))
        return

    # Avoid importing pyplot until used
    try:
        import matplotlib.pyplot as plt
    except:
        print("*** Warning: matplotlib.pyplot not available, cannot plot")
        return

    gdim = mesh.geometry().dim()
    if gdim == 3 or kwargs.get("mode") in ("warp", ):
        # Importing this toolkit has side effects enabling 3d support
        from mpl_toolkits.mplot3d import axes3d
        # Enabling the 3d toolbox requires some additional arguments
        ax = plt.gca(projection='3d')
    else:
        ax = plt.gca()
    ax.set_aspect('equal')

    title = kwargs.pop("title", None)
    if title is not None:
        ax.set_title(title)

    # Translate range_min/max kwargs supported by VTKPlotter
    vmin = kwargs.pop("range_min", None)
    vmax = kwargs.pop("range_max", None)
    if vmin and not "vmin" in kwargs:
        kwargs["vmin"] = vmin
    if vmax and not "vmax" in kwargs:
        kwargs["vmax"] = vmax

    # Drop unsupported kwargs and inform user
    _unsupported_kwargs = ["interactive", "rescale", "wireframe"]
    for kw in _unsupported_kwargs:
        if kwargs.pop(kw, None):
            cpp.warning("Matplotlib backend does not support '%s' kwarg yet. "
                        "Ignoring it..." % kw)

    if isinstance(obj, cpp.Function):
        return mplot_function(ax, obj, **kwargs)
    elif isinstance(obj, cpp.Expression):
        return mplot_expression(ax, obj, mesh, **kwargs)
    elif isinstance(obj, cpp.Mesh):
        return mplot_mesh(ax, obj, **kwargs)
    elif isinstance(obj, cpp.DirichletBC):
        return mplot_dirichletbc(ax, obj, **kwargs)
    elif isinstance(obj, _meshfunction_types):
        return mplot_meshfunction(ax, obj, **kwargs)
    else:
        raise AttributeError('Failed to plot %s' % type(obj))
Ejemplo n.º 7
0
def _create_cpp_form(form, form_compiler_parameters=None):
    """Create a C++ Form from a UFL form"""
    if isinstance(form, cpp.fem.Form):
        if form_compiler_parameters is not None:
            cpp.warning(
                "Ignoring form_compiler_parameters when passed a dolfin Form!")
        return form
    elif isinstance(form, ufl.Form):
        form = Form(form, form_compiler_parameters=form_compiler_parameters)
        return form._cpp_object
    elif form is None:
        return None
    else:
        raise TypeError("Invalid form type: {}".format(type(form)))
Ejemplo n.º 8
0
def _create_dolfin_form(form, form_compiler_parameters=None):
    # First check if we got a cpp.Form
    if isinstance(form, cpp.Form):
        # Check that jit compilation has already happened
        if not hasattr(form, "_compiled_form"):
            raise TypeError("Expected a dolfin form to have a _compiled_form attribute.")
        # Warn that we don't use the parameters if we get any
        if form_compiler_parameters is not None:
            cpp.warning("Ignoring form_compiler_parameters when passed a dolfin Form!")
        return form
    elif isinstance(form, ufl.Form):
        return Form(form, form_compiler_parameters=form_compiler_parameters)
    else:
        raise TypeError("Invalid form type %s" % (type(form),))
Ejemplo n.º 9
0
def mplot_meshfunction(ax, obj, **kwargs):
    mesh = obj.mesh()
    tdim = mesh.topology().dim()
    d = obj.dim()
    if tdim == 2 and d == 2:
        C = obj.array()
        triang = mesh2triang(mesh)
        assert not kwargs.pop("facecolors", None), "Not expecting 'facecolors' in kwargs"
        return ax.tripcolor(triang, facecolors=C, **kwargs)
    else:
        # Return gracefully to make regression test pass without vtk
        cpp.warning('Matplotlib plotting backend does not support mesh '
                    'function of dim %d. Continuing without plotting...' % d)
        return
Ejemplo n.º 10
0
def jit(form, form_compiler_parameters=None, mpi_comm=None):
    """Just-in-time compile any provided form.

    It uses the jit function from the form compiler registered by
    parameters["form_compiler"]["name"].
    """

    # Check that form is not empty
    if isinstance(form, ufl.Form):
        if form.empty():
            cpp.dolfin_error("jit.py",
                             "perform just-in-time compilation of form",
                             "Form is empty. Cannot pass to JIT compiler")

    # Import form compiler
    form_compiler_name = cpp.parameters["form_compiler"]["name"]
    try:
        form_compiler = __import__(form_compiler_name)
    except ImportError as message:
        print(message)
        warning("Could not import %s form compiler, falling back to FFC." \
                % form_compiler_name)
        try:
            form_compiler = __import__("ffc")
        except:
            cpp.dolfin_error("jit.py",
                             "perform just-in-time compilation of form",
                             "Could not import FFC form compiler")

    # Checks on form compiler interface
    if not (hasattr(form_compiler, 'default_parameters')
            and hasattr(form_compiler, 'jit')):
        cpp.dolfin_error("jit.py",
                         "perform just-in-time compilation of form",
                         "Form compiler must implement the default_parameters "
                         "and jit functions")

    # Prepare form compiler parameters
    p = form_compiler.default_parameters()

    # Set parameters from global DOLFIN parameter set
    for key, value in six.iteritems(parameters["form_compiler"]):
        p[key] = value

    # Override with local parameters if any
    if form_compiler_parameters:
        p.update(form_compiler_parameters)

    # Execute!
    return form_compiler.jit(form, parameters=p)
Ejemplo n.º 11
0
def mplot_meshfunction(ax, obj, **kwargs):
    mesh = obj.mesh()
    tdim = mesh.topology().dim()
    d = obj.dim()
    if tdim == 2 and d == 2:
        C = obj.array()
        triang = mesh2triang(mesh)
        assert not kwargs.pop("facecolors", None), "Not expecting 'facecolors' in kwargs"
        return ax.tripcolor(triang, facecolors=C, **kwargs)
    else:
        # Return gracefully to make regression test pass without vtk
        cpp.warning('Matplotlib plotting backend does not support mesh '
                    'function of dim %d. Continuing without plotting...' % d)
        return
Ejemplo n.º 12
0
def _create_dolfin_form(form, form_compiler_parameters=None):
    # First check if we got a cpp.Form
    if isinstance(form, cpp.Form):
        # Check that jit compilation has already happened
        if not hasattr(form, "_compiled_form"):
            raise TypeError(
                "Expected a dolfin form to have a _compiled_form attribute.")
        # Warn that we don't use the parameters if we get any
        if form_compiler_parameters is not None:
            cpp.warning(
                "Ignoring form_compiler_parameters when passed a dolfin Form!")
        return form
    elif isinstance(form, ufl.Form):
        return Form(form, form_compiler_parameters=form_compiler_parameters)
    else:
        raise TypeError("Invalid form type %s" % (type(form), ))
Ejemplo n.º 13
0
def jit(form, form_compiler_parameters=None, common_cell=None):
    """Just-in-time compile any provided form.

    It uses the jit function from the form compiler registered by
    parameters["form_compiler"]["name"].
    """

    # Check that form is not empty
    if isinstance(form, ufl.Form):
        if form.integrals() == ():
            raise RuntimeError, "Form is empty. Cannot pass to JIT compiler."

    global _swig_version_ok

    # Check and set swig binary
    if not _swig_version_ok and not check_and_set_swig_binary(\
        parameters["swig_binary"], parameters["swig_path"]):
        raise OSError, "Could not find swig installation. Pass an existing "\
              "swig binary or install SWIG version 2.0 or higher.\n"

    # Check that the form compiler will use the same swig version
    # that PyDOLFIN was compiled with
    _swig_version_ok = _swig_version_ok or \
                       check_swig_version(cpp.__swigversion__, same=True)

    if not _swig_version_ok:
        raise OSError, """\
PyDOLFIN was not compiled with the present version of swig.
Install swig version %s or recompiled PyDOLFIN with present swig
"""%cpp.__swigversion__

    # Cache swig version test
    _swig_version_ok = True

    # Import form compiler
    form_compiler_name = cpp.parameters["form_compiler"]["name"]
    try:
        form_compiler = __import__(form_compiler_name)
    except ImportError, message:
        print message
        warning("Could not import %s form compiler, falling back to FFC." % form_compiler_name)
        try:
            form_compiler = __import__("ffc")
        except:
            cpp.dolfin_error("jit.py",
                             "perform just-in-time compilation of form",
                             "Could not import FFC form compiler")
Ejemplo n.º 14
0
def _has_matplotlib():
    try:
        import matplotlib
    except ImportError:
        return False

    # Switch to Agg backend if DISPLAY not set
    if not os.environ.get("DISPLAY"):
        cpp.log(cpp.PROGRESS, "Environment variable DISPLAY not set. Switching "
                              "to 'Agg' matplotlib backend.")
        try:
            matplotlib.use("Agg")
        except ValueError as e:
            cpp.warning("Switching to 'Agg' backend failed with the message:")
            print('"%s"' % str(e))
            cpp.warning("Trying to continue...")

    return True
Ejemplo n.º 15
0
def _has_matplotlib():
    try:
        import matplotlib
    except ImportError:
        return False

    # Switch to Agg backend if DISPLAY not set
    if not os.environ.get("DISPLAY"):
        cpp.log(cpp.PROGRESS, "Environment variable DISPLAY not set. Switching "
                              "to 'Agg' matplotlib backend.")
        try:
            matplotlib.use("Agg")
        except ValueError as e:
            cpp.warning("Switching to 'Agg' backend failed with the message:")
            print('"%s"' % str(e))
            cpp.warning("Trying to continue...")

    return True
Ejemplo n.º 16
0
def mplot_function(ax, f, **kwargs):
    mesh = f.function_space().mesh()
    gdim = mesh.geometry().dim()
    tdim = mesh.topology().dim()

    # Extract the function vector in a way that also works for
    # subfunctions
    try:
        fvec = f.vector()
    except RuntimeError:
        fspace = f.function_space()
        try:
            fspace = fspace.collapse()
        # Happens for part of MultiMeshFunction; no way detecting elsewhere
        except RuntimeError:
            cpp.warning("Probably trying to plot MultiMeshFunction "
                        "part. Continuing without plotting...")
            return
        fvec = dolfin.interpolate(f, fspace).vector()

    if fvec.size() == mesh.num_cells():
        # DG0 cellwise function
        C = fvec.array() # NB! Assuming here dof ordering matching cell numbering
        if gdim == 2 and tdim == 2:
            return ax.tripcolor(mesh2triang(mesh), C, **kwargs)
        elif gdim == 3 and tdim == 2: # surface in 3d
            # FIXME: Not tested, probably broken
            xy = mesh.coordinates()
            shade = kwargs.pop("shade", True)
            return ax.plot_trisurf(mesh2triang(mesh), xy[:,2], C, shade=shade,
                                   **kwargs)
        elif gdim == 1 and tdim == 1:
            x = mesh.coordinates()[:,0]
            nv = len(x)
            # Insert duplicate points to get piecewise constant plot
            xp = np.zeros(2*nv-2)
            xp[0] = x[0]
            xp[-1] = x[-1]
            xp[1:2*nv-3:2] = x[1:-1]
            xp[2:2*nv-2:2] = x[1:-1]
            Cp = np.zeros(len(xp))
            Cp[0:len(Cp)-1:2] = C
            Cp[1:len(Cp):2] = C
            return ax.plot(xp, Cp, *kwargs)
        #elif tdim == 1: # FIXME: Plot embedded line
        else:
            raise AttributeError('Matplotlib plotting backend only supports 2D mesh for scalar functions.')

    elif f.value_rank() == 0:
        # Scalar function, interpolated to vertices
        # TODO: Handle DG1?
        C = f.compute_vertex_values(mesh)
        if gdim == 2 and tdim == 2:
            mode = kwargs.pop("mode", "color")
            if mode == "color":
                shading = kwargs.pop("shading", "flat")
                return ax.tripcolor(mesh2triang(mesh), C, shading=shading,
                                    **kwargs)
            elif mode == "warp":
                from matplotlib import cm
                cmap = kwargs.pop("cmap", cm.jet)
                linewidths = kwargs.pop("linewidths", 0)
                return ax.plot_trisurf(mesh2triang(mesh), C, cmap=cmap,
                        linewidths=linewidths, **kwargs)
            elif mode == "wireframe":
                return ax.triplot(mesh2triang(mesh), **kwargs)
            elif mode == "contour":
                return ax.tricontour(mesh2triang(mesh), C, **kwargs)
        elif gdim == 3 and tdim == 2: # surface in 3d
            # FIXME: Not tested
            from matplotlib import cm
            cmap = kwargs.pop("cmap", cm.jet)
            return ax.plot_trisurf(mesh2triang(mesh), C, cmap=cmap, **kwargs)
        elif gdim == 3 and tdim == 3:
            # Volume
            # TODO: Isosurfaces?
            # Vertex point cloud
            X = [mesh.coordinates()[:, i] for i in range(gdim)]
            return ax.scatter(*X, c=C, **kwargs)
        elif gdim == 1 and tdim == 1:
            x = mesh.coordinates()[:,0]
            ax.set_aspect('auto')

            # Setting limits for Line2D objects
            vmin = kwargs.pop("vmin", None)
            vmax = kwargs.pop("vmax", None)
            ax.set_ylim([vmin, vmax])
            return ax.plot(x, C, **kwargs)
        #elif tdim == 1: # FIXME: Plot embedded line
        else:
            raise AttributeError('Matplotlib plotting backend only supports 2D mesh for scalar functions.')

    elif f.value_rank() == 1:
        # Vector function, interpolated to vertices
        w0 = f.compute_vertex_values(mesh)
        nv = mesh.num_vertices()
        if len(w0) != gdim*nv:
            raise AttributeError('Vector length must match geometric dimension.')
        X = mesh.coordinates()
        X = [X[:, i] for i in range(gdim)]
        U = [w0[i*nv: (i+1)*nv] for i in range(gdim)]

        # Compute magnitude
        C = U[0]**2
        for i in range(1,gdim):
            C += U[i]**2
        C = np.sqrt(C)

        mode = kwargs.pop("mode", "glyphs")
        if mode == "glyphs":
            args = X + U + [C]
            if gdim == 3:
                # 3d quiver plot works only since matplotlib 1.4
                import matplotlib
                if StrictVersion(matplotlib.__version__) < '1.4':
                    cpp.warning('Matplotlib version %s does not support 3d '
                                'quiver plot. Continuing without plotting...'
                                % matplotlib.__version__)
                    return

                length = kwargs.pop("length", 0.1)
                return ax.quiver(*args, length=length, **kwargs)
            else:
                return ax.quiver(*args, **kwargs)
        elif mode == "displacement":
            Xdef = [X[i] + U[i] for i in range(gdim)]
            import matplotlib.tri as tri
            if gdim == 2 and tdim == 2:
                # FIXME: Not tested
                triang = tri.Triangulation(Xdef[0], Xdef[1], mesh.cells())
                shading = kwargs.pop("shading", "flat")
                return ax.tripcolor(triang, C, shading=shading, **kwargs)
            else:
                # Return gracefully to make regression test pass without vtk
                cpp.warning('Matplotlib plotting backend does not support '
                            'displacement for %d in %d. Continuing without '
                            'plotting...' % (tdim, gdim))
                return
Ejemplo n.º 17
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.º 18
0
    def __init__(self, form,
                 form_compiler_parameters=None,
                 subdomains=None):
        "Create JIT-compiled form from any given form (compiled or not)."

        # Check form argument
        if isinstance(form, ufl.Form):
            # Cutoff for better error message than ffc would give
            if not form.empty() and not form.domains():
                raise RuntimeError("Expecting a completed form with domains at this point.")

            # Extract subdomain data
            sd = form.subdomain_data()
            if len(sd) != 1:
                # Until the assembler and ufc has multimesh support, we impose this limitation
                raise RuntimeError("Expecting subdomain data for a single domain only.")
            if subdomains is None:
                self.subdomains, = list(sd.values()) # Assuming single domain
            domain, = list(sd.keys()) # Assuming single domain
            mesh = domain.data()

            # Jit the module, this will take some time...
            self._compiled_form, module, prefix \
                                 = jit(form, form_compiler_parameters,
                                       mpi_comm=mesh.mpi_comm())

            # Extract function spaces of form arguments
            self.function_spaces = [func.function_space() for func in form.arguments()]

            # Extract coefficients from form (pass only the ones that the compiled form actually uses to the assembler)
            original_coefficients = form.coefficients()
            self.coefficients = [original_coefficients[self._compiled_form.original_coefficient_position(i)]
                                 for i in range(self._compiled_form.num_coefficients())]

        elif isinstance(form, cpp.Form):
            cpp.deprecation("Passing a cpp.Form to dolfin.Form constructor",
                            "1.3.0", "1.4.0",
                            "Passing a cpp.Form to dolfin.Form constructor"
                            " will be removed.")
            self._compiled_form = form._compiled_form

            self.function_spaces = form.function_spaces
            self.coefficients = form.coefficients
            self.subdomains = form.subdomains
            mesh = form.mesh()

        else:
            cpp.dolfin_error("form.py",
                             "creating dolfin.Form",
                             "Expected a ufl.Form or a dolfin.Form")

        # This is now a strict requirement
        if mesh is None:
            raise RuntimeError("Expecting to find a Mesh in the form.")

        # Type checking argument function_spaces
        r = self._compiled_form.rank()
        if len(self.function_spaces) != r:
            raise ValueError(function_space_error +
                  " Wrong number of test spaces (should be %d)." % r)
        if not all(isinstance(fs, cpp.FunctionSpace) for fs in self.function_spaces):
            raise ValueError(function_space_error +
                  " Invalid type of test spaces.")

        # Type checking coefficients
        if not all(isinstance(c, cpp.GenericFunction) for c in self.coefficients):
            coefficient_error = "Error while extracting coefficients. "
            raise TypeError(coefficient_error +
                            "Either provide a dict of cpp.GenericFunctions, " +
                            "or use Function to define your form.")

        # Type checking subdomain data
        # Check that we have no additional subdomain data (user misspelling)
        # TODO: Get from ufl list?
        integral_types = ("cell", "exterior_facet", "interior_facet", "point") 
        for k in list(self.subdomains.keys()):
            if self.subdomains[k] is None:
                del self.subdomains[k]
        additional_keys = set(self.subdomains.keys()) - set(integral_types)
        if additional_keys:
            cpp.warning("Invalid keys in subdomains: %s" % additional_keys)
        # Check that we have only MeshFunctions
        for data in list(self.subdomains.values()):
            # TODO: This wasn't here before, disable if it's too restrictive:
            if not (data is None or isinstance(data, MeshFunctionSizet)):
                cpp.warning("Invalid subdomain data type %s, expecting a MeshFunction" % type(data))

        # Initialize base class
        cpp.Form.__init__(self, self._compiled_form,
                          self.function_spaces, self.coefficients)

        # Attach subdomains if we have them
        subdomains = self.subdomains.get("cell")
        if subdomains is not None:
            self.set_cell_domains(subdomains)
        subdomains = self.subdomains.get("exterior_facet")
        if subdomains is not None:
            self.set_exterior_facet_domains(subdomains)
        subdomains = self.subdomains.get("interior_facet")
        if subdomains is not None:
            self.set_interior_facet_domains(subdomains)
        subdomains = self.subdomains.get("point")

        if subdomains is not None:
            self.set_vertex_domains(subdomains)

        # Attach mesh
        self.set_mesh(mesh)
Ejemplo n.º 19
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*e*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*e*dx() = u*u*dx() - 2*u*uh*dx() + uh*uh*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.

    """

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

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

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

    # 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)
    else:
        cpp.dolfin_error("norms.py",
                         "compute error norm",
                         "Can't handle elements of rank %d" % rank)

    # 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.º 20
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.º 21
0
def assemble_multimesh(form,
                       tensor=None,
                       form_compiler_parameters=None,
                       backend=None):
    "Assemble the given multimesh form and return the corresponding tensor."

    # The form that comes in is (by construction in function.Argument)
    # defined on the first part of the multimesh. We now need to create
    # the DOLFIN Forms with the proper function spaces for each part.

    # FIXME: This code makes a number of assumptions and will need to
    # be revisited and improved.

    # Warn that we don't use the parameters if we get any
    if form_compiler_parameters is not None:
        cpp.warning(
            "Ignoring form_compiler_parameters when passed a dolfin Form!")
    form_compiler_parameters = None

    # Extract arguments and multimesh function space
    coefficients = form.coefficients()
    arguments = form.arguments()

    # Extract rank
    rank = len(arguments)

    # Extract multimesh function spaces for arguments
    V_multi = [v._V_multi for v in arguments]

    # Extract number of parts, the multimesh and create the multimesh form
    num_parts = None
    if rank > 0:
        num_parts = V_multi[0].num_parts()
        multimesh_form = cpp.fem.MultiMeshForm(*V_multi)
        multimesh = V_multi[0].multimesh()
    elif len(coefficients) > 0:
        for coeff in coefficients:
            # Only create these variables once
            if isinstance(coeff, MultiMeshFunction):
                multimesh = coeff.function_space().multimesh()
                num_parts = coeff.function_space().num_parts()
                multimesh_form = cpp.fem.MultiMeshForm(multimesh)
                break

    if not num_parts:
        # Handle the case Constant(1)*dx(domain=multimesh)
        multimesh = form.ufl_domains()[0].ufl_cargo()
        num_parts = multimesh.num_parts()
        multimesh_form = cpp.fem.MultiMeshForm(multimesh)

    # Build multimesh DOLFIN form
    for part in range(num_parts):
        # Extract standard function spaces for all arguments on
        # current part
        function_spaces = [V_multi[i].part(part) for i in range(rank)]
        # Wrap standard form
        dolfin_form = _create_dolfin_form(form, form_compiler_parameters,
                                          function_spaces)

        # Setting coefficients for the multimesh form
        for i in range(len(coefficients)):
            if isinstance(coefficients[i], MultiMeshFunction):
                coeff = coefficients[i].part(part)
            else:
                coeff = coefficients[i]
            # Developer note: This may be done more elegantly by modifiying
            # _create_dolfin_form
            dolfin_form.set_coefficient(i, coeff._cpp_object)
            dolfin_form.coefficients[i] = coeff

        # Add standard mesh to the standard form and the
        # standard form to the multimesh form
        dolfin_form.set_mesh(multimesh.part(part))
        multimesh_form.add(dolfin_form)

    for i, coeff in enumerate(coefficients):
        if isinstance(coeff, MultiMeshFunction):
            multimesh_form.set_multimesh_coefficient(i, coeff._cpp_object)

    # Build multimesh form
    multimesh_form.build()

    # Create tensor
    comm = MPI.comm_world
    tensor = _create_tensor(comm, form, rank, backend, tensor)

    # Call C++ assemble function
    assembler = cpp.fem.MultiMeshAssembler()
    assembler.assemble(tensor, multimesh_form)

    # Convert to float for scalars
    if rank == 0:
        tensor = tensor.get_scalar_value()

    # Return value
    return tensor
Ejemplo n.º 22
0
def down_cast(foo):
    cpp.warning(
        "down_cast(foo) is deprecated, please use as_backend_type(foo).")
    return cpp.as_backend_type(foo)
Ejemplo n.º 23
0
def rD_errornorm(u,
                 uh,
                 D=None,
                 func_degree=None,
                 norm_type="l2",
                 degree_rise=3,
                 mesh=None):
    r"""
    This function is a modification of FEniCS's built-in errornorm function to adopt the :math:`r^2dr`
    measure as opposed to the standard Cartesian :math:`dx` one. For documentation and usage, see the 
    `standard module <https://github.com/FEniCS/dolfin/blob/master/site-packages/dolfin/fem/norms.py>`_.

    Also see :func:`rD_norm`.

    """

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

    # Get mesh
    if isinstance(u, Function) and mesh is None:
        mesh = u.function_space().mesh()
    if isinstance(uh, Function) and mesh is None:
        mesh = uh.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 rD_norm(e,
                   D,
                   func_degree=func_degree,
                   norm_type=norm_type,
                   mesh=mesh)
Ejemplo n.º 24
0
def mplot_function(ax, f, **kwargs):
    mesh = f.function_space().mesh()
    gdim = mesh.geometry().dim()
    tdim = mesh.topology().dim()

    # Extract the function vector in a way that also works for
    # subfunctions
    try:
        fvec = f.vector()
    except RuntimeError:
        fspace = f.function_space()
        try:
            fspace = fspace.collapse()
        # Happens for part of MultiMeshFunction; no way detecting elsewhere
        except RuntimeError:
            cpp.warning("Probably trying to plot MultiMeshFunction "
                        "part. Continuing without plotting...")
            return
        fvec = dolfin.interpolate(f, fspace).vector()

    if fvec.size() == mesh.num_cells():
        # DG0 cellwise function
        C = fvec.array(
        )  # NB! Assuming here dof ordering matching cell numbering
        if gdim == 2 and tdim == 2:
            return ax.tripcolor(mesh2triang(mesh), C, **kwargs)
        elif gdim == 3 and tdim == 2:  # surface in 3d
            # FIXME: Not tested, probably broken
            xy = mesh.coordinates()
            shade = kwargs.pop("shade", True)
            return ax.plot_trisurf(mesh2triang(mesh),
                                   xy[:, 2],
                                   C,
                                   shade=shade,
                                   **kwargs)
        elif gdim == 1 and tdim == 1:
            x = mesh.coordinates()[:, 0]
            nv = len(x)
            # Insert duplicate points to get piecewise constant plot
            xp = np.zeros(2 * nv - 2)
            xp[0] = x[0]
            xp[-1] = x[-1]
            xp[1:2 * nv - 3:2] = x[1:-1]
            xp[2:2 * nv - 2:2] = x[1:-1]
            Cp = np.zeros(len(xp))
            Cp[0:len(Cp) - 1:2] = C
            Cp[1:len(Cp):2] = C
            return ax.plot(xp, Cp, *kwargs)
        #elif tdim == 1: # FIXME: Plot embedded line
        else:
            raise AttributeError(
                'Matplotlib plotting backend only supports 2D mesh for scalar functions.'
            )

    elif f.value_rank() == 0:
        # Scalar function, interpolated to vertices
        # TODO: Handle DG1?
        C = f.compute_vertex_values(mesh)
        if gdim == 2 and tdim == 2:
            mode = kwargs.pop("mode", "contourf")
            if mode == "contourf":
                levels = kwargs.pop("levels", 40)
                return ax.tricontourf(mesh2triang(mesh), C, levels, **kwargs)
            elif mode == "color":
                shading = kwargs.pop("shading", "gouraud")
                return ax.tripcolor(mesh2triang(mesh),
                                    C,
                                    shading=shading,
                                    **kwargs)
            elif mode == "warp":
                from matplotlib import cm
                cmap = kwargs.pop("cmap", cm.jet)
                linewidths = kwargs.pop("linewidths", 0)
                return ax.plot_trisurf(mesh2triang(mesh),
                                       C,
                                       cmap=cmap,
                                       linewidths=linewidths,
                                       **kwargs)
            elif mode == "wireframe":
                return ax.triplot(mesh2triang(mesh), **kwargs)
            elif mode == "contour":
                return ax.tricontour(mesh2triang(mesh), C, **kwargs)
        elif gdim == 3 and tdim == 2:  # surface in 3d
            # FIXME: Not tested
            from matplotlib import cm
            cmap = kwargs.pop("cmap", cm.jet)
            return ax.plot_trisurf(mesh2triang(mesh), C, cmap=cmap, **kwargs)
        elif gdim == 3 and tdim == 3:
            # Volume
            # TODO: Isosurfaces?
            # Vertex point cloud
            X = [mesh.coordinates()[:, i] for i in range(gdim)]
            return ax.scatter(*X, c=C, **kwargs)
        elif gdim == 1 and tdim == 1:
            x = mesh.coordinates()[:, 0]
            ax.set_aspect('auto')

            # Setting limits for Line2D objects
            vmin = kwargs.pop("vmin", None)
            vmax = kwargs.pop("vmax", None)
            ax.set_ylim([vmin, vmax])
            return ax.plot(x, C, **kwargs)
        #elif tdim == 1: # FIXME: Plot embedded line
        else:
            raise AttributeError(
                'Matplotlib plotting backend only supports 2D mesh for scalar functions.'
            )

    elif f.value_rank() == 1:
        # Vector function, interpolated to vertices
        w0 = f.compute_vertex_values(mesh)
        nv = mesh.num_vertices()
        if len(w0) != gdim * nv:
            raise AttributeError(
                'Vector length must match geometric dimension.')
        X = mesh.coordinates()
        X = [X[:, i] for i in range(gdim)]
        U = [w0[i * nv:(i + 1) * nv] for i in range(gdim)]

        # Compute magnitude
        C = U[0]**2
        for i in range(1, gdim):
            C += U[i]**2
        C = np.sqrt(C)

        mode = kwargs.pop("mode", "glyphs")
        if mode == "glyphs":
            args = X + U + [C]
            if gdim == 3:
                # 3d quiver plot works only since matplotlib 1.4
                import matplotlib
                if StrictVersion(matplotlib.__version__) < '1.4':
                    cpp.warning('Matplotlib version %s does not support 3d '
                                'quiver plot. Continuing without plotting...' %
                                matplotlib.__version__)
                    return

                length = kwargs.pop("length", 0.1)
                return ax.quiver(*args, length=length, **kwargs)
            else:
                return ax.quiver(*args, **kwargs)
        elif mode == "displacement":
            Xdef = [X[i] + U[i] for i in range(gdim)]
            import matplotlib.tri as tri
            if gdim == 2 and tdim == 2:
                # FIXME: Not tested
                triang = tri.Triangulation(Xdef[0], Xdef[1], mesh.cells())
                shading = kwargs.pop("shading", "flat")
                return ax.tripcolor(triang, C, shading=shading, **kwargs)
            else:
                # Return gracefully to make regression test pass without vtk
                cpp.warning('Matplotlib plotting backend does not support '
                            'displacement for %d in %d. Continuing without '
                            'plotting...' % (tdim, gdim))
                return
Ejemplo n.º 25
0
def down_cast(foo):
    cpp.warning("down_cast(foo) is deprecated, please use as_backend_type(foo).")
    return cpp.as_backend_type(foo)
Ejemplo n.º 26
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 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 isinstance(uh, MultiMeshFunction):
        function_space = MultiMeshFunctionSpace
        vector_space = MultiMeshVectorFunctionSpace
        tensor_space = MultiMeshTensorFunctionSpace
        func = MultiMeshFunction
    else:
        function_space = FunctionSpace
        vector_space = VectorFunctionSpace
        tensor_space = TensorFunctionSpace
        func = Function

    if rank == 0:
        V = function_space(mesh, "Discontinuous Lagrange", degree)
    elif rank == 1:
        V = vector_space(mesh, "Discontinuous Lagrange", degree, dim=shape[0])
    elif rank > 1:
        V = tensor_space(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 = func(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.º 27
0
def _plot_matplotlib(obj, mesh, kwargs):
    if not isinstance(obj, _matplotlib_plottable_types):
        print("Don't know how to plot type %s." % type(obj))
        return

    # Plotting is not working with all ufl cells
    if mesh.ufl_cell().cellname() not in [
            'interval', 'triangle', 'tetrahedron'
    ]:
        raise AttributeError(
            ("Matplotlib plotting backend doesn't handle %s mesh.\n"
             "Possible options are saving the output to XDMF file.") %
            mesh.ufl_cell().cellname())

    # Avoid importing pyplot until used
    try:
        import matplotlib.pyplot as plt
    except Exception:
        cpp.warning("matplotlib.pyplot not available, cannot plot.")
        return

    gdim = mesh.geometry.dim
    if gdim == 3 or kwargs.get("mode") in ("warp", ):
        # Importing this toolkit has side effects enabling 3d support
        from mpl_toolkits.mplot3d import axes3d  # noqa
        # Enabling the 3d toolbox requires some additional arguments
        ax = plt.gca(projection='3d')
    else:
        ax = plt.gca()
    ax.set_aspect('equal')

    title = kwargs.pop("title", None)
    if title is not None:
        ax.set_title(title)

    # Translate range_min/max kwargs supported by VTKPlotter
    vmin = kwargs.pop("range_min", None)
    vmax = kwargs.pop("range_max", None)
    if vmin and "vmin" not in kwargs:
        kwargs["vmin"] = vmin
    if vmax and "vmax" not in kwargs:
        kwargs["vmax"] = vmax

    # Drop unsupported kwargs and inform user
    _unsupported_kwargs = ["rescale", "wireframe"]
    for kw in _unsupported_kwargs:
        if kwargs.pop(kw, None):
            cpp.warning("Matplotlib backend does not support '%s' kwarg yet. "
                        "Ignoring it..." % kw)

    if isinstance(obj, cpp.function.Function):
        return mplot_function(ax, obj, **kwargs)
    # elif isinstance(obj, cpp.function.Expression):
    #     return mplot_expression(ax, obj, mesh, **kwargs)
    elif isinstance(obj, cpp.mesh.Mesh):
        return mplot_mesh(ax, obj, **kwargs)
    elif isinstance(obj, cpp.fem.DirichletBC):
        return mplot_dirichletbc(ax, obj, **kwargs)
    elif isinstance(obj, _meshfunction_types):
        return mplot_meshfunction(ax, obj, **kwargs)
    else:
        raise AttributeError('Failed to plot %s' % type(obj))
Ejemplo n.º 28
0
def plot(object, *args, **kwargs):
    """
    Plot given object.

    *Arguments*
        object
            a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction
            <dolfin.cpp.MeshFunction>`, a :py:class:`Function
            <dolfin.functions.function.Function>`, a :py:class:`Expression`
            <dolfin.cpp.Expression>, a :py:class:`DirichletBC`
            <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement
            <ufl.FiniteElement>`.

    *Examples of usage*
        In the simplest case, to plot only e.g. a mesh, simply use

        .. code-block:: python

            mesh = UnitSquare(4,4)
            plot(mesh)

        Use the ``title`` argument to specify title of the plot

        .. code-block:: python

            plot(mesh, tite="Finite element mesh")

        It is also possible to plot an element

        .. code-block:: python

            element = FiniteElement("BDM", tetrahedron, 3)
            plot(element)

        Vector valued functions can be visualized with an alternative mode

        .. code-block:: python

            plot(u, mode = "glyphs")

        A more advanced example

        .. code-block:: python

            plot(u,
                 wireframe = True,              # use wireframe rendering
                 interactive = False,           # do not hold plot on screen
                 scalarbar = False,             # hide the color mapping bar
                 hardcopy_prefix = "myplot",    # default plotfile name
                 scale = 2.0                    # scale the warping/glyphs
                 title = "Fancy plot"           # Set your own title
                 )

    """

    mesh = kwargs.get('mesh')

    p = cpp.Parameters()
    for key in kwargs:
        # If there is a "mesh" kwarg it should not be added to the parameters
        if key != "mesh":
            try:
                p.add(key, kwargs[key])
            except TypeError:
                cpp.warning(
                    "Incompatible type for keyword argument \"%s\". Ignoring."
                    % key)

    # Plot element
    if isinstance(object, ufl.FiniteElementBase):
        if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return
        import ffc
        return ffc.plot(object, *args, **kwargs)

    if mesh is None and len(args) == 1 and isinstance(args[0], cpp.Mesh):
        mesh = args[0]

    # Plot expression
    if isinstance(object, cpp.Expression):
        if mesh is None:
            raise TypeError, "expected a mesh when plotting an expression."
        return cpp.plot(object, mesh, p)

    # Try to project if object is not a standard plottable type
    if not isinstance(
            object, (cpp.Function, cpp.Expression, cpp.Mesh, cpp.DirichletBC,
                     cpp.MeshFunction, cpp.MeshFunctionBool,
                     cpp.MeshFunctionInt, cpp.MeshFunctionDouble,
                     cpp.MeshFunctionSizet, cpp.DirichletBC, cpp.CSGGeometry)):

        from dolfin.fem.projection import project
        try:
            cpp.info("Object cannot be plotted directly, projecting to"\
                    " piecewise linears.")
            object = project(object, mesh=mesh)
        except Exception as e:
            msg = ("Don't know how to plot given object:\n  %s\n"\
                    "and projection failed:\n  %s") % (str(object), str(e))
            #raise RuntimeError(msg)
            raise

    plot_object = cpp.plot(object, p)
    plot_object.write_ps = _VTKPlotter_write_ps

    # Avoid premature deletion of plotted objects if they go out of scope
    # before the plot window is closed. The plotter itself is safe, since it's
    # created in the plot() C++ function, not directly from Python. But the
    # Python plotter proxy may disappear, so we can't store the references
    # there.
    global _objects_referenced_from_plot_windows
    _objects_referenced_from_plot_windows[plot_object.key()] = (object, mesh,
                                                                p)

    return plot_object
Ejemplo n.º 29
0
    def __init__(self, form, form_compiler_parameters=None):
        "Create JIT-compiled form from any given form (compiled or not)."

        # Check form argument
        if not isinstance(form, ufl.Form):
            cpp.dolfin_error("form.py",
                             "creating dolfin.Form",
                             "Expected a ufl.Form.")

        # Cutoff for better error message than ffc would give
        if not form.empty() and not form.domains():
            cpp.dolfin_error("form.py",
                             "creating dolfin.Form",
                             "The ufl.Form does not include any reference to a mesh.")

        # Extract subdomain data.
        # Until the assembler and ufc has multimesh support,
        # we impose the limitation of a single domain at this point.
        sd = form.subdomain_data()
        if len(sd) != 1:
            cpp.dolfin_error("form.py",
                             "creating dolfin.Form",
                             "Expecting subdomain data for a single domain only.")
        self.subdomains, = list(sd.values()) # Assuming single domain
        domain, = list(sd.keys()) # Assuming single domain
        mesh = domain.data()

        # Having a mesh in the form is now a strict requirement
        if mesh is None:
            cpp.dolfin_error("form.py",
                             "creating dolfin.Form",
                             "Expecting to find a Mesh in the form.")

        # Jit the module, this will take some time...
        self._compiled_form, module, prefix \
                             = jit(form, form_compiler_parameters,
                                   mpi_comm=mesh.mpi_comm())

        # Extract function spaces of form arguments
        self.function_spaces = [func.function_space() for func in form.arguments()]

        # Extract coefficients from form (pass only the ones that
        # the compiled form actually uses to the assembler)
        original_coefficients = form.coefficients()
        self.coefficients = []
        for i in range(self._compiled_form.num_coefficients()):
            j = self._compiled_form.original_coefficient_position(i)
            self.coefficients.append(original_coefficients[j])

        # Type checking argument function_spaces
        r = self._compiled_form.rank()
        if len(self.function_spaces) != r:
            raise ValueError(function_space_error +
                  " Wrong number of test spaces (should be %d)." % r)
        if not all(isinstance(fs, cpp.FunctionSpace) for fs in self.function_spaces):
            raise ValueError(function_space_error +
                  " Invalid type of test spaces.")

        # Type checking coefficients
        if not all(isinstance(c, cpp.GenericFunction) for c in self.coefficients):
            coefficient_error = "Error while extracting coefficients. "
            raise TypeError(coefficient_error +
                            "Either provide a dict of cpp.GenericFunctions, " +
                            "or use Function to define your form.")

        # Initialize base class
        cpp.Form.__init__(self, self._compiled_form,
                          self.function_spaces, self.coefficients)

        # Attach mesh (because function spaces and coefficients may be empty lists)
        self.set_mesh(mesh)


        # Type checking subdomain data
        # Delete None entries
        for k in list(self.subdomains.keys()):
            if self.subdomains[k] is None:
                del self.subdomains[k]
        # Check that we have no additional subdomain data (user misspelling)
        # TODO: Get from ufl list?
        integral_types = ("cell", "exterior_facet", "interior_facet", "vertex")
        additional_keys = set(self.subdomains.keys()) - set(integral_types)
        if additional_keys:
            cpp.warning("Invalid keys in subdomains: %s" % additional_keys)
        # Check that we have only MeshFunctions
        for data in list(self.subdomains.values()):
            if not (data is None or isinstance(data, MeshFunctionSizet)):
                cpp.warning("Invalid subdomain data type %s, expecting a MeshFunction" % type(data))

        # Attach subdomains to C++ Form if we have them
        subdomains = self.subdomains.get("cell")
        if subdomains is not None:
            self.set_cell_domains(subdomains)
        subdomains = self.subdomains.get("exterior_facet")
        if subdomains is not None:
            self.set_exterior_facet_domains(subdomains)
        subdomains = self.subdomains.get("interior_facet")
        if subdomains is not None:
            self.set_interior_facet_domains(subdomains)
        subdomains = self.subdomains.get("vertex")
        if subdomains is not None:
            self.set_vertex_domains(subdomains)
Ejemplo n.º 30
0
def plot(object, *args, **kwargs):
    """
    Plot given object.

    *Arguments*
        object
            a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction
            <dolfin.cpp.MeshFunction>`, a :py:class:`Function
            <dolfin.functions.function.Function>`, a :py:class:`Expression`
            <dolfin.cpp.Expression>, a :py:class:`DirichletBC`
            <dolfin.cpp.DirichletBC>, a :py:class:`FiniteElement
            <ufl.FiniteElement>`, or a :py:class:`MultiMesh
            <dolfin.cpp.MultiMesh>`.

    *Examples of usage*
        In the simplest case, to plot only e.g. a mesh, simply use

        .. code-block:: python

            mesh = UnitSquare(4,4)
            plot(mesh)

        Use the ``title`` argument to specify title of the plot

        .. code-block:: python

            plot(mesh, tite="Finite element mesh")

        It is also possible to plot an element

        .. code-block:: python

            element = FiniteElement("BDM", tetrahedron, 3)
            plot(element)

        Vector valued functions can be visualized with an alternative mode

        .. code-block:: python

            plot(u, mode = "glyphs")

        A more advanced example

        .. code-block:: python

            plot(u,
                 wireframe = True,              # use wireframe rendering
                 interactive = False,           # do not hold plot on screen
                 scalarbar = False,             # hide the color mapping bar
                 hardcopy_prefix = "myplot",    # default plotfile name
                 scale = 2.0,                   # scale the warping/glyphs
                 title = "Fancy plot",          # set your own title
                 backend = "vtk"                # choose plotting backend
                 )

    """

    # Plot element
    if isinstance(object, ufl.FiniteElementBase):
        if os.environ.get("DOLFIN_NOPLOT", "0") != "0":
            return
        import ffc
        return ffc.plot(object, *args, **kwargs)

    # Get mesh from explicit mesh kwarg, only positional arg, or via object
    mesh = kwargs.pop('mesh', None)
    if isinstance(object, cpp.Mesh):
        if mesh is not None and mesh.id() != object.id():
            cpp.dolfin_error(
                "plotting.py", "plot mesh",
                "Got different mesh in plot object and keyword argument")
        mesh = object
    if mesh is None:
        if isinstance(object, cpp.Function):
            mesh = object.function_space().mesh()
        elif hasattr(object, "mesh"):
            mesh = object.mesh()

    # Expressions do not carry their own mesh
    if isinstance(object, cpp.Expression) and mesh is None:
        cpp.dolfin_error("plotting.py", "plot expression",
                         "Expecting a mesh as keyword argument")

    # Try to project if object is not a standard plottable type
    if not isinstance(object, _plottable_types):
        from dolfin.fem.projection import project
        try:
            cpp.info("Object cannot be plotted directly, projecting to"\
                     " piecewise linears.")
            object = project(object, mesh=mesh)
            mesh = object.function_space().mesh()
        except Exception as e:
            msg = "Don't know how to plot given object:\n  %s\n" \
                  "and projection failed:\n  %s" % (str(object), str(e))
            cpp.dolfin_error("plotting.py", "plot object", msg)

    # Select backend
    backend = kwargs.pop("backend", None) or cpp.parameters["plotting_backend"]
    if backend == "vtk":
        return _plot_cpp(object, mesh, kwargs)
    elif backend == "matplotlib":
        return _plot_matplotlib(object, mesh, kwargs)
    elif backend == "none":
        cpp.warning("Plotting backend set to 'none'. Plotting disabled.")
        return
    else:
        cpp.dolfin_error("plotting.py", "plot object",
                         "Unknown plotting backend '%s'" % backend)
Ejemplo n.º 31
0
def plot(object, *args, **kwargs):
    """
    Plot given object.

    *Arguments*
        object
            a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction
            <dolfin.cpp.MeshFunction>`, a :py:class:`Function
            <dolfin.functions.function.Function>`, a :py:class:`Expression`
            <dolfin.cpp.Expression>, a :py:class:`DirichletBC`
            <dolfin.cpp.DirichletBC>, a :py:class:`FiniteElement
            <ufl.FiniteElement>`, or a :py:class:`MultiMesh
            <dolfin.cpp.MultiMesh>`.

    *Examples of usage*
        In the simplest case, to plot only e.g. a mesh, simply use

        .. code-block:: python

            mesh = UnitSquare(4,4)
            plot(mesh)

        Use the ``title`` argument to specify title of the plot

        .. code-block:: python

            plot(mesh, tite="Finite element mesh")

        It is also possible to plot an element

        .. code-block:: python

            element = FiniteElement("BDM", tetrahedron, 3)
            plot(element)

        Vector valued functions can be visualized with an alternative mode

        .. code-block:: python

            plot(u, mode = "glyphs")

        A more advanced example

        .. code-block:: python

            plot(u,
                 wireframe = True,              # use wireframe rendering
                 interactive = False,           # do not hold plot on screen
                 scalarbar = False,             # hide the color mapping bar
                 hardcopy_prefix = "myplot",    # default plotfile name
                 scale = 2.0,                   # scale the warping/glyphs
                 title = "Fancy plot",          # set your own title
                 backend = "vtk"                # choose plotting backend
                 )

    """

    # Plot element
    if isinstance(object, ufl.FiniteElementBase):
        if os.environ.get("DOLFIN_NOPLOT", "0") != "0":
            return
        import ffc
        return ffc.plot(object, *args, **kwargs)

    # Get mesh from explicit mesh kwarg, only positional arg, or via object
    mesh = kwargs.pop('mesh', None)
    if isinstance(object, cpp.Mesh):
        if mesh is not None and mesh.id() != object.id():
            cpp.dolfin_error("plotting.py",
                             "plot mesh",
                             "Got different mesh in plot object and keyword argument")
        mesh = object
    if mesh is None:
        if isinstance(object, cpp.Function):
            mesh = object.function_space().mesh()
        elif hasattr(object, "mesh"):
            mesh = object.mesh()

    # Expressions do not carry their own mesh
    if isinstance(object, cpp.Expression) and mesh is None:
        cpp.dolfin_error("plotting.py",
                         "plot expression",
                         "Expecting a mesh as keyword argument")

    # Try to project if object is not a standard plottable type
    if not isinstance(object, _plottable_types):
        from dolfin.fem.projection import project
        try:
            cpp.info("Object cannot be plotted directly, projecting to"\
                     " piecewise linears.")
            object = project(object, mesh=mesh)
            mesh = object.function_space().mesh()
        except Exception as e:
            msg = "Don't know how to plot given object:\n  %s\n" \
                  "and projection failed:\n  %s" % (str(object), str(e))
            cpp.dolfin_error("plotting.py", "plot object", msg)

    # Select backend
    backend = kwargs.pop("backend", None) or cpp.parameters["plotting_backend"]
    if backend == "vtk":
        return _plot_cpp(object, mesh, kwargs)
    elif backend == "matplotlib":
        return _plot_matplotlib(object, mesh, kwargs)
    elif backend == "none":
        cpp.warning("Plotting backend set to 'none'. Plotting disabled.")
        return
    else:
        cpp.dolfin_error("plotting.py", "plot object",
                         "Unknown plotting backend '%s'" % backend)
Ejemplo n.º 32
0
def _down_cast(self):
    cpp.warning(
        "foo.down_cast() is deprecated, please use as_backend_type(foo).")
    return cpp.as_backend_type(self)
Ejemplo n.º 33
0
    def __init__(self,
                 form,
                 form_compiler_parameters=None,
                 function_spaces=None):
        "Create JIT-compiled form from any given form (compiled or not)."

        # Developer note: The function_spaces argument is used to
        # handle forms defined on multimesh function spaces. These are
        # really defined over a standard function space (the first of
        # the spaces) then later recreated on each function space part
        # and added together to form a multimesh form. This happens in
        # the function assemble_multimesh.

        # Check form argument
        if not isinstance(form, ufl.Form):
            cpp.dolfin_error("form.py", "creating dolfin.Form",
                             "Expected a ufl.Form.")

        # Cutoff for better error message than ffc would give
        if not form.empty() and not form.ufl_domains():
            cpp.dolfin_error(
                "form.py", "creating dolfin.Form",
                "The ufl.Form does not include any reference to a mesh.")

        # Extract subdomain data.
        # Until the assembler and ufc has multimesh support,
        # we impose the limitation of a single domain at this point.
        sd = form.subdomain_data()
        if len(sd) != 1:
            cpp.dolfin_error(
                "form.py", "creating dolfin.Form",
                "Expecting subdomain data for a single domain only.")
        self.subdomains, = list(sd.values())  # Assuming single domain
        domain, = list(sd.keys())  # Assuming single domain
        mesh = domain.ufl_cargo()

        # Having a mesh in the form is now a strict requirement
        if mesh is None:
            cpp.dolfin_error("form.py", "creating dolfin.Form",
                             "Expecting to find a Mesh in the form.")

        # Jit the module, this will take some time...
        jit_result = jit(form,
                         form_compiler_parameters,
                         mpi_comm=mesh.mpi_comm())
        if jit_result is None:
            cpp.dolfin_error("form.py", "creating dolfin.Form", "jit failure.")
        self._compiled_form, module, prefix = jit_result

        # Extract function spaces of form arguments
        if function_spaces is None:
            self.function_spaces = [
                func.function_space() for func in form.arguments()
            ]
        else:
            self.function_spaces = function_spaces

        # Type checking argument function_spaces
        if not all(
                isinstance(fs, cpp.FunctionSpace)
                for fs in self.function_spaces):
            raise ValueError(function_space_error +
                             " Invalid type of test spaces.")

        # Initialize base class
        cpp.Form.__init__(self, self._compiled_form, self.function_spaces)

        # Type checking argument function_spaces
        #r = self._compiled_form.rank()
        #if len(self.function_spaces) != r:
        #    raise ValueError(function_space_error +
        #                     " Wrong number of test spaces (should be %d)." % r)

        # Extract coefficients from form (pass only the ones that
        # the compiled form actually uses to the assembler)
        original_coefficients = form.coefficients()
        self.coefficients = []
        for i in range(self.num_coefficients()):
            j = self.original_coefficient_position(i)
            self.coefficients.append(original_coefficients[j])

        # Type checking coefficients
        if not all(
                isinstance(c, (cpp.GenericFunction, cpp.MultiMeshFunction))
                for c in self.coefficients):
            # Developer note:
            # The form accepts a MultiMeshFunction but does not set the
            # correct coefficients. This is done in assemble_multimesh
            # at the moment
            coefficient_error = "Error while extracting coefficients. "
            raise TypeError(coefficient_error +
                            "Either provide a dict of cpp.GenericFunctions, " +
                            "or use Function to define your form.")

        for i in range(self.num_coefficients()):
            if isinstance(self.coefficients[i], cpp.GenericFunction):
                self.set_coefficient(i, self.coefficients[i])

        # Attach mesh (because function spaces and coefficients may be
        # empty lists)
        if not function_spaces:
            self.set_mesh(mesh)
        # Type checking subdomain data
        # Delete None entries
        for k in list(self.subdomains.keys()):
            if self.subdomains[k] is None:
                del self.subdomains[k]
        # Check that we have no additional subdomain data (user
        # misspelling)
        # TODO: Get from ufl list?
        integral_types = ("cell", "exterior_facet", "interior_facet", "vertex")
        additional_keys = set(self.subdomains.keys()) - set(integral_types)
        if additional_keys:
            cpp.warning("Invalid keys in subdomains: %s" % additional_keys)
        # Check that we have only MeshFunctions
        for data in list(self.subdomains.values()):
            if not (data is None or isinstance(data, MeshFunctionSizet)):
                cpp.warning(
                    "Invalid subdomain data type %s, expecting a MeshFunction"
                    % type(data))

        # Attach subdomains to C++ Form if we have them
        subdomains = self.subdomains.get("cell")
        if subdomains is not None:
            self.set_cell_domains(subdomains)
        subdomains = self.subdomains.get("exterior_facet")
        if subdomains is not None:
            self.set_exterior_facet_domains(subdomains)
        subdomains = self.subdomains.get("interior_facet")
        if subdomains is not None:
            self.set_interior_facet_domains(subdomains)
        subdomains = self.subdomains.get("vertex")
        if subdomains is not None:
            self.set_vertex_domains(subdomains)
Ejemplo n.º 34
0
def _down_cast(self):
    cpp.warning("foo.down_cast() is deprecated, please use as_backend_type(foo).")
    return cpp.as_backend_type(self)
Ejemplo n.º 35
0
def plot(object, *args, **kwargs):
    """
    Plot given object.

    *Arguments*
        object
            a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction
            <dolfin.cpp.MeshFunction>`, a :py:class:`Function
            <dolfin.functions.function.Function>`, a :py:class:`Expression`
            <dolfin.cpp.Expression>, a :py:class:`DirichletBC`
            <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement
            <ufl.FiniteElement>`.

    *Examples of usage*
        In the simplest case, to plot only e.g. a mesh, simply use

        .. code-block:: python

            mesh = UnitSquare(4,4)
            plot(mesh)

        Use the ``title`` argument to specify title of the plot

        .. code-block:: python

            plot(mesh, tite="Finite element mesh")

        It is also possible to plot an element

        .. code-block:: python

            element = FiniteElement("BDM", tetrahedron, 3)
            plot(element)

        Vector valued functions can be visualized with an alternative mode

        .. code-block:: python

            plot(u, mode = "glyphs")

        A more advanced example

        .. code-block:: python

            plot(u,
                 wireframe = True,              # use wireframe rendering
                 interactive = False,           # do not hold plot on screen
                 scalarbar = False,             # hide the color mapping bar
                 hardcopy_prefix = "myplot",    # default plotfile name
                 scale = 2.0                    # scale the warping/glyphs
                 title = "Fancy plot"           # Set your own title
                 )

    """

    mesh = kwargs.get('mesh')

    p = cpp.Parameters()
    for key in kwargs:
        # If there is a "mesh" kwarg it should not be added to the parameters
        if key != "mesh":
            try:
                p.add(key, kwargs[key])
            except TypeError:
                cpp.warning("Incompatible type for keyword argument \"%s\". Ignoring." % key)

    # Plot element
    if isinstance(object, ufl.FiniteElementBase):
        if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return
        import ffc
        return ffc.plot(object, *args, **kwargs)

    if mesh is None and len(args) == 1 and isinstance(args[0], cpp.Mesh):
        mesh = args[0]

    # Plot expression
    if isinstance(object, cpp.Expression):
        if mesh is None:
            raise TypeError, "expected a mesh when plotting an expression."
        return cpp.plot(object, mesh, p)

    # Try to project if object is not a standard plottable type
    if not isinstance(object, (cpp.Function, cpp.Expression, cpp.Mesh,
        cpp.DirichletBC, cpp.MeshFunction, cpp.MeshFunctionBool,
        cpp.MeshFunctionInt, cpp.MeshFunctionDouble,
        cpp.MeshFunctionSizet, cpp.DirichletBC, cpp.CSGGeometry)):

        from dolfin.fem.projection import project
        try:
            cpp.info("Object cannot be plotted directly, projecting to"\
                    " piecewise linears.")
            object = project(object, mesh=mesh)
        except Exception as e:
            msg = ("Don't know how to plot given object:\n  %s\n"\
                    "and projection failed:\n  %s") % (str(object), str(e))
            #raise RuntimeError(msg)
            raise

    plot_object = cpp.plot(object, p)
    plot_object.write_ps = _VTKPlotter_write_ps

    # Avoid premature deletion of plotted objects if they go out of scope
    # before the plot window is closed. The plotter itself is safe, since it's
    # created in the plot() C++ function, not directly from Python. But the
    # Python plotter proxy may disappear, so we can't store the references
    # there.
    global _objects_referenced_from_plot_windows
    _objects_referenced_from_plot_windows[plot_object.key()] = (object, mesh, p)

    return plot_object
Ejemplo n.º 36
0
def assemble_multimesh(form,
                       tensor=None,
                       form_compiler_parameters=None,
                       backend=None):
    "Assemble the given multimesh form and return the corresponding tensor."

    # The form that comes in is (by construction in function.Argument)
    # defined on the first part of the multimesh. We now need to create
    # the DOLFIN Forms with the proper function spaces for each part.

    # FIXME: This code makes a number of assumptions and will need to
    # be revisited and improved.

    # Warn that we don't use the parameters if we get any
    if form_compiler_parameters is not None:
        cpp.warning("Ignoring form_compiler_parameters when passed a dolfin Form!")
    form_compiler_parameters = None

    # Extract arguments and multimesh function space
    coefficients = form.coefficients()
    arguments = form.arguments()

    # Extract rank
    rank = len(arguments)

    # Extract multimesh function spaces for arguments
    V_multi = [v._V_multi for v in arguments]

    # Extract number of parts, the multimesh and create the multimesh form
    num_parts = None
    if rank > 0:
        num_parts = V_multi[0].num_parts()
        multimesh_form = cpp.fem.MultiMeshForm(*V_multi)
        multimesh = V_multi[0].multimesh()
    elif len(coefficients) > 0:
        for coeff in coefficients:
            # Only create these variables once
            if isinstance(coeff, MultiMeshFunction):
                multimesh = coeff.function_space().multimesh()
                num_parts = coeff.function_space().num_parts()
                multimesh_form = cpp.fem.MultiMeshForm(multimesh)
                break

    if not num_parts:
        # Handle the case Constant(1)*dx(domain=multimesh)
        multimesh = form.ufl_domains()[0].ufl_cargo()
        num_parts = multimesh.num_parts()
        multimesh_form = cpp.fem.MultiMeshForm(multimesh)

    # Build multimesh DOLFIN form
    for part in range(num_parts):
        # Extract standard function spaces for all arguments on
        # current part
        function_spaces = [V_multi[i].part(part) for i in range(rank)]
        # Wrap standard form
        dolfin_form = _create_dolfin_form(form,
                                          form_compiler_parameters,
                                          function_spaces)

        # Setting coefficients for the multimesh form
        for i in range(len(coefficients)):
            if isinstance(coefficients[i], MultiMeshFunction):
                coeff = coefficients[i].part(part)
            else:
                coeff = coefficients[i]
            # Developer note: This may be done more elegantly by modifiying
            # _create_dolfin_form
            dolfin_form.set_coefficient(i, coeff._cpp_object)
            dolfin_form.coefficients[i] = coeff

        # Add standard mesh to the standard form and the
        # standard form to the multimesh form
        dolfin_form.set_mesh(multimesh.part(part))
        multimesh_form.add(dolfin_form)

    for i, coeff in enumerate(coefficients):
        if isinstance(coeff, MultiMeshFunction):
            multimesh_form.set_multimesh_coefficient(i, coeff._cpp_object)

    # Build multimesh form
    multimesh_form.build()

    # Create tensor
    comm = MPI.comm_world
    tensor = _create_tensor(comm, form, rank, backend, tensor)

    # Call C++ assemble function
    assembler = cpp.fem.MultiMeshAssembler()
    assembler.assemble(tensor, multimesh_form)

    # Convert to float for scalars
    if rank == 0:
        tensor = tensor.get_scalar_value()

    # Return value
    return tensor