Skip to content

Commit cb6fa59

Browse files
committed
First stab at enabling quads
1 parent f3fac54 commit cb6fa59

File tree

1 file changed

+68
-92
lines changed

1 file changed

+68
-92
lines changed

firedrake/mesh.py

+68-92
Original file line numberDiff line numberDiff line change
@@ -509,68 +509,6 @@ class ClosureOrdering(enum.Enum):
509509
FIAT = "fiat"
510510

511511

512-
# TODO do we need to ensure that the cell orientation is always zero?
513-
# Note that the permutation is expressed numbering each entity type from zero,
514-
# meaning that the indices shown in the diagrams must be offset.
515-
_PLEX_TO_FIAT_CLOSURE_PERM = {
516-
# UFCInterval:
517-
#
518-
# 0---2---1
519-
#
520-
# PETSc.DM.PolytopeType.SEGMENT:
521-
#
522-
# 1---0---2
523-
"interval": {
524-
0: np.array([1, 2]) - 1,
525-
1: np.array([0]),
526-
},
527-
528-
# UFCTriangle:
529-
#
530-
# 1
531-
# | \
532-
# 5 3
533-
# | 6 \
534-
# 0---4---2
535-
#
536-
# PETSc.DM.PolytopeType.TRIANGLE:
537-
#
538-
# 4
539-
# | \
540-
# 3 1
541-
# | 0 \
542-
# 6---2---5
543-
"triangle": {
544-
0: np.array([6, 4, 5]) - 1 - 3,
545-
1: np.array([1, 2, 3]) - 1,
546-
2: np.array([0]),
547-
},
548-
549-
# UFCQuadrilateral:
550-
#
551-
# 1---7---3
552-
# | |
553-
# 4 8 5
554-
# | |
555-
# 0---6---2
556-
#
557-
# PETSc.DM.PolytopeType.QUADRILATERAL
558-
#
559-
# 5---4---8
560-
# | |
561-
# 1 0 3
562-
# | |
563-
# 6---2---7
564-
"quadrilateral": {
565-
0: np.array([6, 5, 7, 8]) - 1 - 4,
566-
1: np.array([1, 3, 2, 4]) - 1,
567-
2: np.array([0]),
568-
}
569-
}
570-
"""
571-
"""
572-
573-
574512
class AbstractMeshTopology(abc.ABC):
575513
"""A representation of an abstract mesh topology without a concrete
576514
PETSc DM implementation"""
@@ -670,19 +608,6 @@ def callback(self):
670608
# entity_dofs[-2] = 1
671609
# facet_numbering = self.create_section(entity_dofs)
672610
# self._facet_ordering = dmcommon.get_facet_ordering(self.topology_dm, facet_numbering)
673-
# Derive a cell numbering from the Plex renumbering
674-
# these can all be determined from the axes and are only required
675-
# internally for things like map construction (which I also do internally)
676-
# entity_dofs = np.zeros(tdim+1, dtype=IntType)
677-
# entity_dofs[-1] = 1
678-
# self._cell_numbering = self.create_section(entity_dofs)
679-
# entity_dofs[:] = 0
680-
# entity_dofs[0] = 1
681-
# self._vertex_numbering = self.create_section(entity_dofs)
682-
# entity_dofs[:] = 0
683-
# entity_dofs[-2] = 1
684-
# facet_numbering = self.create_section(entity_dofs)
685-
# self._facet_ordering = dmcommon.get_facet_ordering(self.topology_dm, facet_numbering)
686611

