diff --git a/pystencils_walberla/codegen.py b/pystencils_walberla/codegen.py index 5a2df56e1fe078897a10bdb41b7015b824b31220..60698babc3829304313b5446bc5821380e3d1e2e 100644 --- a/pystencils_walberla/codegen.py +++ b/pystencils_walberla/codegen.py @@ -3,7 +3,7 @@ from collections import OrderedDict, defaultdict from itertools import product from typing import Dict, Sequence, Tuple, Optional -from pystencils import create_staggered_kernel, Field, create_kernel, Assignment, FieldType +from pystencils import create_staggered_kernel, Field, create_kernel, Assignment, FieldType, AssignmentCollection from pystencils.backends.cbackend import get_headers from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets from pystencils.stencil import offset_to_direction_string, inverse_direction @@ -120,7 +120,7 @@ def generate_pack_info_for_field(generation_context, class_name: str, field: Fie def generate_pack_info_from_kernel(generation_context, class_name: str, assignments: Sequence[Assignment], - **create_kernel_params): + kind='pull', **create_kernel_params): """Generates a waLBerla GPU PackInfo from a (pull) kernel. Args: @@ -128,16 +128,37 @@ def generate_pack_info_from_kernel(generation_context, class_name: str, assignme class_name: name of the generated class assignments: list of assignments from the compute kernel - generates PackInfo for "pull" part only i.e. the kernel is expected to only write to the center + kind: **create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel` """ + assert kind in ('push', 'pull') reads = set() + writes = set() + + if isinstance(assignments, AssignmentCollection): + assignments = assignments.all_assignments + for a in assignments: reads.update(a.rhs.atoms(Field.Access)) + writes.update(a.lhs.atoms(Field.Access)) spec = defaultdict(set) - for fa in reads: - assert all(abs(e) <= 1 for e in fa.offsets) - for comm_dir in comm_directions(fa.offsets): - spec[(comm_dir,)].add(fa.field.center(*fa.index)) + if kind == 'pull': + for fa in reads: + assert all(abs(e) <= 1 for e in fa.offsets) + if all(offset == 0 for offset in fa.offsets): + continue + comm_direction = inverse_direction(fa.offsets) + for comm_dir in comm_directions(comm_direction): + spec[(comm_dir,)].add(fa.field.center(*fa.index)) + elif kind == 'push': + for fa in writes: + assert all(abs(e) <= 1 for e in fa.offsets) + if all(offset == 0 for offset in fa.offsets): + continue + for comm_dir in comm_directions(fa.offsets): + spec[(comm_dir,)].add(fa) + else: + raise ValueError("Invalid 'kind' parameter") return generate_pack_info(generation_context, class_name, spec, **create_kernel_params) @@ -168,14 +189,17 @@ def generate_pack_info(generation_context, class_name: str, fields_accessed = set() for terms in directions_to_pack_terms.values(): for term in terms: - assert isinstance(term, Field.Access) and all(e == 0 for e in term.offsets) + assert isinstance(term, Field.Access) #and all(e == 0 for e in term.offsets) fields_accessed.add(term) field_names = {fa.field.name for fa in fields_accessed} data_types = {fa.field.dtype for fa in fields_accessed} + if len(data_types) == 0: + raise ValueError("No fields to pack!") if len(data_types) != 1: - raise NotImplementedError("Fields of different data types are used - this is not supported") + err_detail = "\n".join(" - {} [{}]".format(f.name, f.dtype) for f in fields_accessed) + raise NotImplementedError("Fields of different data types are used - this is not supported.\n" + err_detail) dtype = data_types.pop() pack_kernels = OrderedDict() @@ -191,18 +215,17 @@ def generate_pack_info(generation_context, class_name: str, dtype=dtype.numpy_dtype, index_shape=(len(terms),)) direction_strings = tuple(offset_to_direction_string(d) for d in direction_set) - inv_direction_string = tuple(offset_to_direction_string(inverse_direction(d)) for d in direction_set) all_accesses.update(terms) - pack_ast = create_kernel([Assignment(buffer(i), term) for i, term in enumerate(terms)], - **create_kernel_params) + pack_assignments = [Assignment(buffer(i), term) for i, term in enumerate(terms)] + pack_ast = create_kernel(pack_assignments, **create_kernel_params, ghost_layers=0) pack_ast.function_name = 'pack_{}'.format("_".join(direction_strings)) - unpack_ast = create_kernel([Assignment(term, buffer(i)) for i, term in enumerate(terms)], - **create_kernel_params) - unpack_ast.function_name = 'unpack_{}'.format("_".join(inv_direction_string)) + unpack_assignments = [Assignment(term, buffer(i)) for i, term in enumerate(terms)] + unpack_ast = create_kernel(unpack_assignments, **create_kernel_params, ghost_layers=0) + unpack_ast.function_name = 'unpack_{}'.format("_".join(direction_strings)) pack_kernels[direction_strings] = KernelInfo(pack_ast) - unpack_kernels[inv_direction_string] = KernelInfo(unpack_ast) + unpack_kernels[direction_strings] = KernelInfo(unpack_ast) elements_per_cell[direction_strings] = len(terms) fused_kernel = create_kernel([Assignment(buffer.center, t) for t in all_accesses], **create_kernel_params) @@ -267,7 +290,6 @@ def default_create_kernel_parameters(generation_context, params): def comm_directions(direction): - direction = inverse_direction(direction) yield direction for i in range(len(direction)): if direction[i] != 0: diff --git a/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp b/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp index 6e349d0fd0d04a687005040ff182c004c0aebdc6..d2624b18800f4ee4f8f6d16833cc0f327224ea02 100644 --- a/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp +++ b/pystencils_walberla/templates/GpuPackInfo.tmpl.cpp @@ -62,8 +62,9 @@ void {{class_name}}::unpack(Direction dir, unsigned char * byte_buffer, IBlock * {{fused_kernel|generate_block_data_to_field_extraction(parameters_to_ignore=['buffer'])|indent(4)}} CellInterval ci; {{field_name}}->getGhostRegion(dir, ci, 1, false); + auto communciationDirection = stencil::inverseDir[dir]; - switch( dir ) + switch( communciationDirection ) { {%- for direction_set, kernel in unpack_kernels.items() %} {%- for dir in direction_set %}