Skip to content

Commit 8634d5d

Browse files
committed
mixed_cell
1 parent 1b26a8f commit 8634d5d

File tree

3 files changed

+125
-7
lines changed

3 files changed

+125
-7
lines changed

ufl/algorithms/estimate_degrees.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ def _reduce_degree(self, v, f):
9898
This is used when derivatives are taken. It does not reduce the degree when
9999
TensorProduct elements or quadrilateral elements are involved.
100100
"""
101-
# Can have multiple domains of the same cell type.
102-
(cell,) = set(d.ufl_cell() for d in extract_domains(v))
103-
if isinstance(f, int) and cell.cellname() not in ["quadrilateral", "hexahedron"]:
101+
# Can have multiple domains e.g. in mixed cell type problems.
102+
cells = set(d.ufl_cell() for d in extract_domains(v))
103+
if isinstance(f, int) and all(cell.cellname() not in ["quadrilateral", "hexahedron"] for cell in cells):
104104
return max(f - 1, 0)
105105
else:
106106
return f

ufl/cell.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,11 @@ def reconstruct(self, **kwargs: typing.Any) -> Cell:
339339
raise TypeError(f"reconstruct() got unexpected keyword argument '{key}'")
340340
return Cell(self._cellname)
341341

342+
@property
343+
def cells(self):
344+
"""Return the component cells."""
345+
return (self,)
346+
342347

343348
class TensorProductCell(AbstractCell):
344349
"""Tensor product cell."""
@@ -440,6 +445,11 @@ def reconstruct(self, **kwargs: typing.Any) -> AbstractCell:
440445
raise TypeError(f"reconstruct() got unexpected keyword argument '{key}'")
441446
return TensorProductCell(*self._cells)
442447

448+
@property
449+
def cells(self):
450+
"""Return the component cells."""
451+
return (self,)
452+
443453

444454
def simplex(topological_dimension: int):
445455
"""Return a simplex cell of the given dimension."""
@@ -484,3 +494,107 @@ def as_cell(cell: AbstractCell | str | tuple[AbstractCell, ...]) -> AbstractCell
484494
return TensorProductCell(*cell)
485495
else:
486496
raise ValueError(f"Invalid cell {cell}.")
497+
498+
499+
class CellSequence(AbstractCell):
500+
"""Representation of a named finite element cell with known structure."""
501+
502+
__slots__ = (
503+
"_cells",
504+
"_tdim",
505+
)
506+
507+
def __init__(self, cells):
508+
"""Initialise.
509+
510+
Args:
511+
cellname: Name of the cell
512+
"""
513+
self._cells = cells
514+
#self._tdim = len(self._sub_entity_celltypes) - 1
515+
516+
def topological_dimension(self) -> int:
517+
"""Return the dimension of the topology of this cell."""
518+
#return self._tdim
519+
raise RuntimeError(f"Should not call this method on {type(self)}")
520+
521+
def is_simplex(self) -> bool:
522+
"""Return True if this is a simplex cell."""
523+
#return self._cellname in ["vertex", "interval", "triangle", "tetrahedron"]
524+
raise RuntimeError(f"Should not call this method on {type(self)}")
525+
526+
def has_simplex_facets(self) -> bool:
527+
"""Return True if all the facets of this cell are simplex cells."""
528+
#return self._cellname in ["interval", "triangle", "quadrilateral", "tetrahedron"]
529+
raise RuntimeError(f"Should not call this method on {type(self)}")
530+
531+
def num_sub_entities(self, dim: int) -> int:
532+
"""Get the number of sub-entities of the given dimension."""
533+
#if dim < 0:
534+
# return 0
535+
#try:
536+
# return self._num_cell_entities[dim]
537+
#except IndexError:
538+
# return 0
539+
raise RuntimeError(f"Should not call this method on {type(self)}")
540+
541+
def sub_entities(self, dim: int) -> typing.Tuple[AbstractCell, ...]:
542+
"""Get the sub-entities of the given dimension."""
543+
#if dim < 0:
544+
# return ()
545+
#try:
546+
# return self._sub_entities[dim]
547+
#except IndexError:
548+
# return ()
549+
raise RuntimeError(f"Should not call this method on {type(self)}")
550+
551+
def sub_entity_types(self, dim: int) -> typing.Tuple[AbstractCell, ...]:
552+
"""Get the unique sub-entity types of the given dimension."""
553+
#if dim < 0:
554+
# return ()
555+
#try:
556+
# return self._sub_entity_types[dim]
557+
#except IndexError:
558+
# return ()
559+
raise RuntimeError(f"Should not call this method on {type(self)}")
560+
561+
def _lt(self, other) -> bool:
562+
#return self._cellname < other._cellname
563+
raise RuntimeError(f"Should not call this method on {type(self)}")
564+
565+
def cellname(self) -> str:
566+
"""Return the cellname of the cell."""
567+
#return self._cellname
568+
raise RuntimeError(f"Should not call this method on {type(self)}")
569+
570+
def reconstruct(self, **kwargs: typing.Any) -> CellSequence:
571+
"""Reconstruct this cell, overwriting properties by those in kwargs."""
572+
#for key, value in kwargs.items():
573+
# raise TypeError(f"reconstruct() got unexpected keyword argument '{key}'")
574+
#return Cell(self._cellname)
575+
raise RuntimeError(f"Should not call this method on {type(self)}")
576+
577+
def __repr__(self):
578+
"""Representation."""
579+
return "CellSequence(%s)" % (repr(self._cells),)
580+
581+
def __str__(self):
582+
"""Format as a string."""
583+
return "<CellSequence #%s>" % (self._cells,)
584+
585+
def _ufl_hash_data_(self):
586+
"""UFL hash data."""
587+
return ("CellSequence", tuple(c._ufl_hash_data_() for c in self._cells))
588+
589+
def _ufl_signature_data_(self, renumbering):
590+
"""UFL signature data."""
591+
return ("CellSequence", tuple(c._ufl_signature_data_(renumbering) for c in self._cells))
592+
593+
def _ufl_sort_key_(self):
594+
"""UFL sort key."""
595+
return ("CellSequence", tuple(c._ufl_sort_key_() for c in self._cells))
596+
597+
@property
598+
def cells(self):
599+
"""Return the component cells."""
600+
return self._cells

ufl/domain.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from ufl.core.expr import Expr
1717
from ufl.finiteelement import AbstractFiniteElement # To avoid cyclic import when type-hinting.
1818
from ufl.form import Form
19-
from ufl.cell import AbstractCell
19+
from ufl.cell import AbstractCell, CellSequence
2020
from ufl.core.ufl_id import attach_ufl_id
2121
from ufl.core.ufl_type import UFLObject
2222
from ufl.corealg.traversal import traverse_unique_terminals
@@ -211,14 +211,18 @@ def __init__(self, meshes: Sequence[Mesh]):
211211
if any(isinstance(m, MeshSequence) for m in meshes):
212212
raise NotImplementedError("""
213213
Currently component meshes can not include MeshSequence instances""")
214-
# currently only support single cell type.
215-
(self._ufl_cell,) = set(m.ufl_cell() for m in meshes)
214+
#(self._ufl_cell,) = set(m.ufl_cell() for m in meshes)
215+
self._ufl_cell = CellSequence(tuple(m.ufl_cell() for m in meshes))
216216
(gdim,) = set(m.geometric_dimension() for m in meshes)
217217
# TODO: Need to change for more general mixed meshes.
218-
(tdim,) = set(m.topological_dimension() for m in meshes)
218+
tdim = max(m.topological_dimension() for m in meshes)#???
219219
AbstractDomain.__init__(self, tdim, gdim)
220220
self._meshes = tuple(meshes)
221221

222+
#def topological_dimension(self):
223+
# """Return the dimension of the topology of this domain."""
224+
# raise AssertionError
225+
222226
def ufl_cell(self):
223227
"""Get the cell."""
224228
# TODO: Might need MixedCell class for more general mixed meshes.

0 commit comments

Comments
 (0)