# Path: finat/physically_mapped.py
# class PhysicalGeometry(metaclass=ABCMeta):
# 
#     @abstractmethod
#     def cell_size(self):
#         """The cell size at each vertex.
# 
#         :returns: A GEM expression for the cell size, shape (nvertex, ).
#         """
# 
#     @abstractmethod
#     def jacobian_at(self, point):
#         """The jacobian of the physical coordinates at a point.
# 
#         :arg point: The point in reference space (on the cell) to
#              evaluate the Jacobian.
#         :returns: A GEM expression for the Jacobian, shape (gdim, tdim).
#         """
# 
#     @abstractmethod
#     def detJ_at(self, point):
#         """The determinant of the jacobian of the physical coordinates at a point.
# 
#         :arg point: The point in reference space to evaluate the Jacobian determinant.
#         :returns: A GEM expression for the Jacobian determinant.
#         """
# 
#     @abstractmethod
#     def reference_normals(self):
#         """The (unit) reference cell normals for each facet.
# 
#         :returns: A GEM expression for the normal to each
#            facet (numbered according to FIAT conventions), shape
#            (nfacet, tdim).
#         """
# 
#     @abstractmethod
#     def physical_normals(self):
#         """The (unit) physical cell normals for each facet.
# 
#         :returns: A GEM expression for the normal to each
#            facet (numbered according to FIAT conventions).  These are
#            all computed by a clockwise rotation of the physical
#            tangents, shape (nfacet, gdim).
#         """
# 
#     @abstractmethod
#     def physical_tangents(self):
#         """The (unit) physical cell tangents on each facet.
# 
#         :returns: A GEM expression for the tangent to each
#            facet (numbered according to FIAT conventions).  These
#            always point from low to high numbered local vertex, shape
#            (nfacet, gdim).
#         """
# 
#     @abstractmethod
#     def physical_edge_lengths(self):
#         """The length of each edge of the physical cell.
# 
#         :returns: A GEM expression for the length of each
#            edge (numbered according to FIAT conventions), shape
#            (nfacet, ).
#         """
# 
#     @abstractmethod
#     def physical_points(self, point_set, entity=None):
#         """Maps reference element points to GEM for the physical coordinates
# 
#         :arg point_set: A point_set on the reference cell to push forward to physical space.
#         :arg entity: Reference cell entity on which the point set is
#                      defined (for example if it is a point set on a facet).
#         :returns: a GEM expression for the physical locations of the
#                   points, shape (gdim, ) with free indices of the point_set.
#         """
# 
#     @abstractmethod
#     def physical_vertices(self):
#         """Physical locations of the cell vertices.
# 
#         :returns: a GEM expression for the physical vertices, shape
#                 (gdim, )."""


import FIAT
import numpy as np
import gem
from finat.physically_mapped import PhysicalGeometry


class MyMapping(PhysicalGeometry):
    def __init__(self, ref_cell, phys_cell):
        self.ref_cell = ref_cell
        self.phys_cell = phys_cell

        self.A, self.b = FIAT.reference_element.make_affine_mapping(
            self.ref_cell.vertices,
            self.phys_cell.vertices)

    def cell_size(self):
        # Firedrake interprets this as 2x the circumradius
        # cs = (np.prod([self.phys_cell.volume_of_subcomplex(1, i)
        #                for i in range(3)])
        #       / 2.0 / self.phys_cell.volume())
        # return np.asarray([cs for _ in range(3)])
        # Currently, just return 1 so we can compare FIAT dofs
        # to transformed dofs.

        return np.ones((3,))

    def detJ_at(self, point):
        return gem.Literal(np.linalg.det(self.A))

    def jacobian_at(self, point):
        return gem.Literal(self.A)

    def reference_normals(self):

# Path: finat/physically_mapped.py
# class PhysicalGeometry(metaclass=ABCMeta):
# 
#     @abstractmethod
#     def cell_size(self):
#         """The cell size at each vertex.
# 
#         :returns: A GEM expression for the cell size, shape (nvertex, ).
#         """
# 
#     @abstractmethod
#     def jacobian_at(self, point):
#         """The jacobian of the physical coordinates at a point.
# 
#         :arg point: The point in reference space (on the cell) to
#              evaluate the Jacobian.
#         :returns: A GEM expression for the Jacobian, shape (gdim, tdim).
#         """
# 
#     @abstractmethod
#     def detJ_at(self, point):
#         """The determinant of the jacobian of the physical coordinates at a point.
# 
#         :arg point: The point in reference space to evaluate the Jacobian determinant.
#         :returns: A GEM expression for the Jacobian determinant.
#         """
# 
#     @abstractmethod
#     def reference_normals(self):
#         """The (unit) reference cell normals for each facet.
# 
#         :returns: A GEM expression for the normal to each
#            facet (numbered according to FIAT conventions), shape
#            (nfacet, tdim).
#         """
# 
#     @abstractmethod
#     def physical_normals(self):
#         """The (unit) physical cell normals for each facet.
# 
#         :returns: A GEM expression for the normal to each
#            facet (numbered according to FIAT conventions).  These are
#            all computed by a clockwise rotation of the physical
#            tangents, shape (nfacet, gdim).
#         """
# 
#     @abstractmethod
#     def physical_tangents(self):
#         """The (unit) physical cell tangents on each facet.
# 
#         :returns: A GEM expression for the tangent to each
#            facet (numbered according to FIAT conventions).  These
#            always point from low to high numbered local vertex, shape
#            (nfacet, gdim).
#         """
# 
#     @abstractmethod
#     def physical_edge_lengths(self):
#         """The length of each edge of the physical cell.
# 
#         :returns: A GEM expression for the length of each
#            edge (numbered according to FIAT conventions), shape
#            (nfacet, ).
#         """
# 
#     @abstractmethod
#     def physical_points(self, point_set, entity=None):
#         """Maps reference element points to GEM for the physical coordinates
# 
#         :arg point_set: A point_set on the reference cell to push forward to physical space.
#         :arg entity: Reference cell entity on which the point set is
#                      defined (for example if it is a point set on a facet).
#         :returns: a GEM expression for the physical locations of the
#                   points, shape (gdim, ) with free indices of the point_set.
#         """
# 
#     @abstractmethod
#     def physical_vertices(self):
#         """Physical locations of the cell vertices.
# 
#         :returns: a GEM expression for the physical vertices, shape
#                 (gdim, )."""


# Path: test/fiat_mapping.py
import FIAT
import numpy as np
import gem
from finat.physically_mapped import PhysicalGeometry



class MyMapping(PhysicalGeometry):
    def __init__(self, ref_cell, phys_cell):
        self.ref_cell = ref_cell
        self.phys_cell = phys_cell

        self.A, self.b = FIAT.reference_element.make_affine_mapping(
            self.ref_cell.vertices,
            self.phys_cell.vertices)

    def cell_size(self):
        # Firedrake interprets this as 2x the circumradius
        # cs = (np.prod([self.phys_cell.volume_of_subcomplex(1, i)
        #                for i in range(3)])
        #       / 2.0 / self.phys_cell.volume())
        # return np.asarray([cs for _ in range(3)])
        # Currently, just return 1 so we can compare FIAT dofs
        # to transformed dofs.

        return np.ones((3,))

    def detJ_at(self, point):
        return gem.Literal(np.linalg.det(self.A))

    def jacobian_at(self, point):
        return gem.Literal(self.A)

    def reference_normals(self):

        return gem.Literal(