diff --git a/.github/workflows/tsfc-tests.yml b/.github/workflows/tsfc-tests.yml index 98fd4696b..e240009f7 100644 --- a/.github/workflows/tsfc-tests.yml +++ b/.github/workflows/tsfc-tests.yml @@ -21,7 +21,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: 3.12 - name: Install UFL run: | diff --git a/test/test_apply_restrictions.py b/test/test_apply_restrictions.py index 61b370e00..130102720 100755 --- a/test/test_apply_restrictions.py +++ b/test/test_apply_restrictions.py @@ -11,7 +11,7 @@ i, triangle, ) -from ufl.algorithms.apply_restrictions import apply_default_restrictions, apply_restrictions +from ufl.algorithms.apply_restrictions import apply_restrictions from ufl.algorithms.renumbering import renumber_indices from ufl.finiteelement import FiniteElement from ufl.pullback import identity_pullback @@ -54,7 +54,7 @@ def test_apply_restrictions(): assert apply_restrictions((grad(f) + grad(g))("-")) == (grad(f)("-") + grad(g)("-")) # x is the same from both sides but computed from one of them - assert apply_default_restrictions(x) == x("+") + assert apply_restrictions(x) == x("+") # n on a linear mesh is opposite pointing from the other side assert apply_restrictions(n("+")) == n("+") diff --git a/ufl/__init__.py b/ufl/__init__.py index 0782ebad7..26bb6f4d2 100644 --- a/ufl/__init__.py +++ b/ufl/__init__.py @@ -435,208 +435,208 @@ from ufl.utils.sequences import product __all__ = [ - "product", - "as_cell", - "AbstractCell", - "Cell", - "TensorProductCell", - "AbstractDomain", - "Mesh", - "MeshView", - "L2", "H1", "H2", - "HCurl", - "HDiv", - "HInf", - "HEin", - "HDivDiv", - "HCurlDiv", - "identity_pullback", - "l2_piola", - "contravariant_piola", - "covariant_piola", - "double_contravariant_piola", - "double_covariant_piola", - "covariant_contravariant_piola", - "l2_piola", - "MixedPullback", - "SymmetricPullback", + "L2", + "AbstractCell", + "AbstractDomain", + "AbstractFiniteElement", "AbstractPullback", - "SpatialCoordinate", - "CellVolume", + "Action", + "Adjoint", + "And", + "Argument", + "Arguments", + "BaseForm", + "Cell", "CellDiameter", + "CellNormal", + "CellVolume", "Circumradius", - "MinCellEdgeLength", - "MaxCellEdgeLength", + "Coargument", + "Coefficient", + "Coefficients", + "Cofunction", + "Constant", + "Dn", + "Dx", + "ExternalOperator", "FacetArea", - "MinFacetEdgeLength", - "MaxFacetEdgeLength", "FacetNormal", - "CellNormal", + "Form", + "FormSum", + "FunctionSpace", + "HCurl", + "HCurlDiv", + "HDiv", + "HDivDiv", + "HEin", + "HInf", + "Identity", + "Index", + "Integral", + "Interpolate", "Jacobian", "JacobianDeterminant", "JacobianInverse", - "AbstractFiniteElement", - "FunctionSpace", + "Matrix", + "MaxCellEdgeLength", + "MaxFacetEdgeLength", + "Measure", + "Mesh", + "MeshView", + "MinCellEdgeLength", + "MinFacetEdgeLength", "MixedFunctionSpace", - "Argument", - "Coargument", + "MixedPullback", + "Not", + "Or", + "PermutationSymbol", + "SpatialCoordinate", + "SymmetricPullback", + "TensorConstant", + "TensorProductCell", "TestFunction", - "TrialFunction", - "Arguments", "TestFunctions", + "TrialFunction", "TrialFunctions", - "Coefficient", - "Cofunction", - "Coefficients", - "Matrix", - "Adjoint", - "Action", - "Interpolate", - "interpolate", - "ExternalOperator", - "Constant", "VectorConstant", - "TensorConstant", - "split", - "PermutationSymbol", - "Identity", - "zero", - "as_ufl", - "Index", - "indices", + "ZeroBaseForm", + "acos", + "action", + "adjoint", + "as_cell", + "as_matrix", "as_tensor", + "as_ufl", "as_vector", - "as_matrix", - "unit_vector", - "unit_vectors", - "unit_matrix", - "unit_matrices", - "rank", - "shape", - "conj", - "real", - "imag", - "outer", - "inner", - "dot", - "cross", - "perp", - "det", - "inv", - "cofac", - "transpose", - "tr", - "diag", - "diag_vector", - "dev", - "skew", - "sym", - "sqrt", - "exp", - "ln", - "erf", - "cos", - "sin", - "tan", - "acos", "asin", "atan", "atan2", - "cosh", - "sinh", - "tanh", - "bessel_J", - "bessel_Y", + "avg", "bessel_I", + "bessel_J", "bessel_K", - "eq", - "ne", - "le", - "ge", - "lt", - "gt", - "And", - "Or", - "Not", + "bessel_Y", + "cell_avg", + "cofac", "conditional", - "sign", - "max_value", - "min_value", - "variable", - "diff", - "Dx", - "grad", - "div", + "conj", + "contravariant_piola", + "cos", + "cosh", + "covariant_contravariant_piola", + "covariant_piola", + "cross", "curl", - "rot", - "nabla_grad", - "nabla_div", - "Dn", - "exterior_derivative", - "jump", - "avg", - "cell_avg", - "facet_avg", - "elem_mult", - "elem_div", - "elem_pow", - "elem_op", - "Form", - "BaseForm", - "FormSum", - "ZeroBaseForm", - "Integral", - "Measure", - "register_integral_type", - "integral_types", "custom_integral_types", - "replace", - "derivative", - "action", - "energy_norm", - "rhs", - "lhs", - "extract_blocks", - "system", - "functional", - "adjoint", - "sensitivity_rhs", - "dx", - "ds", - "dS", - "dP", - "dc", "dC", - "dO", "dI", + "dO", + "dP", + "dS", + "dS_h", + "dS_v", "dX", + "dc", + "derivative", + "det", + "dev", + "diag", + "diag_vector", + "diff", + "div", + "dot", + "double_contravariant_piola", + "double_covariant_piola", + "ds", "ds_b", "ds_t", "ds_tb", "ds_v", - "dS_h", - "dS_v", - "vertex", - "interval", - "triangle", - "tetrahedron", - "prism", - "pyramid", - "pentatope", - "tesseract", - "quadrilateral", - "hexahedron", + "dx", + "e", + "elem_div", + "elem_mult", + "elem_op", + "elem_pow", + "energy_norm", + "eq", + "erf", + "exp", + "exterior_derivative", + "extract_blocks", "facet", + "facet_avg", + "functional", + "ge", + "grad", + "gt", + "hexahedron", "i", + "identity_pullback", + "imag", + "indices", + "inner", + "integral_types", + "interpolate", + "interval", + "inv", "j", + "jump", "k", "l", + "l2_piola", + "l2_piola", + "le", + "lhs", + "ln", + "lt", + "max_value", + "min_value", + "nabla_div", + "nabla_grad", + "ne", + "outer", "p", + "pentatope", + "perp", + "pi", + "prism", + "product", + "pyramid", "q", + "quadrilateral", "r", + "rank", + "real", + "register_integral_type", + "replace", + "rhs", + "rot", "s", - "e", - "pi", + "sensitivity_rhs", + "shape", + "sign", + "sin", + "sinh", + "skew", + "split", + "sqrt", + "sym", + "system", + "tan", + "tanh", + "tesseract", + "tetrahedron", + "tr", + "transpose", + "triangle", + "unit_matrices", + "unit_matrix", + "unit_vector", + "unit_vectors", + "variable", + "vertex", + "zero", ] diff --git a/ufl/action.py b/ufl/action.py index fb6416865..b2f0a7ce3 100644 --- a/ufl/action.py +++ b/ufl/action.py @@ -9,15 +9,14 @@ from itertools import chain +from ufl import matrix # noqa 401 from ufl.algebra import Sum from ufl.argument import Argument, Coargument -from ufl.coefficient import BaseCoefficient, Coefficient, Cofunction +from ufl.coefficient import BaseCoefficient, Coefficient from ufl.constantvalue import Zero -from ufl.core.base_form_operator import BaseFormOperator from ufl.core.ufl_type import ufl_type from ufl.differentiation import CoefficientDerivative from ufl.form import BaseForm, Form, FormSum, ZeroBaseForm -from ufl.matrix import Matrix # --- The Action class represents the action of a numerical object that needs # to be computed at assembly time --- @@ -38,14 +37,14 @@ class Action(BaseForm): """ __slots__ = ( - "_left", - "_right", - "ufl_operands", - "_repr", "_arguments", "_coefficients", "_domains", "_hash", + "_left", + "_repr", + "_right", + "ufl_operands", ) def __new__(cls, *args, **kw): @@ -159,20 +158,13 @@ def __hash__(self): def _check_function_spaces(left, right): """Check if the function spaces of left and right match.""" + # Action differentiation pushes differentiation through + # right as a consequence of Leibniz formula. if isinstance(right, CoefficientDerivative): - # Action differentiation pushes differentiation through - # right as a consequence of Leibniz formula. right, *_ = right.ufl_operands + if isinstance(left, CoefficientDerivative): + left, *_ = left.ufl_operands - # `left` can also be a Coefficient in V (= V**), e.g. - # `action(Coefficient(V), Cofunction(V.dual()))`. - left_arg = left.arguments()[-1] if not isinstance(left, Coefficient) else left - if isinstance(right, (Form, Action, Matrix, ZeroBaseForm)): - if left_arg.ufl_function_space().dual() != right.arguments()[0].ufl_function_space(): - raise TypeError("Incompatible function spaces in Action") - elif isinstance(right, (Coefficient, Cofunction, Argument, BaseFormOperator)): - if left_arg.ufl_function_space() != right.ufl_function_space(): - raise TypeError("Incompatible function spaces in Action") # `Zero` doesn't contain any information about the function space. # -> Not a problem since Action will get simplified with a # `ZeroBaseForm` which won't take into account the arguments on @@ -180,8 +172,22 @@ def _check_function_spaces(left, right): # This occurs for: # `derivative(Action(A, B), u)` with B is an `Expr` such that dB/du == 0 # -> `derivative(B, u)` becomes `Zero` when expanding derivatives since B is an Expr. - elif not isinstance(right, Zero): - raise TypeError("Incompatible argument in Action: %s" % type(right)) + if isinstance(left, Zero) or isinstance(right, Zero): + return + + # `left` can also be a Coefficient in V (= V**), e.g. + # `action(Coefficient(V), Cofunction(V.dual()))`. + if isinstance(left, Coefficient): + V_left = left.ufl_function_space() + else: + V_left = left.arguments()[-1].ufl_function_space().dual() + if isinstance(right, Coefficient): + V_right = right.ufl_function_space() + else: + V_right = right.arguments()[0].ufl_function_space().dual() + + if V_left.dual() != V_right: + raise TypeError("Incompatible function spaces in Action") def _get_action_form_arguments(left, right): diff --git a/ufl/adjoint.py b/ufl/adjoint.py index 987372a73..71227f578 100644 --- a/ufl/adjoint.py +++ b/ufl/adjoint.py @@ -28,13 +28,13 @@ class Adjoint(BaseForm): """ __slots__ = ( - "_form", - "_repr", "_arguments", "_coefficients", "_domains", - "ufl_operands", + "_form", "_hash", + "_repr", + "ufl_operands", ) def __new__(cls, *args, **kw): diff --git a/ufl/algorithms/__init__.py b/ufl/algorithms/__init__.py index 18dce39fd..541abbfb5 100644 --- a/ufl/algorithms/__init__.py +++ b/ufl/algorithms/__init__.py @@ -15,43 +15,43 @@ # on grepping of other FEniCS code for ufl.algorithm imports. __all__ = [ - "estimate_total_polynomial_degree", - "sort_elements", - "compute_form_data", - "preprocess_form", - "apply_transformer", + "FormSplitter", + "MultiFunction", "ReuseTransformer", - "load_ufl_file", "Transformer", - "MultiFunction", - "extract_unique_elements", - "extract_type", - "extract_elements", - "extract_sub_elements", - "expand_indices", - "replace", - "expand_derivatives", - "extract_coefficients", - "extract_base_form_operators", - "strip_variables", - "strip_terminal_data", - "replace_terminal_data", - "post_traversal", + "apply_transformer", "change_to_reference_grad", - "validate_form", - "FormSplitter", - "extract_arguments", - "compute_form_adjoint", - "compute_form_action", "compute_energy_norm", + "compute_form_action", + "compute_form_adjoint", + "compute_form_arities", + "compute_form_data", + "compute_form_functional", "compute_form_lhs", "compute_form_rhs", - "compute_form_functional", "compute_form_signature", - "compute_form_arities", - "tree_format", - "read_ufl_file", + "estimate_total_polynomial_degree", + "expand_derivatives", + "expand_indices", + "extract_arguments", + "extract_base_form_operators", + "extract_coefficients", + "extract_elements", + "extract_sub_elements", + "extract_type", + "extract_unique_elements", "load_forms", + "load_ufl_file", + "post_traversal", + "preprocess_form", + "read_ufl_file", + "replace", + "replace_terminal_data", + "sort_elements", + "strip_terminal_data", + "strip_variables", + "tree_format", + "validate_form", ] from ufl.algorithms.ad import expand_derivatives diff --git a/ufl/algorithms/apply_restrictions.py b/ufl/algorithms/apply_restrictions.py index a7550d722..d2a4ace41 100644 --- a/ufl/algorithms/apply_restrictions.py +++ b/ufl/algorithms/apply_restrictions.py @@ -22,16 +22,20 @@ class RestrictionPropagator(MultiFunction): """Restriction propagator.""" - def __init__(self, side=None): + def __init__(self, side=None, apply_default=True): """Initialise.""" MultiFunction.__init__(self) self.current_restriction = side self.default_restriction = "+" + self.apply_default = apply_default # Caches for propagating the restriction with map_expr_dag self.vcaches = {"+": {}, "-": {}} self.rcaches = {"+": {}, "-": {}} if self.current_restriction is None: - self._rp = {"+": RestrictionPropagator("+"), "-": RestrictionPropagator("-")} + self._rp = { + "+": RestrictionPropagator(side="+", apply_default=apply_default), + "-": RestrictionPropagator(side="-", apply_default=apply_default), + } def restricted(self, o): """When hitting a restricted quantity, visit child with a separate restriction algorithm.""" @@ -64,9 +68,12 @@ def _require_restriction(self, o): def _default_restricted(self, o): """Restrict a continuous quantity to default side if no current restriction is set.""" r = self.current_restriction - if r is None: - r = self.default_restriction - return o(r) + if r is not None: + return o(r) + if self.apply_default: + return o(self.default_restriction) + else: + return o def _opposite(self, o): """Restrict a quantity to default side. @@ -139,6 +146,18 @@ def reference_value(self, o): reference_cell_volume = _ignore_restriction reference_facet_volume = _ignore_restriction + # These are the same from either side but to compute them + # cell (or facet) data from one side must be selected: + spatial_coordinate = _default_restricted + # Depends on cell only to get to the facet: + facet_jacobian = _default_restricted + facet_jacobian_determinant = _default_restricted + facet_jacobian_inverse = _default_restricted + facet_area = _default_restricted + min_facet_edge_length = _default_restricted + max_facet_edge_length = _default_restricted + facet_origin = _default_restricted # FIXME: Is this valid for quads? + def coefficient(self, o): """Restrict a coefficient. @@ -174,76 +193,10 @@ def facet_normal(self, o): return self._require_restriction(o) -def apply_restrictions(expression): +def apply_restrictions(expression, apply_default=True): """Propagate restriction nodes to wrap differential terminals directly.""" integral_types = [ k for k in integral_type_to_measure_name.keys() if k.startswith("interior_facet") ] - rules = RestrictionPropagator() - return map_integrand_dags(rules, expression, only_integral_type=integral_types) - - -class DefaultRestrictionApplier(MultiFunction): - """Default restriction applier.""" - - def __init__(self, side=None): - """Initialise.""" - MultiFunction.__init__(self) - self.current_restriction = side - self.default_restriction = "+" - if self.current_restriction is None: - self._rp = {"+": DefaultRestrictionApplier("+"), "-": DefaultRestrictionApplier("-")} - - def terminal(self, o): - """Apply to terminal.""" - # Most terminals are unchanged - return o - - # Default: Operators should reconstruct only if subtrees are not touched - operator = MultiFunction.reuse_if_untouched - - def restricted(self, o): - """Apply to restricted.""" - # Don't restrict twice - return o - - def derivative(self, o): - """Apply to derivative.""" - # I don't think it's safe to just apply default restriction - # to the argument of any derivative, i.e. grad(cg1_function) - # is not continuous across cells even if cg1_function is. - return o - - def _default_restricted(self, o): - """Restrict a continuous quantity to default side if no current restriction is set.""" - r = self.current_restriction - if r is None: - r = self.default_restriction - return o(r) - - # These are the same from either side but to compute them - # cell (or facet) data from one side must be selected: - spatial_coordinate = _default_restricted - # Depends on cell only to get to the facet: - facet_jacobian = _default_restricted - facet_jacobian_determinant = _default_restricted - facet_jacobian_inverse = _default_restricted - # facet_tangents = _default_restricted - # facet_midpoint = _default_restricted - facet_area = _default_restricted - # facet_diameter = _default_restricted - min_facet_edge_length = _default_restricted - max_facet_edge_length = _default_restricted - facet_origin = _default_restricted # FIXME: Is this valid for quads? - - -def apply_default_restrictions(expression): - """Some terminals can be restricted from either side. - - This applies a default restriction to such terminals if unrestricted. - """ - integral_types = [ - k for k in integral_type_to_measure_name.keys() if k.startswith("interior_facet") - ] - rules = DefaultRestrictionApplier() + rules = RestrictionPropagator(apply_default=apply_default) return map_integrand_dags(rules, expression, only_integral_type=integral_types) diff --git a/ufl/algorithms/compute_form_data.py b/ufl/algorithms/compute_form_data.py index 687e8edc4..2784f6236 100644 --- a/ufl/algorithms/compute_form_data.py +++ b/ufl/algorithms/compute_form_data.py @@ -19,7 +19,7 @@ from ufl.algorithms.apply_function_pullbacks import apply_function_pullbacks from ufl.algorithms.apply_geometry_lowering import apply_geometry_lowering from ufl.algorithms.apply_integral_scaling import apply_integral_scaling -from ufl.algorithms.apply_restrictions import apply_default_restrictions, apply_restrictions +from ufl.algorithms.apply_restrictions import apply_restrictions from ufl.algorithms.check_arities import check_form_arity from ufl.algorithms.comparison_checker import do_comparison_check @@ -306,10 +306,6 @@ def compute_form_data( if do_apply_integral_scaling: form = apply_integral_scaling(form) - # Apply default restriction to fully continuous terminals - if do_apply_default_restrictions: - form = apply_default_restrictions(form) - # Lower abstractions for geometric quantities into a smaller set # of quantities, allowing the form compiler to deal with a smaller # set of types and treating geometric quantities like any other @@ -334,7 +330,7 @@ def compute_form_data( # Propagate restrictions to terminals if do_apply_restrictions: - form = apply_restrictions(form) + form = apply_restrictions(form, apply_default=do_apply_default_restrictions) # If in real mode, remove any complex nodes introduced during form processing. if not complex_mode: diff --git a/ufl/algorithms/domain_analysis.py b/ufl/algorithms/domain_analysis.py index 19e0f4e3c..3a1aed9d0 100644 --- a/ufl/algorithms/domain_analysis.py +++ b/ufl/algorithms/domain_analysis.py @@ -33,12 +33,12 @@ class IntegralData(object): __slots__ = ( "domain", + "enabled_coefficients", + "integral_coefficients", "integral_type", - "subdomain_id", "integrals", "metadata", - "integral_coefficients", - "enabled_coefficients", + "subdomain_id", ) def __init__(self, domain, integral_type, subdomain_id, integrals, metadata): diff --git a/ufl/argument.py b/ufl/argument.py index a9326a237..4ff5927fa 100644 --- a/ufl/argument.py +++ b/ufl/argument.py @@ -149,11 +149,11 @@ class Argument(FormArgument, BaseArgument): """UFL value: Representation of an argument to a form.""" __slots__ = ( - "_ufl_function_space", - "_ufl_shape", "_number", "_part", "_repr", + "_ufl_function_space", + "_ufl_shape", ) _primal = True @@ -195,15 +195,15 @@ class Coargument(BaseForm, BaseArgument): """UFL value: Representation of an argument to a form in a dual space.""" __slots__ = ( - "_ufl_function_space", - "_ufl_shape", "_arguments", "_coefficients", - "ufl_operands", + "_hash", "_number", "_part", "_repr", - "_hash", + "_ufl_function_space", + "_ufl_shape", + "ufl_operands", ) _primal = False diff --git a/ufl/cell.py b/ufl/cell.py index d85c305e5..6d565d7fd 100644 --- a/ufl/cell.py +++ b/ufl/cell.py @@ -243,11 +243,11 @@ class Cell(AbstractCell): __slots__ = ( "_cellname", - "_tdim", "_num_cell_entities", - "_sub_entity_types", "_sub_entities", "_sub_entity_types", + "_sub_entity_types", + "_tdim", ) def __init__(self, cellname: str): diff --git a/ufl/classes.py b/ufl/classes.py index b8f48516c..cd162757f 100644 --- a/ufl/classes.py +++ b/ufl/classes.py @@ -63,12 +63,12 @@ nonterminal_classes = set(c for c in all_ufl_classes if not c._ufl_is_terminal_) __all__ += [ - "all_ufl_classes", + "__exproperators", "abstract_classes", - "ufl_classes", - "terminal_classes", + "all_ufl_classes", "nonterminal_classes", - "__exproperators", + "terminal_classes", + "ufl_classes", ] diff --git a/ufl/coefficient.py b/ufl/coefficient.py index bd35f8275..3fc668bb6 100644 --- a/ufl/coefficient.py +++ b/ufl/coefficient.py @@ -106,15 +106,15 @@ class Cofunction(BaseCoefficient, BaseForm): """UFL form argument type: Representation of a form coefficient from a dual space.""" __slots__ = ( - "_count", - "_counted_class", "_arguments", "_coefficients", - "_ufl_function_space", - "ufl_operands", + "_count", + "_counted_class", + "_hash", "_repr", + "_ufl_function_space", "_ufl_shape", - "_hash", + "ufl_operands", ) _primal = False _dual = True diff --git a/ufl/constantvalue.py b/ufl/constantvalue.py index b918a670b..007350680 100644 --- a/ufl/constantvalue.py +++ b/ufl/constantvalue.py @@ -63,7 +63,7 @@ class Zero(ConstantValue): Class for representing zero tensors of different shapes. """ - __slots__ = ("ufl_shape", "ufl_free_indices", "ufl_index_dimensions") + __slots__ = ("ufl_free_indices", "ufl_index_dimensions", "ufl_shape") _cache = {} @@ -453,7 +453,7 @@ class PermutationSymbol(ConstantValue): or alternating symbol. """ - __slots__ = ("ufl_shape", "_dim") + __slots__ = ("_dim", "ufl_shape") def __init__(self, dim): """Initialise.""" diff --git a/ufl/core/expr.py b/ufl/core/expr.py index cef955f0e..41b6e55a6 100644 --- a/ufl/core/expr.py +++ b/ufl/core/expr.py @@ -83,7 +83,7 @@ class MyOperator(Operator): # This is to freeze member variables for objects of this class and # save memory by skipping the per-instance dict. - __slots__ = ("_hash", "__weakref__") + __slots__ = ("__weakref__", "_hash") # _ufl_noslots_ = True # --- Basic object behaviour --- diff --git a/ufl/core/multiindex.py b/ufl/core/multiindex.py index 2d91e40f3..75116fff1 100644 --- a/ufl/core/multiindex.py +++ b/ufl/core/multiindex.py @@ -28,7 +28,7 @@ def __init__(self): class FixedIndex(IndexBase): """UFL value: An index with a specific value assigned.""" - __slots__ = ("_value", "_hash") + __slots__ = ("_hash", "_value") _cache = {} diff --git a/ufl/differentiation.py b/ufl/differentiation.py index 74e33617d..5c1d0b842 100644 --- a/ufl/differentiation.py +++ b/ufl/differentiation.py @@ -196,9 +196,9 @@ class VariableDerivative(Derivative): """Variable Derivative.""" __slots__ = ( - "ufl_shape", "ufl_free_indices", "ufl_index_dimensions", + "ufl_shape", ) def __new__(cls, f, v): diff --git a/ufl/finiteelement.py b/ufl/finiteelement.py index 8dbc76ed1..3aceef689 100644 --- a/ufl/finiteelement.py +++ b/ufl/finiteelement.py @@ -147,14 +147,14 @@ class FiniteElement(AbstractFiniteElement): """A directly defined finite element.""" __slots__ = ( - "_repr", - "_str", - "_family", "_cell", "_degree", - "_reference_value_shape", + "_family", "_pullback", + "_reference_value_shape", + "_repr", "_sobolev_space", + "_str", "_sub_elements", "_subdegree", ) diff --git a/ufl/form.py b/ufl/form.py index 4fc7c2165..274a873fd 100644 --- a/ufl/form.py +++ b/ufl/form.py @@ -227,26 +227,26 @@ class Form(BaseForm): """Description of a weak form consisting of a sum of integrals over subdomains.""" __slots__ = ( + "_arguments", + "_base_form_operators", + # --- Dict that external frameworks can place framework-specific + # data in to be carried with the form + # Never use this internally in ufl! + "_cache", + "_coefficient_numbering", + "_coefficients", + "_constant_numbering", + "_constants", + "_domain_numbering", + "_hash", # --- List of Integral objects (a Form is a sum of these # Integrals, everything else is derived) "_integrals", # --- Internal variables for caching various data "_integration_domains", - "_domain_numbering", + "_signature", "_subdomain_data", - "_arguments", - "_base_form_operators", - "_coefficients", - "_coefficient_numbering", - "_constants", - "_constant_numbering", "_terminal_numbering", - "_hash", - "_signature", - # --- Dict that external frameworks can place framework-specific - # data in to be carried with the form - # Never use this internally in ufl! - "_cache", ) def __init__(self, integrals): @@ -690,12 +690,12 @@ class FormSum(BaseForm): __slots__ = ( "_arguments", "_coefficients", - "_weights", "_components", - "ufl_operands", - "_domains", "_domain_numbering", + "_domains", "_hash", + "_weights", + "ufl_operands", ) _ufl_required_methods_ = "_analyze_form_arguments" @@ -843,11 +843,11 @@ class ZeroBaseForm(BaseForm): __slots__ = ( "_arguments", "_coefficients", - "ufl_operands", "_domains", "_hash", # Pyadjoint compatibility "form", + "ufl_operands", ) def __init__(self, arguments): diff --git a/ufl/integral.py b/ufl/integral.py index 510f4ebd5..8561d9b7a 100644 --- a/ufl/integral.py +++ b/ufl/integral.py @@ -22,12 +22,12 @@ class Integral(object): """An integral over a single domain.""" __slots__ = ( - "_integrand", "_integral_type", - "_ufl_domain", - "_subdomain_id", + "_integrand", "_metadata", "_subdomain_data", + "_subdomain_id", + "_ufl_domain", ) def __init__(self, integrand, integral_type, domain, subdomain_id, metadata, subdomain_data): diff --git a/ufl/matrix.py b/ufl/matrix.py index 039d70e23..d548c0abd 100644 --- a/ufl/matrix.py +++ b/ufl/matrix.py @@ -21,16 +21,16 @@ class Matrix(BaseForm, Counted): """An assemble linear operator between two function spaces.""" __slots__ = ( + "_arguments", + "_coefficients", "_count", "_counted_class", - "_ufl_function_spaces", - "ufl_operands", - "_repr", + "_domains", "_hash", + "_repr", + "_ufl_function_spaces", "_ufl_shape", - "_arguments", - "_coefficients", - "_domains", + "ufl_operands", ) def __getnewargs__(self): diff --git a/ufl/measure.py b/ufl/measure.py index 08f1fa803..6c1d40973 100644 --- a/ufl/measure.py +++ b/ufl/measure.py @@ -99,7 +99,7 @@ class Measure(object): expression. """ - __slots__ = ("_integral_type", "_domain", "_subdomain_id", "_metadata", "_subdomain_data") + __slots__ = ("_domain", "_integral_type", "_metadata", "_subdomain_data", "_subdomain_id") def __init__( self, diff --git a/ufl/tensors.py b/ufl/tensors.py index 3edb0759c..cfdda07ca 100644 --- a/ufl/tensors.py +++ b/ufl/tensors.py @@ -128,7 +128,7 @@ def substring(expressions, indent): class ComponentTensor(Operator): """Maps the free indices of a scalar valued expression to tensor axes.""" - __slots__ = ("ufl_shape", "ufl_free_indices", "ufl_index_dimensions") + __slots__ = ("ufl_free_indices", "ufl_index_dimensions", "ufl_shape") def __new__(cls, expression, indices): """Create a new ComponentTensor."""