# Path: gusto/kernels.py
# class GaussianElimination(object):
# class Average(object):
# class AverageWeightings(object):
# class PhysicsRecoveryTop():
# class PhysicsRecoveryBottom():
#     def __init__(self, DG1):
#     def apply(self, v_DG1_old, v_DG1, act_coords, eff_coords, num_ext):
#     def __init__(self, V):
#     def apply(self, v_out, weighting, v_in):
#     def __init__(self, V):
#     def apply(self, w):
#     def __init__(self):
#     def apply(self, v_DG1, v_CG1):
#     def __init__(self):
#     def apply(self, v_DG1, v_CG1):


from enum import Enum
from firedrake import (BrokenElement, Constant, DirichletBC, FiniteElement,
                       Function, FunctionSpace, Interpolator, Projector,
                       SpatialCoordinate, TensorProductElement,
                       VectorFunctionSpace, as_vector, function, interval)
from firedrake.utils import cached_property
from gusto import kernels
import ufl
    """
    An object that 'recovers' a low order field (e.g. in DG0)
    into a higher order field (e.g. in CG1).
    The code is essentially that of the Firedrake Projector
    object, using the "average" method, and could possibly
    be replaced by it if it comes into the master branch.

    :arg v: the :class:`ufl.Expr` or
         :class:`.Function` to project.
    :arg v_out: :class:`.Function` to put the result in.
    """

    def __init__(self, v, v_out):

        if not isinstance(v, (ufl.core.expr.Expr, function.Function)):
            raise ValueError("Can only recover UFL expression or Functions not '%s'" % type(v))

        # Check shape values
        if v.ufl_shape != v_out.ufl_shape:
            raise RuntimeError('Shape mismatch between source %s and target function spaces %s in project' % (v.ufl_shape, v_out.ufl_shape))

        self._same_fspace = (isinstance(v, function.Function) and v.function_space() == v_out.function_space())
        self.v = v
        self.v_out = v_out
        self.V = v_out.function_space()

        # Check the number of local dofs
        if self.v_out.function_space().finat_element.space_dimension() != self.v.function_space().finat_element.space_dimension():
            raise RuntimeError("Number of local dofs for each field must be equal.")


# Path: gusto/kernels.py
# class GaussianElimination(object):
# class Average(object):
# class AverageWeightings(object):
# class PhysicsRecoveryTop():
# class PhysicsRecoveryBottom():
#     def __init__(self, DG1):
#     def apply(self, v_DG1_old, v_DG1, act_coords, eff_coords, num_ext):
#     def __init__(self, V):
#     def apply(self, v_out, weighting, v_in):
#     def __init__(self, V):
#     def apply(self, w):
#     def __init__(self):
#     def apply(self, v_DG1, v_CG1):
#     def __init__(self):
#     def apply(self, v_DG1, v_CG1):


# Path: gusto/recovery.py
from enum import Enum
from firedrake import (BrokenElement, Constant, DirichletBC, FiniteElement,
                       Function, FunctionSpace, Interpolator, Projector,
                       SpatialCoordinate, TensorProductElement,
                       VectorFunctionSpace, as_vector, function, interval)
from firedrake.utils import cached_property
from gusto import kernels
import ufl

    """
    An object that 'recovers' a low order field (e.g. in DG0)
    into a higher order field (e.g. in CG1).
    The code is essentially that of the Firedrake Projector
    object, using the "average" method, and could possibly
    be replaced by it if it comes into the master branch.

    :arg v: the :class:`ufl.Expr` or
         :class:`.Function` to project.
    :arg v_out: :class:`.Function` to put the result in.
    """

    def __init__(self, v, v_out):

        if not isinstance(v, (ufl.core.expr.Expr, function.Function)):
            raise ValueError("Can only recover UFL expression or Functions not '%s'" % type(v))

        # Check shape values
        if v.ufl_shape != v_out.ufl_shape:
            raise RuntimeError('Shape mismatch between source %s and target function spaces %s in project' % (v.ufl_shape, v_out.ufl_shape))

        self._same_fspace = (isinstance(v, function.Function) and v.function_space() == v_out.function_space())
        self.v = v
        self.v_out = v_out
        self.V = v_out.function_space()

        # Check the number of local dofs
        if self.v_out.function_space().finat_element.space_dimension() != self.v.function_space().finat_element.space_dimension():
            raise RuntimeError("Number of local dofs for each field must be equal.")


        self.average_kernel = kernels.Average(self.V)