687612
points = op3.Axis(
688613
{
@@ -737,6 +662,34 @@ def _renumber_entities(self, reorder):
737662
"""Renumber entities."""
738663
pass
739664

665+
@utils.cached_property
666+
def _vertex_numbering(self):
667+
assert not hasattr(self, "_callback"), "Mesh must be initialised"
668+
return self._entity_numbering(self.vertex_label)
669+
670+
@utils.cached_property
671+
def _cell_numbering(self):
672+
assert not hasattr(self, "_callback"), "Mesh must be initialised"
673+
return self._entity_numbering(self.cell_label)
674+
675+
@utils.cached_property
676+
def _facet_numbering(self):
677+
assert not hasattr(self, "_callback"), "Mesh must be initialised"
678+
return self._entity_numbering(self.facet_label)
679+
680+
def _entity_numbering(self, label):
681+
component_index = tuple(c.label for c in self.points.components).index(label)
682+
683+
section = PETSc.Section().create(self._comm)
684+
section.setChart(*self.topology_dm.getChart())
685+
686+
renumbering = self.points._default_to_applied_numbering[component_index]
687+
for old_component_num, new_component_num in enumerate(renumbering):
688+
old_pt = old_component_num + self.points._component_offsets[component_index]
689+
section.setOffset(old_pt, new_component_num)
690+
691+
return section
692+
740693
@property
741694
def comm(self):
742695
return self.user_comm
@@ -901,19 +854,6 @@ def _closure_map(self, ordering):
901854
# closure_ordering
902855
closure_data_concat = np.concatenate(closure_data, axis=1)
903856

904-
if self.comm.size > 1:
905-
# TODO determine the *global* vertex numbering, else ranks may disagree
906-
# on the direction of some edges/faces
907-
# TODO cache this
908-
# vertex_numbering = self._vertex_numbering.createGlobalSection(
909-
# self.topology_dm.getPointSF()
910-
# )
911-
raise NotImplementedError
912-
# ah, but the vertices have already been renumbered! Therefore don't
913-
# want to use the component_numbering but instead an identity numbering
914-
# vertex_numbering = self.points.component_numbering(self.vert_label)
915-
vertex_numbering = None # change this when implemented
916-
917857
cell = self.ufl_cell()
918858
if cell.is_simplex():
919859
topology = FIAT.ufc_cell(cell).get_topology()
@@ -924,12 +864,42 @@ def _closure_map(self, ordering):
924864
reordered = dmcommon.closure_ordering(
925865
self,
926866
closure_data_concat,
927-
vertex_numbering,
867+
None, # vertex numbering already applied, clean up Cython to reflect this
928868
entity_per_cell
929869
)
930-
# reordered is ordered in order of increasing dimension
870+
# reordered is ordered in order of increasing dimension, now
871+
# split it apart by dimension
931872
closure_data = tuple(
932-
reordered[:, start:stop] for start, stop in pairwise(steps(closure_sizes))
873+
reordered[:, start:stop]
874+
for start, stop in pairwise(steps(closure_sizes))
875+
)
876+
877+
elif cell.cellname() == "quadrilateral":
878+
from firedrake_citations import Citations
879+
880+
Citations().register("Homolya2016")
881+
Citations().register("McRae2016")
882+
883+
plex = self.topology_dm
884+
cell_ranks = dmcommon.get_cell_remote_ranks(plex)
885+
facet_orientations = dmcommon.quadrilateral_facet_orientations(
886+
plex, self._global_vertex_numbering, cell_ranks
887+
)
888+
cell_orientations = dmcommon.orientations_facet2cell(
889+
plex,
890+
self._global_vertex_numbering,
891+
cell_ranks,
892+
facet_orientations,
893+
self._cell_numbering,
894+
)
895+
dmcommon.exchange_cell_orientations(
896+
plex, self._cell_numbering, cell_orientations
897+
)
898+
899+
# do not return...
900+
# TODO pass closure data here, don't do inside
901+
XXX = dmcommon.quadrilateral_closure_ordering(
902+
plex, vertex_numbering, cell_numbering, cell_orientations
933903
)
934904
else:
935905
raise NotImplementedError
@@ -1198,6 +1168,12 @@ def mark_entities(self, tf, label_value, label_name=None):
11981168
def extruded_periodic(self):
11991169
return self.cell_set._extruded_periodic
12001170

1171+
@utils.cached_property
1172+
def _global_vertex_numbering(self):
1173+
return self._vertex_numbering.createGlobalSection(
1174+
self.topology_dm.getPointSF()
1175+
)
1176+
12011177

12021178
class MeshTopology(AbstractMeshTopology):
12031179
"""A representation of mesh topology implemented on a PETSc DMPlex."""
@@ -2029,7 +2005,7 @@ def cell_closure(self):
20292005

20302006
# Cell numbering and global vertex numbering
20312007
cell_numbering = self._cell_numbering
2032-
vertex_numbering = self._vertex_numbering.createGlobalSection(swarm.getPointSF())
2008+
vertex_numbering = self._global_vertex_numbering
20332009

20342010
cell = self.ufl_cell()
20352011
assert tdim == cell.topological_dimension()

0 commit comments

Comments
 (0)