diff --git a/ufl/__init__.py b/ufl/__init__.py index 57884a507..0a48f8359 100644 --- a/ufl/__init__.py +++ b/ufl/__init__.py @@ -303,6 +303,7 @@ SpatialCoordinate, ) from ufl.integral import Integral +from ufl.integral_domain import DSIntegralDomain, DsIntegralDomain, DxIntegralDomain from ufl.matrix import Matrix from ufl.measure import Measure, custom_integral_types, integral_types, register_integral_type from ufl.objects import ( @@ -463,8 +464,11 @@ "Coefficients", "Cofunction", "Constant", + "DSIntegralDomain", "Dn", + "DsIntegralDomain", "Dx", + "DxIntegralDomain", "ExternalOperator", "FacetArea", "FacetNormal", diff --git a/ufl/integral_domain.py b/ufl/integral_domain.py new file mode 100644 index 000000000..ea8138232 --- /dev/null +++ b/ufl/integral_domain.py @@ -0,0 +1,85 @@ +"""Integral domains.""" + +from abc import ABC, abstractmethod + +from ufl.cell import AbstractCell +from ufl.finiteelement import AbstractFiniteElement + + +class AbstractIntegralDomain(ABC): + """Abstract base class for integral domain.""" + + def __hash__(self) -> int: + """Hash.""" + return hash(self.__repr__()) + + @abstractmethod + def __repr__(self) -> str: + """Representation.""" + + @property + @abstractmethod + def integral_type(self) -> str: + """Integral type.""" + + +class DxIntegralDomain(AbstractIntegralDomain): + """Integral domain for dx.""" + + def __init__(self, coordinate_element: AbstractFiniteElement): + """Initialise.""" + self.coordinate_element = coordinate_element + + def __repr__(self) -> str: + """Representation.""" + return f"DxIntegralDomain({self.coordinate_element!r})" + + @property + def integral_type(self) -> str: + """Integral type.""" + return "cell" + + +class DsIntegralDomain(AbstractIntegralDomain): + """Integral domain for ds.""" + + def __init__(self, coordinate_element: AbstractFiniteElement, facet_type: AbstractCell): + """Initialise.""" + self.coordinate_element = coordinate_element + self.facet_type = facet_type + + def __repr__(self) -> str: + """Representation.""" + return f"DsIntegralDomain({self.coordinate_element!r}, {self.facet_type!r})" + + @property + def integral_type(self) -> str: + """Integral type.""" + return "exterior_facet" + + +class DSIntegralDomain(AbstractIntegralDomain): + """Integral domain for dS.""" + + def __init__( + self, + coordinate_element_positive_side: AbstractFiniteElement, + coordinate_element_negative_side: AbstractFiniteElement, + facet_type: AbstractCell, + ): + """Initialise.""" + self.coordinate_element_positive_side = coordinate_element_positive_side + self.coordinate_element_negative_side = coordinate_element_negative_side + self.facet_type = facet_type + + def __repr__(self) -> str: + """Representation.""" + return ( + f"DSIntegralDomain({self.coordinate_element_positive_side!r}, " + f"{self.coordinate_element_negative_side!r}, {self.facet_type!r})" + ) + + @property + def integral_type(self) -> str: + """Integral type.""" + return "interior_facet"