diff --git a/hog/operator_generation/function_space_impls.py b/hog/operator_generation/function_space_impls.py index 7b3a51fe8857c1a2c7b476ee7a9a143cbfda8e4b..fdad32bea2f71bb248b8c633c674dd4cba2c925e 100644 --- a/hog/operator_generation/function_space_impls.py +++ b/hog/operator_generation/function_space_impls.py @@ -36,8 +36,10 @@ from hog.function_space import ( from hog.operator_generation.indexing import ( CellType, FaceType, + VolumeDoFMemoryLayout, micro_element_to_vertex_indices, micro_vertex_to_edge_indices, + micro_element_to_volume_indices, IndexingInfo, ) from hog.operator_generation.types import HOGType @@ -98,6 +100,8 @@ class FunctionSpaceImpl(ABC): impl_class = P2FunctionSpaceImpl elif func_space.degree == 1: impl_class = P1FunctionSpaceImpl + elif func_space.degree == 0: + impl_class = P0FunctionSpaceImpl else: raise HOGException("Lagrangian function space must be of order 1 or 2.") elif isinstance(func_space, TensorialVectorFunctionSpace): @@ -241,6 +245,113 @@ class FunctionSpaceImpl(ABC): else: return self.name +class P0FunctionSpaceImpl(FunctionSpaceImpl): + def __init__( + self, + fe_space: FunctionSpace, + name: str, + type_descriptor: HOGType, + is_pointer: bool = False, + ): + super().__init__(fe_space, name, type_descriptor, is_pointer) + self.field = self._create_field(name) + + def pre_communication(self, dim: int) -> str: + return "" + # if dim == 2: + # return f"communication::syncFunctionBetweenPrimitives( {self.name}, level, communication::syncDirection_t::LOW2HIGH );" + # else: + # return ( + # f"{self._deref()}.communicate< Face, Cell >( level );\n" + # f"{self._deref()}.communicate< Edge, Cell >( level );\n" + # f"{self._deref()}.communicate< Vertex, Cell >( level );" + # ) + + def zero_halos(self, dim: int) -> str: + return "" + # if dim == 2: + # return ( + # f"for ( const auto& idx : vertexdof::macroface::Iterator( level ) ) {{\n" + # f" if ( vertexdof::macroface::isVertexOnBoundary( level, idx ) ) {{\n" + # f" auto arrayIdx = vertexdof::macroface::index( level, idx.x(), idx.y() );\n" + # f" _data_{self.name}[arrayIdx] = {self.type_descriptor.pystencils_type}( 0 );\n" + # f" }}\n" + # f"}}" + # ) + # else: + # return ( + # f"for ( const auto& idx : vertexdof::macrocell::Iterator( level ) ) {{\n" + # f" if ( !vertexdof::macrocell::isOnCellFace( idx, level ).empty() ) {{\n" + # f" auto arrayIdx = vertexdof::macrocell::index( level, idx.x(), idx.y(), idx.z() );\n" + # f" _data_{self.name}[arrayIdx] = {self.type_descriptor.pystencils_type}( 0 );\n" + # f" }}\n" + # f"}}" + # ) + + def post_communication( + self, dim: int, params: str, transform_basis: bool = True + ) -> str: + return "" + # if dim == 2: + # return ( + # f"{self._deref()}.communicateAdditively < Face, Edge > ( {params} );\n" + # f"{self._deref()}.communicateAdditively < Face, Vertex > ( {params} );" + # ) + # else: + # return ( + # f"{self._deref()}.communicateAdditively< Cell, Face >( {params} );\n" + # f"{self._deref()}.communicateAdditively< Cell, Edge >( {params} );\n" + # f"{self._deref()}.communicateAdditively< Cell, Vertex >( {params} );" + # ) + + def pointer_retrieval(self, dim: int) -> str: + """C++ code for retrieving pointers to the numerical data stored in the macro primitives `face` (2d) or `cell` (3d).""" + Macro = {2: "Face", 3: "Cell"}[dim] + macro = {2: "face", 3: "cell"}[dim] + + return f"{self.type_descriptor.pystencils_type}* _data_{self.name} = {self._deref()}.getDGFunction()->volumeDoFFunction()->dofMemory( it.first, level );" + + def invert_elementwise(self, dim: int) -> str: + return f"{self._deref()}.invertElementwise( level );" + + def local_dofs( + self, + geometry: ElementGeometry, + element_index: Tuple[int, int, int], + element_type: Union[FaceType, CellType], + indexing_info: IndexingInfo, + element_vertex_ordering: List[int], + ) -> List[Field.Access]: + vertex_dof_indices = micro_element_to_volume_indices( + element_type, element_index, 1, VolumeDoFMemoryLayout.SoA + ) + + vertex_array_indices = [ + dof_idx.array_index(geometry, indexing_info) + for dof_idx in vertex_dof_indices + ] + + return [ + self.field.absolute_access((idx,), (0,)) for idx in vertex_array_indices + ] + + def func_type_string(self) -> str: + return f"P0Function< {self.type_descriptor.pystencils_type} >" + + def includes(self) -> Set[str]: + return {f"hyteg/p0functionspace/P0Function.hpp"} + + def dof_transformation( + self, + geometry: ElementGeometry, + element_index: Tuple[int, int, int], + element_type: Union[FaceType, CellType], + element_vertex_ordering: List[int], + ) -> Tuple[CustomCodeNode, sp.MatrixBase]: + return ( + CustomCodeNode("", [], []), + sp.Identity(self.fe_space.num_dofs(geometry)), + ) class P1FunctionSpaceImpl(FunctionSpaceImpl): def __init__( diff --git a/hog/operator_generation/indexing.py b/hog/operator_generation/indexing.py index e33704ecc6112ec192671029c69e88ed92e66095..91620ad4bd8f2a53f60e2831b3bda3d507bb7d8a 100644 --- a/hog/operator_generation/indexing.py +++ b/hog/operator_generation/indexing.py @@ -150,7 +150,7 @@ def generalized_macro_cell_index( def num_microvertices_per_face_from_width(width: int) -> int: """Computes the number of microvertices in a refined macro triangle. width depends on the level and quantifies the amount of primitives in one direction of the refined triangle.""" - return (width * (width + 1)) >> 1 + return int_div((width * (width + 1)), 2) def num_microvertices_per_cell_from_width(width: int) -> int: @@ -197,20 +197,20 @@ def num_faces_per_row_by_type( def num_cells_per_row_by_type( - level: int, cellType: Union[None, EdgeType, FaceType, CellType] + level: int, cellType: Union[None, EdgeType, FaceType, CellType], num_microedges_per_edge: sp.Symbol ) -> int: if cellType == CellType.WHITE_UP: - return num_microedges_per_edge(level) + return num_microedges_per_edge elif cellType == CellType.GREEN_UP: - return num_microedges_per_edge(level) - 1 + return num_microedges_per_edge - 1 elif cellType == CellType.BLUE_UP: - return num_microedges_per_edge(level) - 1 + return num_microedges_per_edge - 1 elif cellType == CellType.WHITE_DOWN: - return num_microedges_per_edge(level) - 2 + return num_microedges_per_edge - 2 elif cellType == CellType.BLUE_DOWN: - return num_microedges_per_edge(level) - 1 + return num_microedges_per_edge - 1 elif cellType == CellType.GREEN_DOWN: - return num_microedges_per_edge(level) - 1 + return num_microedges_per_edge - 1 else: raise HOGException(f"Unexpected cell type: {cellType}") @@ -221,9 +221,9 @@ def num_micro_faces_per_macro_face(level: int, faceType: FaceType) -> int: ) -def num_micro_cells_per_macro_cell(level: int, cellType: CellType) -> int: +def num_micro_cells_per_macro_cell(level: int, cellType: CellType, num_microedges_per_edge: sp.Symbol) -> int: return num_microvertices_per_cell_from_width( - num_cells_per_row_by_type(level, cellType) + num_cells_per_row_by_type(level, cellType, num_microedges_per_edge) ) @@ -254,16 +254,16 @@ def facedof_index( level: int, index: Tuple[int, int, int], faceType: Union[None, EdgeType, FaceType, CellType], + num_microfaces_per_face: sp.Symbol, + num_microedges_per_edge: sp.Symbol ) -> int: """Indexes triangles/faces. Used to compute offsets in volume dof indexing in 2D and AoS layout.""" - x, y, _ = index - width = num_faces_per_row_by_type(level, faceType) + x, y = index + # width = num_faces_per_row_by_type(level, faceType) if faceType == FaceType.GRAY: - return linear_macro_face_index(width, x, y) + return linear_macro_face_index(num_microedges_per_edge, x, y) elif faceType == FaceType.BLUE: - return num_micro_faces_per_macro_face( - level, FaceType.GRAY - ) + linear_macro_face_index(width, x, y) + return num_microvertices_per_face_from_width(num_microedges_per_edge) + linear_macro_face_index(num_microedges_per_edge - 1, x, y) else: raise HOGException(f"Unexpected face type: {faceType}") @@ -272,44 +272,45 @@ def celldof_index( level: int, index: Tuple[int, int, int], cellType: Union[None, EdgeType, FaceType, CellType], + num_microedges_per_edge: sp.Symbol, ) -> int: """Indexes cells/tetrahedra. Used to compute offsets in volume dof indexing in 3D and AoS layout.""" - x, y, z = index - width = num_cells_per_row_by_type(level, cellType) # gives expr(level) + x, y, z = index + width = num_cells_per_row_by_type(level, cellType, num_microedges_per_edge) # gives expr(level) if cellType == CellType.WHITE_UP: return linear_macro_cell_index(width, x, y, z) elif cellType == CellType.BLUE_UP: return num_micro_cells_per_macro_cell( # gives expr(level) - level, CellType.WHITE_UP + level, CellType.WHITE_UP, num_microedges_per_edge ) + linear_macro_cell_index(width, x, y, z) elif cellType == CellType.GREEN_UP: return ( - num_micro_cells_per_macro_cell(level, CellType.WHITE_UP) - + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP) + num_micro_cells_per_macro_cell(level, CellType.WHITE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP, num_microedges_per_edge) + linear_macro_cell_index(width, x, y, z) ) elif cellType == CellType.WHITE_DOWN: return ( - num_micro_cells_per_macro_cell(level, CellType.WHITE_UP) - + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP) - + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP) + num_micro_cells_per_macro_cell(level, CellType.WHITE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP, num_microedges_per_edge) + linear_macro_cell_index(width, x, y, z) ) elif cellType == CellType.BLUE_DOWN: return ( - num_micro_cells_per_macro_cell(level, CellType.WHITE_UP) - + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP) - + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP) - + num_micro_cells_per_macro_cell(level, CellType.WHITE_DOWN) + num_micro_cells_per_macro_cell(level, CellType.WHITE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.WHITE_DOWN, num_microedges_per_edge) + linear_macro_cell_index(width, x, y, z) ) elif cellType == CellType.GREEN_DOWN: return ( - num_micro_cells_per_macro_cell(level, CellType.WHITE_UP) - + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP) - + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP) - + num_micro_cells_per_macro_cell(level, CellType.WHITE_DOWN) - + num_micro_cells_per_macro_cell(level, CellType.BLUE_DOWN) + num_micro_cells_per_macro_cell(level, CellType.WHITE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.BLUE_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.GREEN_UP, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.WHITE_DOWN, num_microedges_per_edge) + + num_micro_cells_per_macro_cell(level, CellType.BLUE_DOWN, num_microedges_per_edge) + linear_macro_cell_index(width, x, y, z) ) else: @@ -326,6 +327,7 @@ class IndexingInfo: self.micro_edges_per_macro_edge = TypedSymbol("micro_edges_per_macro_edge", int) self.num_microfaces_per_face = TypedSymbol("num_microfaces_per_face", int) self.num_microcells_per_cell = TypedSymbol("num_microcells_per_cell", int) + # self.num_microedges_per_edge = TypedSymbol("num_microedges_per_edge", int) self.micro_edges_per_macro_edge_float = sp.Symbol( "micro_edges_per_macro_edge_float" ) @@ -445,7 +447,7 @@ class DoFIndex: numMicroVolumes = indexing_info.num_microfaces_per_face microVolume = facedof_index( - indexing_info.level, self.primitive_index, self.dof_sub_type + indexing_info.level, self.primitive_index, self.dof_sub_type, indexing_info.num_microfaces_per_face, indexing_info.micro_edges_per_macro_edge ) if self.mem_layout == VolumeDoFMemoryLayout.SoA: @@ -461,7 +463,7 @@ class DoFIndex: numMicroVolumes = indexing_info.num_microcells_per_cell microVolume = celldof_index( - indexing_info.level, self.primitive_index, self.dof_sub_type + indexing_info.level, self.primitive_index, self.dof_sub_type, indexing_info.micro_edges_per_macro_edge ) if self.mem_layout == VolumeDoFMemoryLayout.SoA: diff --git a/hog/operator_generation/operators.py b/hog/operator_generation/operators.py index 18dbfede7ce05b0f9b57714e3c3203fd8f7a8918..b137074b28e9c55a3edc791822939857d48b306a 100644 --- a/hog/operator_generation/operators.py +++ b/hog/operator_generation/operators.py @@ -274,6 +274,7 @@ class HyTeGElementwiseOperator: "hyteg/types/types.hpp", } + VAR_NAME_MICRO_FACES_PER_MACRO_FACE = "num_microfaces_per_face" VAR_NAME_MICRO_EDGES_PER_MACRO_EDGE = "micro_edges_per_macro_edge" VAR_NAME_MICRO_EDGES_PER_MACRO_EDGE_FLOAT = "micro_edges_per_macro_edge_float" @@ -1615,6 +1616,7 @@ class HyTeGElementwiseOperator: # Setting up required scalar parameters. scalar_parameter_setup = ( f"const auto {self.VAR_NAME_MICRO_EDGES_PER_MACRO_EDGE} = (int64_t) levelinfo::num_microedges_per_edge( level );\n" + f"const auto {self.VAR_NAME_MICRO_FACES_PER_MACRO_FACE} = (int64_t) levelinfo::num_microfaces_per_face( level );\n" f"const auto {self.VAR_NAME_MICRO_EDGES_PER_MACRO_EDGE_FLOAT} = ({self._type_descriptor.pystencils_type}) levelinfo::num_microedges_per_edge( level );\n" ) scalar_parameter_setup += "\n".join(