Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into connorjward/pyop2-f…
Browse files Browse the repository at this point in the history
…ixes
  • Loading branch information
connorjward committed Dec 5, 2024
2 parents 08709bc + 452b342 commit f08e7d6
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 66 deletions.
2 changes: 1 addition & 1 deletion docker/Dockerfile.env
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN apt-get update \
cmake gfortran git libopenblas-serial-dev \
libtool python3-dev python3-pip python3-tk python3-venv \
python3-requests zlib1g-dev libboost-dev sudo gmsh \
bison flex ninja-build \
bison flex ninja-build pkg-config \
libocct-ocaf-dev libocct-data-exchange-dev \
swig graphviz \
libcurl4-openssl-dev libxml2-dev \
Expand Down
1 change: 1 addition & 0 deletions docs/source/download.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ they have the system dependencies:
* zlib
* flex, bison
* Ninja
* pkg-config

Firedrake has been successfully installed on Windows 10 using the
Windows Subsystem for Linux. There are more detailed instructions for
Expand Down
36 changes: 23 additions & 13 deletions firedrake/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,16 @@ def split(self):

@utils.cached_property
def _components(self):
if self.dof_dset.cdim == 1:
return (self, )
if self.function_space().rank == 0:
return tuple((self, ))
else:
return tuple(CoordinatelessFunction(self.function_space().sub(i), val=op2.DatView(self.dat, j),
name="view[%d](%s)" % (i, self.name()))
for i, j in enumerate(np.ndindex(self.dof_dset.dim)))
if self.dof_dset.cdim == 1:
return (CoordinatelessFunction(self.function_space().sub(0), val=self.dat,
name=f"view[0]({self.name()})"),)
else:
return tuple(CoordinatelessFunction(self.function_space().sub(i), val=op2.DatView(self.dat, j),
name=f"view[{i}]({self.name()})")
for i, j in enumerate(np.ndindex(self.dof_dset.dim)))

@PETSc.Log.EventDecorator()
def sub(self, i):
Expand All @@ -143,9 +147,12 @@ def sub(self, i):
rank-n :class:`~.FunctionSpace`, this returns a proxy object
indexing the ith component of the space, suitable for use in
boundary condition application."""
if len(self.function_space()) == 1:
return self._components[i]
return self.subfunctions[i]
mixed = len(self.function_space()) != 1
data = self.subfunctions if mixed else self._components
bound = len(data)
if i < 0 or i >= bound:
raise IndexError(f"Invalid component {i}, not in [0, {bound})")
return data[i]

@property
def cell_set(self):
Expand Down Expand Up @@ -327,8 +334,8 @@ def split(self):

@utils.cached_property
def _components(self):
if self.function_space().value_size == 1:
return (self, )
if self.function_space().rank == 0:
return tuple((self, ))
else:
return tuple(type(self)(self.function_space().sub(i), self.topological.sub(i))
for i in range(self.function_space().block_size))
Expand All @@ -345,9 +352,12 @@ def sub(self, i):
:func:`~.VectorFunctionSpace` or :func:`~.TensorFunctionSpace` this returns a proxy object
indexing the ith component of the space, suitable for use in
boundary condition application."""
if len(self.function_space()) == 1:
return self._components[i]
return self.subfunctions[i]
mixed = len(self.function_space()) != 1
data = self.subfunctions if mixed else self._components
bound = len(data)
if i < 0 or i >= bound:
raise IndexError(f"Invalid component {i}, not in [0, {bound})")
return data[i]

@PETSc.Log.EventDecorator()
@FunctionMixin._ad_annotate_project
Expand Down
19 changes: 12 additions & 7 deletions firedrake/functionspaceimpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,12 @@ def _components(self):

@PETSc.Log.EventDecorator()
def sub(self, i):
bound = len(self._components)
mixed = len(self) != 1
data = self.subfunctions if mixed else self._components
bound = len(data)
if i < 0 or i >= bound:
raise IndexError("Invalid component %d, not in [0, %d)" % (i, bound))
return self._components[i]
raise IndexError(f"Invalid component {i}, not in [0, {bound})")
return data[i]

