Skip to content

Commit 9dac91e

Browse files
committed
Draft: Refactor UFL types using UFLType
1 parent 404d690 commit 9dac91e

File tree

3 files changed

+58
-52
lines changed

3 files changed

+58
-52
lines changed

ufl/core/expr.py

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,66 @@
2020
# Modified by Massimiliano Leoni, 2016
2121

2222
from ufl.log import error
23+
# from ufl.core.ufl_type import UFLType
24+
from ufl.utils.formatting import camel2underscore
25+
26+
27+
class UFLType(type):
28+
"""Base class for all UFL types.
29+
30+
Equip UFL types with properties such as:
31+
32+
- `_ufl_typecode_`: The integer typecode is a contiguous index different for each
33+
type. This is used for fast lookup into e.g. multifunction handler tables.
34+
35+
- `_ufl_num_typecodes_`: A global counter of the number of typecodes assigned.
36+
37+
"""
38+
39+
def __init__(cls, name, bases, attrs):
40+
# Determine integer typecode by incrementally counting all types
41+
cls._ufl_typecode_ = UFLType._ufl_num_typecodes_
42+
UFLType._ufl_num_typecodes_ += 1
43+
44+
UFLType._ufl_all_classes_.append(cls)
45+
46+
# Determine handler name by a mapping from "TypeName" to "type_name"
47+
cls._ufl_handler_name_ = camel2underscore(cls.__name__)
48+
UFLType._ufl_all_handler_names_.add(cls._ufl_handler_name_)
49+
50+
# Append space for counting object creation and destriction of
51+
# this this type.
52+
UFLType._ufl_obj_init_counts_.append(0)
53+
UFLType._ufl_obj_del_counts_.append(0)
54+
55+
# A global counter of the number of typecodes assigned.
56+
_ufl_num_typecodes_ = 0
57+
58+
# A global array of all Expr subclasses, indexed by typecode
59+
_ufl_all_classes_ = []
60+
61+
# A global set of all handler names added
62+
_ufl_all_handler_names_ = set()
63+
64+
# A global array of the number of initialized objects for each
65+
# typecode
66+
_ufl_obj_init_counts_ = []
67+
68+
# A global array of the number of deleted objects for each
69+
# typecode
70+
_ufl_obj_del_counts_ = []
71+
72+
# Type trait: If the type is abstract. An abstract class cannot
73+
# be instantiated and does not need all properties specified.
74+
_ufl_is_abstract_ = True
75+
76+
# Type trait: If the type is terminal.
77+
_ufl_is_terminal_ = None
2378

2479

2580
# --- The base object for all UFL expression tree nodes ---
2681

