# Source code for fe_utils.finite_elements

```# Cause division to always mean floating point division.
from __future__ import division
import numpy as np
from .reference_elements import ReferenceInterval, ReferenceTriangle
np.seterr(invalid='ignore', divide='ignore')

[docs]def lagrange_points(cell, degree):
"""Construct the locations of the equispaced Lagrange nodes on cell.

:param cell: the :class:`~.reference_elements.ReferenceCell`
:param degree: the degree of polynomials for which to construct nodes.

:returns: a rank 2 :class:`~numpy.array` whose rows are the
coordinates of the nodes.

The implementation of this function is left as an :ref:`exercise
<ex-lagrange-points>`.

"""

raise NotImplementedError

"""Construct the generalised Vandermonde matrix for polynomials of the
specified degree on the cell provided.

:param cell: the :class:`~.reference_elements.ReferenceCell`
:param degree: the degree of polynomials for which to construct the matrix.
:param points: a list of coordinate tuples corresponding to the points.

:returns: the generalised :ref:`Vandermonde matrix <sec-vandermonde>`

The implementation of this function is left as an :ref:`exercise
<ex-vandermonde>`.
"""

raise NotImplementedError

[docs]class FiniteElement(object):
def __init__(self, cell, degree, nodes, entity_nodes=None):
"""A finite element defined over cell.

:param cell: the :class:`~.reference_elements.ReferenceCell`
over which the element is defined.
:param degree: the
polynomial degree of the element. We assume the element
spans the complete polynomial space.
:param nodes: a list of coordinate tuples corresponding to
point evaluation node locations on the element.
:param entity_nodes: a dictionary of dictionaries such that
entity_nodes[d][i] is the list of nodes associated with
entity `(d, i)` of dimension `d` and index `i`.

Most of the implementation of this class is left as exercises.
"""

#: The :class:`~.reference_elements.ReferenceCell`
#: over which the element is defined.
self.cell = cell
#: The polynomial degree of the element. We assume the element
#: spans the complete polynomial space.
self.degree = degree
#: The list of coordinate tuples corresponding to the nodes of
#: the element.
self.nodes = nodes
#: A dictionary of dictionaries such that ``entity_nodes[d][i]``
#: is the list of nodes associated with entity `(d, i)`.
self.entity_nodes = entity_nodes

if entity_nodes:
#: ``nodes_per_entity[d]`` is the number of entities
#: associated with an entity of dimension d.
self.nodes_per_entity = np.array([len(entity_nodes[d])
for d in range(cell.dim+1)])

# Replace this exception with some code which sets
# self.basis_coefs
# to an array of polynomial coefficients defining the basis functions.
raise NotImplementedError

#: The number of nodes in this element.
self.node_count = nodes.shape

"""Evaluate the basis functions of this finite element at the points
provided.

:param points: a list of coordinate tuples at which to
tabulate the basis.
:param grad: whether to return the tabulation of the basis or the
tabulation of the gradient of the basis.

:result: an array containing the value of each basis function
each basis vector at each point is returned as a rank 3
array. The shape of the array is (points, nodes) if
is ``True``.

The implementation of this method is left as an :ref:`exercise
<ex-tabulate>`.

"""

raise NotImplementedError

[docs]    def interpolate(self, fn):
"""Interpolate fn onto this finite element by evaluating it
at each of the nodes.

:param fn: A function ``fn(X)`` which takes a coordinate
vector and returns a scalar value.

:returns: A vector containing the value of ``fn`` at each node
of this element.

The implementation of this method is left as an :ref:`exercise
<ex-interpolate>`.

"""

raise NotImplementedError

def __repr__(self):
return "%s(%s, %s)" % (self.__class__.__name__,
self.cell,
self.degree)

[docs]class LagrangeElement(FiniteElement):
def __init__(self, cell, degree):
"""An equispaced Lagrange finite element.

:param cell: the :class:`~.reference_elements.ReferenceCell`
over which the element is defined.
:param degree: the
polynomial degree of the element. We assume the element
spans the complete polynomial space.

The implementation of this class is left as an :ref:`exercise
<ex-lagrange-element>`.
"""

raise NotImplementedError
# Use lagrange_points to obtain the set of nodes.  Once you
# have obtained nodes, the following line will call the
# __init__ method on the FiniteElement class to set up the
# basis coefficients.
super(LagrangeElement, self).__init__(cell, degree, nodes)
```