From 2a61063dbeb50b1d5f37d8055c3afb3acb6acf46 Mon Sep 17 00:00:00 2001
From: Michael Kuron <mkuron@icp.uni-stuttgart.de>
Date: Tue, 21 Apr 2020 16:22:32 +0200
Subject: [PATCH] pystencils_walberla: staggered boundary generation

---
 python/pystencils_walberla/__init__.py |   3 +-
 python/pystencils_walberla/boundary.py | 108 ++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/python/pystencils_walberla/__init__.py b/python/pystencils_walberla/__init__.py
index 767581a75..88eb440a6 100644
--- a/python/pystencils_walberla/__init__.py
+++ b/python/pystencils_walberla/__init__.py
@@ -1,3 +1,4 @@
+from .boundary import generate_staggered_boundary, generate_staggered_flux_boundary
 from .cmake_integration import CodeGeneration
 from .codegen import (
     generate_pack_info, generate_pack_info_for_field, generate_pack_info_from_kernel,
@@ -5,4 +6,4 @@ from .codegen import (
 
 __all__ = ['CodeGeneration',
            'generate_sweep', 'generate_pack_info_from_kernel', 'generate_pack_info_for_field', 'generate_pack_info',
-           'generate_mpidtype_info_from_kernel']
+           'generate_mpidtype_info_from_kernel', 'generate_staggered_boundary', 'generate_staggered_flux_boundary']
diff --git a/python/pystencils_walberla/boundary.py b/python/pystencils_walberla/boundary.py
index 79b7ed28a..00346cfd6 100644
--- a/python/pystencils_walberla/boundary.py
+++ b/python/pystencils_walberla/boundary.py
@@ -1,16 +1,120 @@
 import numpy as np
 from jinja2 import Environment, PackageLoader, StrictUndefined
 
-from pystencils_walberla.codegen import KernelInfo
 from pystencils import Field, FieldType
+from pystencils.boundaries.boundaryhandling import create_boundary_kernel
 from pystencils.boundaries.createindexlist import (
     boundary_index_array_coordinate_names, direction_member_name,
     numpy_data_type_for_boundary_object)
 from pystencils.data_types import TypedSymbol, create_type
-from pystencils_walberla.codegen import default_create_kernel_parameters
+from pystencils_walberla.codegen import KernelInfo
 from pystencils_walberla.jinja_filters import add_pystencils_filters_to_jinja_env
 
 
+def generate_staggered_boundary(generation_context, class_name, boundary_object,
+                                dim, neighbor_stencil, index_shape, target='cpu'):
+    struct_name = "IndexInfo"
+    boundary_object.name = class_name
+
+    index_struct_dtype = numpy_data_type_for_boundary_object(boundary_object, dim)
+
+    staggered_field = Field.create_generic('field', dim,
+                                           np.float64 if generation_context.double_accuracy else np.float32,
+                                           index_dimensions=len(index_shape), layout='c', index_shape=index_shape,
+                                           field_type=FieldType.STAGGERED)
+
+    index_field = Field('indexVector', FieldType.INDEXED, index_struct_dtype, layout=[0],
+                        shape=(TypedSymbol("indexVectorSize", create_type(np.int64)), 1), strides=(1, 1))
+
+    kernel = create_boundary_kernel(staggered_field, index_field, neighbor_stencil, boundary_object, target=target,
+                                    openmp=generation_context.openmp)
+    kernel.function_name = "boundary_" + boundary_object.name
+
+    # waLBerla is a 3D framework. Therefore, a zero for the z index has to be added if we work in 2D
+    if dim == 2:
+        stencil = ()
+        for d in neighbor_stencil:
+            d = d + (0,)
+            stencil = stencil + (d,)
+    else:
+        stencil = neighbor_stencil
+
+    stencil_info = [(i, ", ".join([str(e) for e in d])) for i, d in enumerate(stencil)]
+
+    context = {
+        'class_name': boundary_object.name,
+        'StructName': struct_name,
+        'StructDeclaration': struct_from_numpy_dtype(struct_name, index_struct_dtype),
+        'kernel': KernelInfo(kernel),
+        'stencil_info': stencil_info,
+        'dim': dim,
+        'target': target,
+        'namespace': 'pystencils',
+    }
+
+    env = Environment(loader=PackageLoader('pystencils_walberla'), undefined=StrictUndefined)
+    add_pystencils_filters_to_jinja_env(env)
+
+    header = env.get_template('Boundary.tmpl.h').render(**context)
+    source = env.get_template('Boundary.tmpl.cpp').render(**context)
+
+    source_extension = "cpp" if target == "cpu" else "cu"
+    generation_context.write_file("{}.h".format(class_name), header)
+    generation_context.write_file("{}.{}".format(class_name, source_extension), source)
+
+
+def generate_staggered_flux_boundary(generation_context, class_name, boundary_object,
+                                     dim, neighbor_stencil, index_shape, target='cpu'):
+    struct_name = "IndexInfo"
+    boundary_object.name = class_name
+
+    index_struct_dtype = numpy_data_type_for_boundary_object(boundary_object, dim)
+
+    staggered_field = Field.create_generic('flux', dim,
+                                           np.float64 if generation_context.double_accuracy else np.float32,
+                                           index_dimensions=len(index_shape), layout='c', index_shape=index_shape,
+                                           field_type=FieldType.STAGGERED_FLUX)
+
+    index_field = Field('indexVector', FieldType.INDEXED, index_struct_dtype, layout=[0],
+                        shape=(TypedSymbol("indexVectorSize", create_type(np.int64)), 1), strides=(1, 1))
+
+    kernel = create_boundary_kernel(staggered_field, index_field, neighbor_stencil, boundary_object, target=target,
+                                    openmp=generation_context.openmp)
+    kernel.function_name = "boundary_" + boundary_object.name
+
+    # waLBerla is a 3D framework. Therefore, a zero for the z index has to be added if we work in 2D
+    if dim == 2:
+        stencil = ()
+        for d in neighbor_stencil:
+            d = d + (0,)
+            stencil = stencil + (d,)
+    else:
+        stencil = neighbor_stencil
+
+    stencil_info = [(i, ", ".join([str(e) for e in d])) for i, d in enumerate(stencil)]
+
+    context = {
+        'class_name': boundary_object.name,
+        'StructName': struct_name,
+        'StructDeclaration': struct_from_numpy_dtype(struct_name, index_struct_dtype),
+        'kernel': KernelInfo(kernel),
+        'stencil_info': stencil_info,
+        'dim': dim,
+        'target': target,
+        'namespace': 'pystencils',
+    }
+
+    env = Environment(loader=PackageLoader('pystencils_walberla'), undefined=StrictUndefined)
+    add_pystencils_filters_to_jinja_env(env)
+
+    header = env.get_template('Boundary.tmpl.h').render(**context)
+    source = env.get_template('Boundary.tmpl.cpp').render(**context)
+
+    source_extension = "cpp" if target == "cpu" else "cu"
+    generation_context.write_file("{}.h".format(class_name), header)
+    generation_context.write_file("{}.{}".format(class_name, source_extension), source)
+
+
 def struct_from_numpy_dtype(struct_name, numpy_dtype):
     result = "struct %s { \n" % (struct_name,)
 
-- 
GitLab