27-
class Expr(object):
82+
class Expr(object, metaclass=UFLType):
2883
"""Base class for all UFL expression types.
2984
3085
*Instance properties*
@@ -128,22 +183,10 @@ def __init__(self):
128183
# implement for this type in a multifunction.
129184
_ufl_handler_name_ = "expr"
130185

131-
# The integer typecode, a contiguous index different for each
132-
# type. This is used for fast lookup into e.g. multifunction
133-
# handler tables.
134-
_ufl_typecode_ = 0
135-
136186
# Number of operands, "varying" for some types, or None if not
137187
# applicable for abstract types.
138188
_ufl_num_ops_ = None
139189

140-
# Type trait: If the type is abstract. An abstract class cannot
141-
# be instantiated and does not need all properties specified.
142-
_ufl_is_abstract_ = True
143-
144-
# Type trait: If the type is terminal.
145-
_ufl_is_terminal_ = None
146-
147190
# Type trait: If the type is a literal.
148191
_ufl_is_literal_ = None
149192

@@ -227,15 +270,6 @@ def __init__(self):
227270

228271
# --- Global variables for collecting all types ---
229272

230-
# A global counter of the number of typecodes assigned
231-
_ufl_num_typecodes_ = 1
232-
233-
# A global set of all handler names added
234-
_ufl_all_handler_names_ = set()
235-
236-
# A global array of all Expr subclasses, indexed by typecode
237-
_ufl_all_classes_ = []
238-
239273
# A global dict mapping language_operator_name to the type it
240274
# produces
241275
_ufl_language_operators_ = {}
@@ -245,14 +279,6 @@ def __init__(self):
245279

246280
# --- Mechanism for profiling object creation and deletion ---
247281

248-
# A global array of the number of initialized objects for each
249-
# typecode
250-
_ufl_obj_init_counts_ = [0]
251-
252-
# A global array of the number of deleted objects for each
253-
# typecode
254-
_ufl_obj_del_counts_ = [0]
255-
256282
# Backup of default init and del
257283
_ufl_regular__init__ = __init__
258284

@@ -425,8 +451,6 @@ def geometric_dimension(self):
425451
# Initializing traits here because Expr is not defined in the class
426452
# declaration
427453
Expr._ufl_class_ = Expr
428-
Expr._ufl_all_handler_names_.add(Expr)
429-
Expr._ufl_all_classes_.append(Expr)
430454

431455

432456
def ufl_err_str(expr):

ufl/core/ufl_type.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from ufl.core.expr import Expr
1212
from ufl.core.compute_expr_hash import compute_expr_hash
13-
from ufl.utils.formatting import camel2underscore
1413

1514

1615
# Make UFL type coercion available under the as_ufl name
@@ -214,9 +213,6 @@ def _inherited_ufl_index_dimensions(self):
214213

215214
def update_global_expr_attributes(cls):
216215
"Update global ``Expr`` attributes, mainly by adding *cls* to global collections of ufl types."
217-
Expr._ufl_all_classes_.append(cls)
218-
Expr._ufl_all_handler_names_.add(cls._ufl_handler_name_)
219-
220216
if cls._ufl_is_terminal_modifier_:
221217
Expr._ufl_terminal_modifiers_.append(cls)
222218

@@ -228,11 +224,6 @@ def update_global_expr_attributes(cls):
228224
cls._ufl_function_.__func__.__doc__ = cls.__doc__
229225
Expr._ufl_language_operators_[cls._ufl_handler_name_] = cls._ufl_function_
230226

231-
# Append space for counting object creation and destriction of
232-
# this this type.
233-
Expr._ufl_obj_init_counts_.append(0)
234-
Expr._ufl_obj_del_counts_.append(0)
235-
236227

237228
def ufl_type(is_abstract=False,
238229
is_terminal=None,
@@ -264,13 +255,6 @@ def ufl_type(is_abstract=False,
264255
"""
265256

266257
def _ufl_type_decorator_(cls):
267-
# Determine integer typecode by oncrementally counting all types
268-
typecode = Expr._ufl_num_typecodes_
269-
Expr._ufl_num_typecodes_ += 1
270-
271-
# Determine handler name by a mapping from "TypeName" to "type_name"
272-
handler_name = camel2underscore(cls.__name__)
273-
274258
# is_scalar implies is_index_free
275259
if is_scalar:
276260
_is_index_free = True
@@ -279,8 +263,6 @@ def _ufl_type_decorator_(cls):
279263

280264
# Store type traits
281265
cls._ufl_class_ = cls
282-
set_trait(cls, "handler_name", handler_name, inherit=False)
283-
set_trait(cls, "typecode", typecode, inherit=False)
284266
set_trait(cls, "is_abstract", is_abstract, inherit=False)
285267

286268
set_trait(cls, "is_terminal", is_terminal, inherit=True)

ufl/form.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from ufl.integral import Integral
2020
from ufl.checks import is_scalar_constant_expression
2121
from ufl.equation import Equation
22-
from ufl.core.expr import Expr
22+
from ufl.core.expr import Expr, UFLType
2323
from ufl.core.expr import ufl_err_str
2424
from ufl.constantvalue import Zero
2525

@@ -69,7 +69,7 @@ def _sorted_integrals(integrals):
6969
return tuple(all_integrals) # integrals_dict
7070

7171

72-
class BaseForm(object):
72+
class BaseForm(object, metaclass=UFLType):
7373
"""Description of an object containing arguments"""
7474

7575
# Slots is kept empty to enable multiple inheritance with other classes.

0 commit comments

Comments
 (0)