Example #1
0
File: ale.py Project: alogg/dolfin
def init_parent_edge_indices(submesh, mesh):
    "Initialize data 'parent_edge_indices' for submesh."

    # Check arguments
    if not isinstance(submesh, Mesh):
        raise TypeError, "expected 'Mesh' as argument"
    if not isinstance(mesh, Mesh):
        raise TypeError, "expected 'Mesh' as argument"

    # Check if edge map has already been computed
    if not submesh.data().mesh_function("parent_edge_indices") is None:
        info("Edge map 'parent_edge_indices' already computed, not computing again.")

    # Get parent vertex numbers
    parent_vertex_indices = submesh.data().mesh_function("parent_vertex_indices")
    if parent_vertex_indices is None:
        cpp.dolfin_error("ale.py",
                         "initialize parent edge indices",
                         "Parent vertex indice are missing")

    # Make sure that we have edges for both meshes
    submesh.init(1)
    mesh.init(1)

    # Make sure we have vertex-edge connectivity for parent mesh
    mesh.init(0, 1)

    # Create the edge map
    parent_edge_indices = submesh.data().create_mesh_function("parent_edge_indices")
    parent_edge_indices.init(1)

    # Iterate over the edges and figure out their parent number
    for local_edge in edges(submesh):

        # Get parent indices for edge vertices
        v0, v1 = local_edge.entities(0)
        V0 = Vertex(mesh, parent_vertex_indices[int(v0)])
        V1 = Vertex(mesh, parent_vertex_indices[int(v1)])

        # Get outgoing edges from the two parent vertices
        edges0 = set(V0.entities(1))
        edges1 = set(V1.entities(1))

        # Check intersection
        common_edges = edges0.intersection(edges1)
        if not len(common_edges) == 1:
            cpp.dolfin_error("ale.py",
                             "initialize parent edge indices",
                             "Parent vertices do not share exactly one common edge")
        parent_edge_index = list(common_edges)[0]

        # Set value
        parent_edge_indices[local_edge.index()] = parent_edge_index