@utils.cached_property
def dm(self):
Expand Down Expand Up @@ -654,13 +656,16 @@ def __getitem__(self, i):

@utils.cached_property
def _components(self):
return tuple(ComponentFunctionSpace(self, i) for i in range(self.block_size))
if self.rank == 0:
return self.subfunctions
else:
return tuple(ComponentFunctionSpace(self, i) for i in range(self.block_size))

def sub(self, i):
r"""Return a view into the ith component."""
if self.rank == 0:
assert i == 0
return self
bound = len(self._components)
if i < 0 or i >= bound:
raise IndexError(f"Invalid component {i}, not in [0, {bound})")
return self._components[i]

def __mul__(self, other):
Expand Down
42 changes: 21 additions & 21 deletions firedrake/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@
}


_supported_embedded_cell_types_and_gdims = [(ufl.Cell('interval'), 2),
(ufl.Cell('triangle'), 3),
(ufl.Cell("quadrilateral"), 3),
(ufl.TensorProductCell(ufl.Cell('interval'), ufl.Cell('interval')), 3)]
_supported_embedded_cell_types_and_gdims = [('interval', 2),
('triangle', 3),
("quadrilateral", 3),
("interval * interval", 3)]


unmarked = -1
Expand Down Expand Up @@ -1966,7 +1966,7 @@ def _renumber_entities(self, reorder):
if reorder:
swarm = self.topology_dm
parent = self._parent_mesh.topology_dm
swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid")
swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid").ravel()
parent_renum = self._parent_mesh._dm_renumbering.getIndices()
pStart, _ = parent.getChart()
parent_renum_inv = np.empty_like(parent_renum)
Expand Down Expand Up @@ -2063,7 +2063,7 @@ def cell_parent_cell_list(self):
"""Return a list of parent mesh cells numbers in vertex only
mesh cell order.
"""
cell_parent_cell_list = np.copy(self.topology_dm.getField("parentcellnum"))
cell_parent_cell_list = np.copy(self.topology_dm.getField("parentcellnum").ravel())
self.topology_dm.restoreField("parentcellnum")
return cell_parent_cell_list[self.cell_closure[:, -1]]

Expand All @@ -2082,7 +2082,7 @@ def cell_parent_base_cell_list(self):
"""
if not isinstance(self._parent_mesh, ExtrudedMeshTopology):
raise AttributeError("Parent mesh is not extruded")
cell_parent_base_cell_list = np.copy(self.topology_dm.getField("parentcellbasenum"))
cell_parent_base_cell_list = np.copy(self.topology_dm.getField("parentcellbasenum").ravel())
self.topology_dm.restoreField("parentcellbasenum")
return cell_parent_base_cell_list[self.cell_closure[:, -1]]

Expand All @@ -2103,7 +2103,7 @@ def cell_parent_extrusion_height_list(self):
"""
if not isinstance(self._parent_mesh, ExtrudedMeshTopology):
raise AttributeError("Parent mesh is not extruded.")
cell_parent_extrusion_height_list = np.copy(self.topology_dm.getField("parentcellextrusionheight"))
cell_parent_extrusion_height_list = np.copy(self.topology_dm.getField("parentcellextrusionheight").ravel())
self.topology_dm.restoreField("parentcellextrusionheight")
return cell_parent_extrusion_height_list[self.cell_closure[:, -1]]

Expand All @@ -2123,7 +2123,7 @@ def mark_entities(self, tf, label_value, label_name=None):
@utils.cached_property # TODO: Recalculate if mesh moves
def cell_global_index(self):
"""Return a list of unique cell IDs in vertex only mesh cell order."""
cell_global_index = np.copy(self.topology_dm.getField("globalindex"))
cell_global_index = np.copy(self.topology_dm.getField("globalindex").ravel())
self.topology_dm.restoreField("globalindex")
return cell_global_index

