44classes for attaching extra information to instances of these.
55"""
66
7+ import warnings
78from collections import OrderedDict
8- from dataclasses import dataclass
9- from typing import Optional
109
1110import 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
515493class 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 ]
0 commit comments