-
Notifications
You must be signed in to change notification settings - Fork 166
RestrictedFunctionSpace: support Fieldsplit, multigrid, and python PC #4169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c55b648
1b20212
475fe05
fd42aa1
3c63f6c
7a07dff
f165b4b
6512d47
c0287de
82b7b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -378,17 +378,23 @@ def make_function_space(cls, mesh, element, name=None): | |
new = cls.create(new, mesh) | ||
return new | ||
|
||
def reconstruct(self, mesh=None, name=None, **kwargs): | ||
def reconstruct(self, mesh=None, element=None, boundary_set=None, name=None, **kwargs): | ||
r"""Reconstruct this :class:`.WithGeometryBase` . | ||
|
||
:kwarg mesh: the new :func:`~.Mesh` (defaults to same mesh) | ||
:kwarg element: the new :class:`finat.ufl.FiniteElement` (defaults to same element) | ||
:kwarg boundary_set: boundary subdomain labels defining a new | ||
:func:`~.RestrictedFunctionSpace` (defaults to same boundary_set) | ||
:kwarg name: the new name (defaults to None) | ||
:returns: the new function space of the same class as ``self``. | ||
|
||
Any extra kwargs are used to reconstruct the finite element. | ||
For details see :meth:`finat.ufl.finiteelement.FiniteElement.reconstruct`. | ||
""" | ||
V_parent = self | ||
if boundary_set is None: | ||
boundary_set = V_parent.boundary_set | ||
|
||
# Deal with ProxyFunctionSpace | ||
indices = [] | ||
while True: | ||
|
@@ -403,15 +409,19 @@ def reconstruct(self, mesh=None, name=None, **kwargs): | |
|
||
if mesh is None: | ||
mesh = V_parent.mesh() | ||
if element is None: | ||
element = V_parent.ufl_element() | ||
|
||
element = V_parent.ufl_element() | ||
cell = mesh.topology.ufl_cell() | ||
if len(kwargs) > 0 or element.cell != cell: | ||
element = element.reconstruct(cell=cell, **kwargs) | ||
|
||
V = type(self).make_function_space(mesh, element, name=name) | ||
for i in reversed(indices): | ||
V = V.sub(i) | ||
|
||
if boundary_set: | ||
V = RestrictedFunctionSpace(V, boundary_set=boundary_set, name=V.name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For separate discussion: should |
||
return V | ||
|
||
|
||
|
@@ -876,6 +886,14 @@ class RestrictedFunctionSpace(FunctionSpace): | |
If using this class to solve or similar, a list of DirichletBCs will still | ||
need to be specified on this space and passed into the function. | ||
""" | ||
def __new__(cls, function_space, boundary_set=frozenset(), name=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
mesh = function_space.mesh() | ||
if mesh is not mesh.topology: | ||
V = RestrictedFunctionSpace(function_space.topological, | ||
boundary_set=boundary_set, name=name) | ||
return type(function_space).create(V, mesh) | ||
return FunctionSpace.__new__(cls) | ||
|
||
def __init__(self, function_space, boundary_set=frozenset(), name=None): | ||
label = "" | ||
boundary_set_ = [] | ||
|
@@ -901,8 +919,7 @@ def __init__(self, function_space, boundary_set=frozenset(), name=None): | |
function_space.ufl_element(), | ||
label=self._label) | ||
self.function_space = function_space | ||
self.name = name or (function_space.name or "Restricted" + "_" | ||
+ "_".join(sorted(map(str, self.boundary_set)))) | ||
self.name = name or function_space.name | ||
|
||
def set_shared_data(self): | ||
sdata = get_shared_data(self._mesh, self.ufl_element(), self.boundary_set) | ||
|
@@ -1200,7 +1217,7 @@ class ProxyFunctionSpace(FunctionSpace): | |
""" | ||
def __new__(cls, mesh, element, name=None): | ||
topology = mesh.topology | ||
self = super(ProxyFunctionSpace, cls).__new__(cls) | ||
self = FunctionSpace.__new__(cls) | ||
if mesh is not topology: | ||
return WithGeometry.create(self, mesh) | ||
else: | ||
|
@@ -1255,7 +1272,7 @@ class ProxyRestrictedFunctionSpace(RestrictedFunctionSpace): | |
""" | ||
def __new__(cls, function_space, boundary_set=frozenset(), name=None): | ||
topology = function_space._mesh.topology | ||
self = super(ProxyRestrictedFunctionSpace, cls).__new__(cls) | ||
self = FunctionSpace.__new__(cls) | ||
if function_space._mesh is not topology: | ||
return WithGeometry.create(self, function_space._mesh) | ||
else: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,18 +58,17 @@ def prolong(coarse, fine): | |
repeat = (fine_level - coarse_level)*refinements_per_level | ||
next_level = coarse_level * refinements_per_level | ||
|
||
element = Vc.ufl_element() | ||
meshes = hierarchy._meshes | ||
for j in range(repeat): | ||
next_level += 1 | ||
if j == repeat - 1: | ||
next = fine | ||
Vf = fine.function_space() | ||
else: | ||
Vf = firedrake.FunctionSpace(meshes[next_level], element) | ||
Vf = Vc.reconstruct(mesh=meshes[next_level]) | ||
next = firedrake.Function(Vf) | ||
|
||
coarse_coords = Vc.mesh().coordinates | ||
coarse_coords = get_coordinates(Vc) | ||
fine_to_coarse = utils.fine_node_to_coarse_node_map(Vf, Vc) | ||
fine_to_coarse_coords = utils.fine_node_to_coarse_node_map(Vf, coarse_coords.function_space()) | ||
kernel = kernels.prolong_kernel(coarse) | ||
|
@@ -119,7 +118,6 @@ def restrict(fine_dual, coarse_dual): | |
repeat = (fine_level - coarse_level)*refinements_per_level | ||
next_level = fine_level * refinements_per_level | ||
|
||
element = Vc.ufl_element() | ||
meshes = hierarchy._meshes | ||
|
||
for j in range(repeat): | ||
|
@@ -128,15 +126,15 @@ def restrict(fine_dual, coarse_dual): | |
coarse_dual.dat.zero() | ||
next = coarse_dual | ||
else: | ||
Vc = firedrake.FunctionSpace(meshes[next_level], element) | ||
next = firedrake.Cofunction(Vc.dual()) | ||
Vc = Vf.reconstruct(mesh=meshes[next_level]) | ||
next = firedrake.Cofunction(Vc) | ||
Vc = next.function_space() | ||
# XXX: Should be able to figure out locations by pushing forward | ||
# reference cell node locations to physical space. | ||
# x = \sum_i c_i \phi_i(x_hat) | ||
node_locations = utils.physical_node_locations(Vf) | ||
node_locations = utils.physical_node_locations(Vf.dual()) | ||
|
||
coarse_coords = Vc.mesh().coordinates | ||
coarse_coords = get_coordinates(Vc.dual()) | ||
fine_to_coarse = utils.fine_node_to_coarse_node_map(Vf, Vc) | ||
fine_to_coarse_coords = utils.fine_node_to_coarse_node_map(Vf, coarse_coords.function_space()) | ||
# Have to do this, because the node set core size is not right for | ||
|
@@ -195,7 +193,6 @@ def inject(fine, coarse): | |
repeat = (fine_level - coarse_level)*refinements_per_level | ||
next_level = fine_level * refinements_per_level | ||
|
||
element = Vc.ufl_element() | ||
meshes = hierarchy._meshes | ||
|
||
for j in range(repeat): | ||
|
@@ -205,12 +202,12 @@ def inject(fine, coarse): | |
next = coarse | ||
Vc = next.function_space() | ||
else: | ||
Vc = firedrake.FunctionSpace(meshes[next_level], element) | ||
Vc = Vf.reconstruct(mesh=meshes[next_level]) | ||
next = firedrake.Function(Vc) | ||
if not dg: | ||
node_locations = utils.physical_node_locations(Vc) | ||
|
||
fine_coords = Vf.mesh().coordinates | ||
fine_coords = get_coordinates(Vf) | ||
coarse_node_to_fine_nodes = utils.coarse_node_to_fine_node_map(Vc, Vf) | ||
coarse_node_to_fine_coords = utils.coarse_node_to_fine_node_map(Vc, fine_coords.function_space()) | ||
|
||
|
@@ -242,3 +239,11 @@ def inject(fine, coarse): | |
fine = next | ||
Vf = Vc | ||
return coarse | ||
|
||
|
||
def get_coordinates(V): | ||
coords = V.mesh().coordinates | ||
if V.boundary_set: | ||
W = V.reconstruct(element=coords.function_space().ufl_element()) | ||
coords = firedrake.Function(W).interpolate(coords) | ||
return coords | ||
Comment on lines
+244
to
+249
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ksagiyam I need to restrict There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need to do that here? Normally, we shouldn't need to do that as restricted function spaces are just regular function spaces with different DoF ordering. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we can reconstruct named spaces without too much worry, as the new name defaults to
None