Example #2
0
def _solve_varproblem_adaptive(*args, **kwargs):
    "Solve variational problem a == L or F == 0 adaptively"

    # Extract arguments
    eq, u, bcs, J, tol, M, form_compiler_parameters, \
        solver_parameters = _extract_args(*args, **kwargs)

    # Check that we received the goal functional
    if M is None:
        cpp.dolfin_error("solving.py", "solve variational problem adaptively",
                         "Missing goal functional")

    # Solve linear variational problem
    if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form):

        # Create problem
        problem = LinearVariationalProblem(
            eq.lhs,
            eq.rhs,
            u,
            bcs,
            form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = AdaptiveLinearVariationalSolver(problem, M)
        solver.parameters.update(solver_parameters)
        solver.solve(tol)

    # Solve nonlinear variational problem
    else:

        # Create Jacobian if missing
        if J is None:
            cpp.info(
                "No Jacobian form specified for nonlinear variational problem."
            )
            cpp.info(
                "Differentiating residual form F to obtain Jacobian J = F'.")
            F = eq.lhs
            J = derivative(F, u)

        # Create problem
        problem = NonlinearVariationalProblem(
            eq.lhs,
            u,
            bcs,
            J,
            form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = AdaptiveNonlinearVariationalSolver(problem, M)
        solver.parameters.update(solver_parameters)
        solver.solve(tol)
Example #3
0
def init_parent_edge_indices(submesh, mesh):
    "Initialize data 'parent_edge_indices' for submesh."

    # Check arguments
    if not isinstance(submesh, Mesh):
        raise TypeError("expected 'Mesh' as argument")
    if not isinstance(mesh, Mesh):
        raise TypeError("expected 'Mesh' as argument")

    # Check if edge map has already been computed
    if not submesh.data().exists("parent_edge_indices", 1):
        info(
            "Edge map 'parent_edge_indices' already computed, not computing again."
        )

    # Get parent vertex numbers
    parent_vertex_indices = submesh.data().array("parent_vertex_indices", 0)
    if parent_vertex_indices is None:
        cpp.dolfin_error("ale.py", "initialize parent edge indices",
                         "Parent vertex indice are missing")

    # Make sure that we have edges for both meshes
    submesh.init(1)
    mesh.init(1)

    # Make sure we have vertex-edge connectivity for parent mesh
    mesh.init(0, 1)

    # Create the edge map
    parent_edge_indices = submesh.data().create_array("parent_edge_indices", 1)

    # Iterate over the edges and figure out their parent number
    for local_edge in edges(submesh):

        # Get parent indices for edge vertices
        v0, v1 = local_edge.entities(0)
        V0 = Vertex(mesh, parent_vertex_indices[int(v0)])
        V1 = Vertex(mesh, parent_vertex_indices[int(v1)])

        # Get outgoing edges from the two parent vertices
        edges0 = set(V0.entities(1))
        edges1 = set(V1.entities(1))

        # Check intersection
        common_edges = edges0.intersection(edges1)
        if not len(common_edges) == 1:
            cpp.dolfin_error(
                "ale.py", "initialize parent edge indices",
                "Parent vertices do not share exactly one common edge")
        parent_edge_index = list(common_edges)[0]

        # Set value
        parent_edge_indices[local_edge.index()] = parent_edge_index
Example #4
0
def _solve_varproblem(*args, **kwargs):
    "Solve variational problem a == L or F == 0"

    # Extract arguments
    eq, u, bcs, J, tol, M, form_compiler_parameters, solver_parameters \
        = _extract_args(*args, **kwargs)

    # Solve linear variational problem
    if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form):

        # Create problem
        problem = LinearVariationalProblem(
            eq.lhs,
            eq.rhs,
            u,
            bcs,
            form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = LinearVariationalSolver(problem)
        solver.parameters.update(solver_parameters)
        solver.solve()

    # Solve nonlinear variational problem
    else:

        # Create Jacobian if missing
        if J is None:
            cpp.info(
                "No Jacobian form specified for nonlinear variational problem."
            )
            cpp.info(
                "Differentiating residual form F to obtain Jacobian J = F'.")
            F = eq.lhs
            J = derivative(F, u)

        # Create problem
        problem = NonlinearVariationalProblem(
            eq.lhs,
            u,
            bcs,
            J,
            form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = NonlinearVariationalSolver(problem)
        solver.parameters.update(solver_parameters)
        solver.solve()
Example #5
0
def _solve_varproblem_adaptive(*args, **kwargs):
    "Solve variational problem a == L or F == 0 adaptively"

    # Extract arguments
    eq, u, bcs, J, tol, M, form_compiler_parameters, solver_parameters \
        = _extract_args(*args, **kwargs)

    # Check that we received the goal functional
    if M is None:
        cpp.dolfin_error("solving.py",
                         "solve variational problem adaptively",
                         "Missing goal functional")

    # Solve linear variational problem
    if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form):

        # Create problem
        problem = LinearVariationalProblem(eq.lhs, eq.rhs, u, bcs,
                    form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = AdaptiveLinearVariationalSolver(problem, M)
        solver.parameters.update(solver_parameters)
        solver.solve(tol)

    # Solve nonlinear variational problem
    else:

        # Create Jacobian if missing
        if J is None:
            cpp.info("No Jacobian form specified for nonlinear variational problem.")
            cpp.info("Differentiating residual form F to obtain Jacobian J = F'.")
            F = eq.lhs
            J = derivative(F, u)

        # Create problem
        problem = NonlinearVariationalProblem(eq.lhs, u, bcs, J,
                    form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = AdaptiveNonlinearVariationalSolver(problem, M)
        solver.parameters.update(solver_parameters)
        solver.solve(tol)
def generate_error_control_forms(problem, goal):
    """
    Create UFL forms required for initializing an ErrorControl object

    *Arguments*

        problem (:py:class:`LinearVariationalProblem <dolfin.fem.solving.LinearVariationalProblem>` or :py:class:`NonlinearVariationalProblem <dolfin.fem.solving.NonlinearVariationalProblem>`)

            The (primal) problem

        goal (:py:class:`Form <dolfin.fem.form.Form>`)

            The goal functional

    *Returns*

        (tuple of forms, bool)

    """

    msg = "Generating forms required for error control, this may take some time..."
    cpp.info(msg)

    # Extract primal forms from problem
    is_linear = True
    if isinstance(problem, LinearVariationalProblem):
        primal = (problem.a_ufl, problem.L_ufl)
    elif isinstance(problem, NonlinearVariationalProblem):
        is_linear = False
        primal = problem.F_ufl
    else:
        cpp.dolfin_error("adaptivesolving.py",
                         "generate forms required for error control",
                         "Unknown problem type (\"%s\")" % str(problem))

    # Extract unknown Function from problem
    u = problem.u_ufl

    # Get DOLFIN's error control generator to generate all forms
    generator = DOLFINErrorControlGenerator(primal, goal, u)
    forms = generator.generate_all_error_control_forms()

    return (forms, is_linear)
Example #7
0
def _solve_varproblem(*args, **kwargs):
    "Solve variational problem a == L or F == 0"

    # Extract arguments
    eq, u, bcs, J, tol, M, form_compiler_parameters, solver_parameters \
        = _extract_args(*args, **kwargs)

    # Solve linear variational problem
    if isinstance(eq.lhs, ufl.Form) and isinstance(eq.rhs, ufl.Form):

        # Create problem
        problem = LinearVariationalProblem(eq.lhs, eq.rhs, u, bcs,
                    form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = LinearVariationalSolver(problem)
        solver.parameters.update(solver_parameters)
        solver.solve()

    # Solve nonlinear variational problem
    else:

        # Create Jacobian if missing
        if J is None:
            cpp.info("No Jacobian form specified for nonlinear variational problem.")
            cpp.info("Differentiating residual form F to obtain Jacobian J = F'.")
            F = eq.lhs
            J = derivative(F, u)

        # Create problem
        problem = NonlinearVariationalProblem(eq.lhs, u, bcs, J,
                    form_compiler_parameters=form_compiler_parameters)

        # Create solver and call solve
        solver = NonlinearVariationalSolver(problem)
        solver.parameters.update(solver_parameters)
        solver.solve()
Example #8
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
Example #9
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
                 )

    """

    # 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)
        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 = cpp.parameters["plotting_backend"]
    if backend == "vtk":
        return _plot_cpp(object, mesh, kwargs)
    elif backend == "matplotlib":
        return _plot_matplotlib(object, mesh, kwargs)
Example #10
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
                 )

    """

    # 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)
        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 = cpp.parameters["plotting_backend"]
    if backend == "vtk":
        return _plot_cpp(object, mesh, kwargs)
    elif backend == "matplotlib":
        return _plot_matplotlib(object, mesh, kwargs)
Example #11
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
Example #12
0
def generate_error_control_forms(problem, goal):
    """
    Create UFL forms required for initializing an ErrorControl object

    *Arguments*

        problem (:py:class:`LinearVariationalProblem <dolfin.fem.solving.LinearVariationalProblem>` or :py:class:`NonlinearVariationalProblem <dolfin.fem.solving.NonlinearVariationalProblem>`)

            The (primal) problem

        goal (:py:class:`Form <dolfin.fem.form.Form>`)

            The goal functional

    *Returns*

        (tuple of forms, bool)

    """

    msg = "Generating forms required for error control, this may take some time..."
    cpp.info(msg)

    # Paranoid checks added after introduction of multidomain features in ufl:
    for form in [goal]:
        assert len(form.ufl_domains()) > 0, "Error control got as input a form with no domain!"
        assert len(form.ufl_domains()) == 1, "Error control got as input a form with more than one domain!"

    # Extract primal forms from problem
    is_linear = True
    if isinstance(problem, LinearVariationalProblem):
        primal = (problem.a_ufl, problem.L_ufl)

        # Paranoid checks added after introduction of multidomain features in ufl:
        for form in primal:
            assert len(form.ufl_domains()) > 0, "Error control got as input a form with no domain!"
            assert len(form.ufl_domains()) == 1, "Error control got as input a form with more than one domain!"

    elif isinstance(problem, NonlinearVariationalProblem):
        is_linear = False
        primal = problem.F_ufl

        # Paranoid checks added after introduction of multidomain features in ufl:
        for form in [primal]:
            assert len(form.ufl_domains()) > 0, "Error control got as input a form with no domain!"
            assert len(form.ufl_domains()) == 1, "Error control got as input a form with more than one domain!"

    else:
        cpp.dolfin_error("adaptivesolving.py",
                         "generate forms required for error control",
                         "Unknown problem type (\"%s\")" % str(problem))

    # Extract unknown Function from problem
    u = problem.u_ufl

    # Get DOLFIN's error control generator to generate all forms
    generator = DOLFINErrorControlGenerator(primal, goal, u)
    forms = generator.generate_all_error_control_forms()

    # Paranoid checks added after introduction of multidomain features in ufl:
    for form in forms:
        assert len(form.ufl_domains()) > 0, "Error control produced a form with no domain!"
        assert len(form.ufl_domains()) == 1, "Error control produced a form with more than one domain!"

    return (forms, is_linear)