Skip to content

Commit ef4c1bf

Browse files
authored
Deprecate WithGeometry.create factory function (#4957)
1 parent a101140 commit ef4c1bf

5 files changed

Lines changed: 61 additions & 100 deletions

File tree

docs/source/mesh-coordinates.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ functions over to the new mesh. To move `f` over to ``mesh``, use:
118118

119119
.. code-block:: python3
120120
121-
g = Function(functionspaceimpl.WithGeometry.create(f.function_space(), mesh),
121+
g = Function(functionspaceimpl.WithGeometry(f.function_space(), mesh),
122122
val=f.topological)
123123
124124
This creates a :py:class:`~.Function` `g` which shares data with `f`,

firedrake/checkpointing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,7 @@ def load_mesh(self, name=DEFAULT_MESH_NAME, reorder=None, distribution_parameter
12461246
radial_coord_name = self.get_attr(path, PREFIX + "_radial_coordinates")
12471247
radial_coordinates = self._load_function_topology(tmesh, radial_coord_element, radial_coord_name)
12481248
tV_radial_coord = impl.FunctionSpace(tmesh, radial_coord_element)
1249-
V_radial_coord = impl.WithGeometry.create(tV_radial_coord, mesh)
1249+
V_radial_coord = impl.WithGeometry(tV_radial_coord, mesh)
12501250
radial_coord_function_name = self.get_attr(path, PREFIX + "_radial_coordinate_function")
12511251
mesh.radial_coordinates = Function(V_radial_coord, val=radial_coordinates, name=radial_coord_function_name)
12521252
# The followings are conceptually redundant, but needed.
@@ -1416,7 +1416,7 @@ def _load_function_space(self, mesh, name):
14161416
element = self._load_ufl_element(path, PREFIX + "_ufl_element")
14171417
tV = self._load_function_space_topology(tmesh, element)
14181418
# Construct function space
1419-
V = impl.WithGeometry.create(tV, mesh)
1419+
V = impl.WithGeometry(tV, mesh)
14201420
else:
14211421
raise RuntimeError(f"""
14221422
FunctionSpace ({name}) not found in either of the following path in {self.filename}:

firedrake/functionspace.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ def rec(eles):
313313

314314
mixed_mesh_geometry = MeshSequenceGeometry(meshes)
315315
new = impl.MixedFunctionSpace(spaces, mixed_mesh_geometry.topology, name=name)
316-
return cls.create(new, mixed_mesh_geometry)
316+
return cls(new, mixed_mesh_geometry)
317317

318318

319319
@PETSc.Log.EventDecorator("CreateFunctionSpace")
@@ -331,7 +331,7 @@ def RestrictedFunctionSpace(function_space, boundary_set=[], name=None):
331331
An optional name for the function space.
332332
333333
"""
334-
return impl.WithGeometry.create(impl.RestrictedFunctionSpace(function_space,
335-
boundary_set=boundary_set,
336-
name=name),
337-
function_space.mesh())
334+
return impl.WithGeometry(impl.RestrictedFunctionSpace(function_space,
335+
boundary_set=boundary_set,
336+
name=name),
337+
function_space.mesh())

firedrake/functionspaceimpl.py

Lines changed: 51 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
classes for attaching extra information to instances of these.
55
"""
66

7+
import warnings
78
from collections import OrderedDict
8-
from dataclasses import dataclass
9-
from typing import Optional
109

1110
import numpy
1211

@@ -79,42 +78,57 @@ def check_element(element, top=True):
7978
check_element(e, top=False)
8079

8180

82-
class WithGeometryBase(object):
81+
class WithGeometryBase:
8382
r"""Attach geometric information to a :class:`~.FunctionSpace`.
8483
8584
Function spaces on meshes with different geometry but the same
8685
topology can share data, except for their UFL cell. This class
8786
facilitates that.
8887
89-
Users should not instantiate a :class:`WithGeometryBase` object
90-
explicitly except in a small number of cases.
91-
92-
When instantiating a :class:`WithGeometryBase`, users should call
93-
:meth:`WithGeometryBase.create` rather than ``__init__``.
88+
Parameters
89+
----------
90+
function_space : FunctionSpace or MixedFunctionSpace
91+
Topological function space to attach geometry to.
92+
mesh : MeshGeometry
93+
Mesh with geometric information to use.
94+
parent : WithGeometry
95+
Parent geometric function space if exists.
9496
95-
:arg mesh: The mesh with geometric information to use.
96-
:arg element: The UFL element.
97-
:arg component: The component of this space in a parent vector
98-
element space, or ``None``.
99-
:arg cargo: :class:`FunctionSpaceCargo` instance carrying
100-
Firedrake-specific data that is not required for code
101-
generation.
10297
"""
103-
def __init__(self, mesh, element, component=None, cargo=None):
98+
def __init__(self, function_space, mesh, parent=None):
99+
if isinstance(function_space, MixedFunctionSpace):
100+
if not isinstance(mesh, MeshSequenceGeometry):
101+
raise TypeError(f"Can only use MixedFunctionSpace with MeshSequenceGeometry: got {type(mesh)}")
102+
103+
function_space = function_space.topological
104+
assert mesh.topology == function_space.mesh()
105+
assert mesh.topology != mesh
106+
107+
if function_space.parent is not None:
108+
if parent is None:
109+
raise ValueError("Must pass parent if function_space.parent is not None")
110+
else:
111+
parent = None
112+
113+
element = function_space.ufl_element().reconstruct(cell=mesh.ufl_cell())
104114
if type(element) is finat.ufl.MixedElement:
105115
if not isinstance(mesh, MeshSequenceGeometry):
106116
raise TypeError(f"Can only use MixedElement with MeshSequenceGeometry: got {type(mesh)}")
107-
assert component is None or isinstance(component, int)
108-
assert cargo is None or isinstance(cargo, FunctionSpaceCargo)
109-
super().__init__(mesh, element, label=cargo.topological._label or "")
110-
self.component = component
111-
self.cargo = cargo
117+
assert function_space.component is None or isinstance(function_space.component, int)
118+
119+
self.topological = function_space
120+
self.parent = parent
121+
self.component = function_space.component
112122
self.comm = mesh.comm
123+
super().__init__(mesh, element, label=function_space._label or "")
113124

114125
@classmethod
115126
def create(cls, function_space, mesh, parent=None):
116127
"""Create a :class:`WithGeometry`.
117128
129+
This factory function is deprecated. Use the `WithGeometry` constructor
130+
instead.
131+
118132
Parameters
119133
----------
120134
function_space : FunctionSpace or MixedFunctionSpace
@@ -125,53 +139,22 @@ def create(cls, function_space, mesh, parent=None):
125139
Parent geometric function space if exists.
126140
127141
"""
128-
if isinstance(function_space, MixedFunctionSpace):
129-
if not isinstance(mesh, MeshSequenceGeometry):
130-
raise TypeError(f"Can only use MixedFunctionSpace with MeshSequenceGeometry: got {type(mesh)}")
131-
function_space = function_space.topological
132-
assert mesh.topology == function_space.mesh()
133-
assert mesh.topology != mesh
134-
135-
element = function_space.ufl_element().reconstruct(cell=mesh.ufl_cell())
136-
137-
topological = function_space
138-
component = function_space.component
139-
140-
if function_space.parent is not None:
141-
if parent is None:
142-
raise ValueError("Must pass parent if function_space.parent is not None")
143-
else:
144-
parent = None
145-
146-
cargo = FunctionSpaceCargo(topological, parent)
147-
return cls(mesh, element, component=component, cargo=cargo)
142+
warnings.warn(
143+
"'WithGeometry.create' is deprecated, instantiate them directly instead",
144+
FutureWarning,
145+
)
146+
return cls(function_space, mesh, parent=parent)
148147

149148
def _ufl_signature_data_(self, *args, **kwargs):
150149
return (type(self), self.component,
151150
super()._ufl_signature_data_(*args, **kwargs))
152151

153-
@property
154-
def parent(self):
155-
return self.cargo.parent
156-
157-
@parent.setter
158-
def parent(self, val):
159-
self.cargo.parent = val
160-
161-
@property
162-
def topological(self):
163-
return self.cargo.topological
164-
165-
@topological.setter
166-
def topological(self, val):
167-
self.cargo.topological = val
168-
169152
@cached_property
170153
def subspaces(self):
171154
r"""Split into a tuple of constituent spaces."""
172155
if isinstance(self.topological, MixedFunctionSpace):
173156
return tuple(
174-
type(self).create(subspace, mesh, parent=self)
157+
type(self)(subspace, mesh, parent=self)
175158
for mesh, subspace in zip(self.mesh(), self.topological.subspaces, strict=True)
176159
)
177160
else:
@@ -193,7 +176,7 @@ def ufl_cell(self):
193176

194177
@cached_property
195178
def _components(self):
196-
return tuple(type(self).create(self.topological.sub(i), self.mesh(), parent=self)
179+
return tuple(type(self)(self.topological.sub(i), self.mesh(), parent=self)
197180
for i in range(self.block_size))
198181

199182
@PETSc.Log.EventDecorator()
@@ -367,7 +350,7 @@ def boundary_nodes(self, sub_domain):
367350
return self._shared_data.boundary_nodes(self, sub_domain)
368351

369352
def collapse(self):
370-
return type(self).create(self.topological.collapse(), self.mesh())
353+
return type(self)(self.topological.collapse(), self.mesh())
371354

372355
@classmethod
373356
def make_function_space(cls, mesh, element, name=None):
@@ -395,7 +378,7 @@ def make_function_space(cls, mesh, element, name=None):
395378
# Skip this if we are just building subspaces of an abstract MixedFunctionSpace
396379
if mesh is not topology:
397380
# Create a concrete WithGeometry or FiredrakeDualSpace on this mesh
398-
new = cls.create(new, mesh)
381+
new = cls(new, mesh)
399382
return new
400383

401384
def broken_space(self):
@@ -500,31 +483,21 @@ def reconstruct(
500483
return V
501484

502485

503-
class WithGeometry(WithGeometryBase, ufl.FunctionSpace):
504-
505-
def __init__(self, mesh, element, component=None, cargo=None):
506-
super(WithGeometry, self).__init__(mesh, element,
507-
component=component,
508-
cargo=cargo)
486+
class WithGeometry(WithGeometryBase, ufl.functionspace.FunctionSpace):
509487

510488
def dual(self):
511489
parent = None if self.parent is None else self.parent.dual()
512-
return FiredrakeDualSpace.create(self.topological, self.mesh(), parent=parent)
490+
return FiredrakeDualSpace(self.topological, self.mesh(), parent=parent)
513491

514492

515493
class FiredrakeDualSpace(WithGeometryBase, ufl.functionspace.DualSpace):
516494

517-
def __init__(self, mesh, element, component=None, cargo=None):
518-
super(FiredrakeDualSpace, self).__init__(mesh, element,
519-
component=component,
520-
cargo=cargo)
521-
522495
def dual(self):
523496
parent = None if self.parent is None else self.parent.dual()
524-
return WithGeometry.create(self.topological, self.mesh(), parent=parent)
497+
return WithGeometry(self.topological, self.mesh(), parent=parent)
525498

526499

527-
class FunctionSpace(object):
500+
class FunctionSpace:
528501
r"""A representation of a function space.
529502
530503
A :class:`FunctionSpace` associates degrees of freedom with
@@ -1004,6 +977,7 @@ def __init__(self, function_space, boundary_set=frozenset(), name=None):
1004977
function_space.ufl_element(),
1005978
label=self._label)
1006979
self.function_space = function_space
980+
self.topological = self
1007981
self.name = name or function_space.name
1008982

1009983
def set_shared_data(self):
@@ -1301,7 +1275,7 @@ def __new__(cls, mesh, element, name=None):
13011275
topology = mesh.topology
13021276
self = super(ProxyFunctionSpace, cls).__new__(cls)
13031277
if mesh is not topology:
1304-
return WithGeometry.create(self, mesh)
1278+
return WithGeometry(self, mesh)
13051279
else:
13061280
return self
13071281

@@ -1356,7 +1330,7 @@ def __new__(cls, function_space, boundary_set=frozenset(), name=None):
13561330
topology = function_space._mesh.topology
13571331
self = super(ProxyRestrictedFunctionSpace, cls).__new__(cls)
13581332
if function_space._mesh is not topology:
1359-
return WithGeometry.create(self, function_space._mesh)
1333+
return WithGeometry(self, function_space._mesh)
13601334
else:
13611335
return self
13621336

@@ -1496,16 +1470,3 @@ def top_nodes(self):
14961470
def local_to_global_map(self, bcs, lgmap=None, mat_type=None):
14971471
assert len(bcs) == 0
14981472
return None
1499-
1500-
1501-
@dataclass
1502-
class FunctionSpaceCargo:
1503-
"""Helper class carrying data for a :class:`WithGeometryBase`.
1504-
1505-
It is required because it permits Firedrake to have stripped forms
1506-
that still know Firedrake-specific information (e.g. that they are a
1507-
component of a parent function space).
1508-
"""
1509-
1510-
topological: FunctionSpace
1511-
parent: Optional[WithGeometryBase]

firedrake/mesh.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,7 +2386,7 @@ def __init__(self, coordinates):
23862386

23872387
# Save the coordinates as a 'CoordinatelessFunction' and as a 'Function'
23882388
self._coordinates = coordinates
2389-
V = functionspaceimpl.WithGeometry.create(coordinates.function_space(), self)
2389+
V = functionspaceimpl.WithGeometry(coordinates.function_space(), self)
23902390
self._coordinates_function = function.Function(V, val=coordinates)
23912391

23922392
def _ufl_signature_data_(self, *args, **kwargs):
@@ -3197,7 +3197,7 @@ def make_vom_from_vom_topology(topology, name, tolerance=0.5):
31973197
reference_coordinates = function.CoordinatelessFunction(reference_coordinates_fs,
31983198
val=reference_coordinates_data,
31993199
name=_generate_default_mesh_reference_coordinates_name(name))
3200-
refCoordV = functionspaceimpl.WithGeometry.create(reference_coordinates_fs, vmesh)
3200+
refCoordV = functionspaceimpl.WithGeometry(reference_coordinates_fs, vmesh)
32013201
vmesh.reference_coordinates = function.Function(refCoordV, val=reference_coordinates)
32023202
else:
32033203
# We can't do this in 0D so leave it undefined.

0 commit comments

Comments
 (0)