Expand Down Expand Up @@ -2158,8 +2158,8 @@ def _make_input_ordering_sf(swarm, nroots, ilocal):
# ilocal = None -> leaves are swarm points [0, 1, 2, ...).
# ilocal can also be Firedrake cell numbers.
sf = PETSc.SF().create(comm=swarm.comm)
input_ranks = swarm.getField("inputrank")
input_indices = swarm.getField("inputindex")
input_ranks = swarm.getField("inputrank").ravel()
input_indices = swarm.getField("inputindex").ravel()
nleaves = len(input_ranks)
if ilocal is not None and nleaves != len(ilocal):
swarm.restoreField("inputrank")
Expand Down Expand Up @@ -2765,7 +2765,7 @@ def init_cell_orientations(self, expr):
import firedrake.function as function
import firedrake.functionspace as functionspace

if (self.ufl_cell(), self.geometric_dimension()) not in _supported_embedded_cell_types_and_gdims:
if (self.ufl_cell().cellname(), self.geometric_dimension()) not in _supported_embedded_cell_types_and_gdims:
raise NotImplementedError('Only implemented for intervals embedded in 2d and triangles and quadrilaterals embedded in 3d')

if hasattr(self, '_cell_orientations'):
Expand Down Expand Up @@ -3652,7 +3652,7 @@ def _pic_swarm_in_mesh(
# local_points[halo_indices] (it also updates local_points[~halo_indices]`, not changing any values there).
# If some index of local_points_reduced corresponds to a missing point, local_points_reduced[index] is not updated
# when we reduce and it does not update any leaf data, i.e., local_points, when we bcast.
owners = swarm.getField("DMSwarm_rank")
owners = swarm.getField("DMSwarm_rank").ravel()
halo_indices, = np.where(owners != parent_mesh.comm.rank)
halo_indices = halo_indices.astype(IntType)
n = coords.shape[0]
Expand Down Expand Up @@ -3868,13 +3868,13 @@ def _dmswarm_create(

# NOTE ensure that swarm.restoreField is called for each field too!
swarm_coords = swarm.getField("DMSwarmPIC_coor").reshape((num_vertices, gdim))
swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid")
field_parent_cell_nums = swarm.getField("parentcellnum")
swarm_parent_cell_nums = swarm.getField("DMSwarm_cellid").ravel()
field_parent_cell_nums = swarm.getField("parentcellnum").ravel()
field_reference_coords = swarm.getField("refcoord").reshape((num_vertices, tdim))
field_global_index = swarm.getField("globalindex")
field_rank = swarm.getField("DMSwarm_rank")
field_input_rank = swarm.getField("inputrank")
field_input_index = swarm.getField("inputindex")
field_global_index = swarm.getField("globalindex").ravel()
field_rank = swarm.getField("DMSwarm_rank").ravel()
field_input_rank = swarm.getField("inputrank").ravel()
field_input_index = swarm.getField("inputindex").ravel()
swarm_coords[...] = coords
swarm_parent_cell_nums[...] = plex_parent_cell_nums
field_parent_cell_nums[...] = parent_cell_nums
Expand All @@ -3895,8 +3895,8 @@ def _dmswarm_create(
swarm.restoreField("DMSwarm_cellid")

if extruded:
field_base_parent_cell_nums = swarm.getField("parentcellbasenum")
field_extrusion_heights = swarm.getField("parentcellextrusionheight")
field_base_parent_cell_nums = swarm.getField("parentcellbasenum").ravel()
field_extrusion_heights = swarm.getField("parentcellextrusionheight").ravel()
field_base_parent_cell_nums[...] = base_parent_cell_nums
field_extrusion_heights[...] = extrusion_heights
swarm.restoreField("parentcellbasenum")
Expand Down
17 changes: 12 additions & 5 deletions firedrake/output/vtk_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ def __init__(self, filename, project_output=False, comm=None, mode="w",
@no_annotations
def _prepare_output(self, function, max_elem):
from firedrake import FunctionSpace, VectorFunctionSpace, \
TensorFunctionSpace, Function
TensorFunctionSpace, Function, Cofunction

name = function.name()
# Need to project/interpolate?
Expand All @@ -477,16 +477,23 @@ def _prepare_output(self, function, max_elem):
shape=shape)
else:
raise ValueError("Unsupported shape %s" % (shape, ))
output = Function(V)
if isinstance(function, Function):
output = Function(V)
else:
assert isinstance(function, Cofunction)
output = Function(V.dual())

if self.project:
if isinstance(function, Cofunction):
raise ValueError("Can not project Cofunctions")
output.project(function)
else:
output.interpolate(function)

return OFunction(array=get_array(output), name=name, function=output)

def _write_vtu(self, *functions):
from firedrake.function import Function
from firedrake import Function, Cofunction

# Check if the user has requested to write out a plain mesh
if len(functions) == 1 and isinstance(functions[0], ufl.Mesh):
Expand All @@ -496,8 +503,8 @@ def _write_vtu(self, *functions):
functions = [Function(V)]

for f in functions:
if not isinstance(f, Function):
raise ValueError("Can only output Functions or a single mesh, not %r" % type(f))
if not isinstance(f, (Function, Cofunction)):
raise ValueError(f"Can only output Functions, Cofunctions or a single mesh, not {type(f).__name__}")
meshes = tuple(extract_unique_domain(f) for f in functions)
if not all(m == meshes[0] for m in meshes):
raise ValueError("All functions must be on same mesh")
Expand Down
4 changes: 3 additions & 1 deletion scripts/firedrake-install
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ def get_petsc_options(minimal=False):
petsc_options.add("--download-suitesparse")
petsc_options.add("--download-pastix")
# Required by pastix
petsc_options.add("--download-hwloc")
petsc_options.update({"--download-hwloc", "--download-netlib-lapack", "--with-netlib-lapack-c-bindings"})
if osname == "Darwin":
petsc_options.add("--download-hwloc-configure-arguments=--disable-opencl")
# Serial mesh partitioner
Expand Down Expand Up @@ -1517,6 +1517,7 @@ if mode == "install" or not args.update_script:
if osname == "Darwin":
package_manager = "brew"
required_packages = ["gcc",
"pkg-config",
"autoconf",
"make",
"automake",
Expand All @@ -1535,6 +1536,7 @@ if mode == "install" or not args.update_script:
"flex", # for ptscotch
"cmake",
"gfortran",
"pkg-config",
"git",
"libcurl4-openssl-dev",
"pkgconf", # for p4est
Expand Down
22 changes: 16 additions & 6 deletions tests/firedrake/output/test_pvd_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,16 @@ def test_bad_file_name(tmpdir):
VTKFile(str(tmpdir.join("foo.vtu")))


def test_different_functions(mesh, pvd):
@pytest.mark.parametrize("space",
["primal", "dual"])
def test_different_functions(mesh, pvd, space):
V = FunctionSpace(mesh, "DG", 0)

f = Function(V, name="foo")
g = Function(V, name="bar")
if space == "primal":
f = Function(V, name="foo")
g = Function(V, name="bar")
else:
f = Cofunction(V.dual(), name="foo")
g = Cofunction(V.dual(), name="bar")

pvd.write(f)

Expand Down Expand Up @@ -136,9 +141,14 @@ def test_not_function(mesh, pvd):
pvd.write(grad(f))


def test_append(mesh, tmpdir):
@pytest.mark.parametrize("space",
["primal", "dual"])
def test_append(mesh, tmpdir, space):
V = FunctionSpace(mesh, "DG", 0)
g = Function(V)
if space == "primal":
g = Function(V)
else:
g = Cofunction(V.dual())

outfile = VTKFile(str(tmpdir.join("restart_test.pvd")))
outfile.write(g)
Expand Down
Loading

0 comments on commit f08e7d6

Please sign in to comment.