Commit 577f7797 authored by Frederik Hennig's avatar Frederik Hennig
Browse files

Refactoring + First steps toward merging boundary implementations

parent ac69e4f1
Pipeline #27450 passed with stage
in 29 minutes and 41 seconds
from .boundaryindexing import AdvancedStreamingBoundaryIndexing from .indexing import BetweenTimestepsIndexing
from .boundaryconditions import FlexibleBoundary, FlexibleNoSlip from .boundaryconditions import FlexibleBoundary, FlexibleNoSlip
from .boundaryhandling import FlexibleLBMBoundaryHandling, \ from .boundaryhandling import FlexibleLBMBoundaryHandling, \
create_advanced_streaming_boundary_kernel create_advanced_streaming_boundary_kernel
from .communication import get_communication_slices, PeriodicityHandling from .communication import get_communication_slices, PeriodicityHandling
from .utility import Timestep, get_accessor from .utility import Timestep, get_accessor
__all__ = ['AdvancedStreamingBoundaryIndexing', 'FlexibleBoundary', __all__ = ['BetweenTimestepsIndexing', 'FlexibleBoundary',
'FlexibleNoSlip', 'create_advanced_streaming_boundary_kernel', 'FlexibleNoSlip', 'create_advanced_streaming_boundary_kernel',
'FlexibleLBMBoundaryHandling', 'FlexibleLBMBoundaryHandling',
'get_communication_slices', 'PeriodicityHandling', 'get_communication_slices', 'PeriodicityHandling',
......
from lbmpy.advanced_streaming.boundaryindexing import AdvancedStreamingBoundaryIndexing import numpy as np
from lbmpy.advanced_streaming.utility import Timestep from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing
from lbmpy.advanced_streaming.utility import is_inplace, Timestep, AccessPdfValues
from pystencils import Field, Assignment, create_indexed_kernel from pystencils import Field, Assignment, create_indexed_kernel
from pystencils.boundaries import BoundaryHandling from pystencils.boundaries import BoundaryHandling
from pystencils.boundaries.createindexlist import numpy_data_type_for_boundary_object from pystencils.boundaries.createindexlist import numpy_data_type_for_boundary_object
...@@ -16,13 +17,11 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling): ...@@ -16,13 +17,11 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling):
name="boundary_handling", flag_interface=None, target='cpu', openmp=True): name="boundary_handling", flag_interface=None, target='cpu', openmp=True):
self._lb_method = lb_method self._lb_method = lb_method
self._streaming_pattern = streaming_pattern self._streaming_pattern = streaming_pattern
self._two_fields_kernel = streaming_pattern in ['pull', 'push'] self._inplace = is_inplace(streaming_pattern)
self._prev_timestep = None self._prev_timestep = None
super(FlexibleLBMBoundaryHandling, self).__init__(data_handling, pdf_field_name, lb_method.stencil, super(FlexibleLBMBoundaryHandling, self).__init__(data_handling, pdf_field_name, lb_method.stencil,
name, flag_interface, target, openmp) name, flag_interface, target, openmp)
# TODO: Force On Boundary
# ------------------------- Overridden methods of pystencils.BoundaryHandling ------------------------- # ------------------------- Overridden methods of pystencils.BoundaryHandling -------------------------
@property @property
...@@ -38,10 +37,10 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling): ...@@ -38,10 +37,10 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling):
raise NotImplementedError("Adding to fixed loop is not supported by FlexibleLBMBoundaryHandling") raise NotImplementedError("Adding to fixed loop is not supported by FlexibleLBMBoundaryHandling")
def _add_boundary(self, boundary_obj, flag=None): def _add_boundary(self, boundary_obj, flag=None):
if self._two_fields_kernel: if self._inplace:
return super(FlexibleLBMBoundaryHandling, self)._add_boundary(boundary_obj, flag)
else:
return self._add_flexible_boundary(boundary_obj, flag) return self._add_flexible_boundary(boundary_obj, flag)
else:
return super(FlexibleLBMBoundaryHandling, self)._add_boundary(boundary_obj, flag)
def _add_flexible_boundary(self, boundary_obj, flag=None): def _add_flexible_boundary(self, boundary_obj, flag=None):
if boundary_obj not in self._boundary_object_to_boundary_info: if boundary_obj not in self._boundary_object_to_boundary_info:
...@@ -53,7 +52,7 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling): ...@@ -53,7 +52,7 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling):
self._data_handling.fields[self._field_name], sym_index_field, boundary_obj, Timestep.ODD).compile()] self._data_handling.fields[self._field_name], sym_index_field, boundary_obj, Timestep.ODD).compile()]
if flag is None: if flag is None:
flag = self.flag_interface.reserve_next_flag() flag = self.flag_interface.reserve_next_flag()
boundary_info = self.FlexibleBoundaryInfo(self, boundary_obj, flag, kernels) boundary_info = self.InplaceStreamingBoundaryInfo(self, boundary_obj, flag, kernels)
self._boundary_object_to_boundary_info[boundary_obj] = boundary_info self._boundary_object_to_boundary_info[boundary_obj] = boundary_info
return self._boundary_object_to_boundary_info[boundary_obj].flag return self._boundary_object_to_boundary_info[boundary_obj].flag
...@@ -63,14 +62,14 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling): ...@@ -63,14 +62,14 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling):
prev_timestep=prev_timestep, streaming_pattern=self._streaming_pattern, prev_timestep=prev_timestep, streaming_pattern=self._streaming_pattern,
target=self._target, openmp=self._openmp) target=self._target, openmp=self._openmp)
class FlexibleBoundaryInfo(object): class InplaceStreamingBoundaryInfo(object):
@property @property
def kernel(self): def kernel(self):
prev_timestep = self._boundary_handling.prev_timestep prev_timestep = self._boundary_handling.prev_timestep
if prev_timestep is None: if prev_timestep is None:
raise Exception( raise Exception(
"The flexible boundary kernel property was accessed while " "The boundary kernel property was accessed while "
+ "there was no boundary handling in progress.") + "there was no boundary handling in progress.")
return self._kernels[prev_timestep] return self._kernels[prev_timestep]
...@@ -79,6 +78,41 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling): ...@@ -79,6 +78,41 @@ class FlexibleLBMBoundaryHandling(BoundaryHandling):
self.boundary_object = boundary_obj self.boundary_object = boundary_obj
self.flag = flag self.flag = flag
self._kernels = kernels self._kernels = kernels
# end class InplaceStreamingBoundaryInfo
# ------------------------------ Force On Boundary ------------------------------------------------------------
def force_on_boundary(self, boundary_obj, prev_timestep=Timestep.BOTH):
from lbmpy.advanced_streaming import FlexibleNoSlip
if isinstance(boundary_obj, FlexibleNoSlip):
return self._force_on_no_slip(boundary_obj, prev_timestep)
else:
self.__call__()
return self._force_on_boundary(boundary_obj, prev_timestep)
def _force_on_no_slip(self, boundary_obj, prev_timestep):
dh = self._data_handling
ff_ghost_layers = dh.ghost_layers_of_field(self.flag_interface.flag_field_name)
method = self._lb_method
stencil = np.array(method.stencil)
result = np.zeros(self.dim)
for b in dh.iterate(ghost_layers=ff_ghost_layers):
obj_to_ind_list = b[self._index_array_name].boundary_object_to_index_list
pdf_array = b[self._field_name]
if boundary_obj in obj_to_ind_list:
ind_arr = obj_to_ind_list[boundary_obj]
acc = AccessPdfValues(dh.fields[self._field_name], self._lb_method.stencil,
streaming_pattern=self._streaming_pattern, timestep=prev_timestep,
streaming_dir='out')
values = 2 * acc.collect_from_index_list(pdf_array, ind_arr)
forces = stencil[ind_arr['dir']] * values[:, np.newaxis]
result += forces.sum(axis=0)
return dh.reduce_float_sequence(list(result), 'sum')
def _force_on_boundary(self, boundary_obj, prev_timestep):
raise NotImplementedError()
# end class FlexibleLBMBoundaryHandling # end class FlexibleLBMBoundaryHandling
...@@ -88,7 +122,7 @@ def create_advanced_streaming_boundary_kernel(pdf_field, index_field, lb_method, ...@@ -88,7 +122,7 @@ def create_advanced_streaming_boundary_kernel(pdf_field, index_field, lb_method,
target='cpu', openmp=True): target='cpu', openmp=True):
index_dtype = index_field.dtype.numpy_dtype.fields['dir'][0] index_dtype = index_field.dtype.numpy_dtype.fields['dir'][0]
offsets_dtype = index_field.dtype.numpy_dtype.fields['x'][0] offsets_dtype = index_field.dtype.numpy_dtype.fields['x'][0]
indexing = AdvancedStreamingBoundaryIndexing( indexing = BetweenTimestepsIndexing(
pdf_field, lb_method.stencil, prev_timestep, streaming_pattern, index_dtype, offsets_dtype) pdf_field, lb_method.stencil, prev_timestep, streaming_pattern, index_dtype, offsets_dtype)
f_out, f_in = indexing.proxy_fields f_out, f_in = indexing.proxy_fields
......
...@@ -161,7 +161,7 @@ class PeriodicityHandling: ...@@ -161,7 +161,7 @@ class PeriodicityHandling:
to be about four times faster. to be about four times faster.
""" """
if not isinstance(data_handling, SerialDataHandling): if not isinstance(data_handling, SerialDataHandling):
raise ValueError('Only single node data handling is supported!') raise ValueError('Only serial data handling is supported!')
assert target in ['cpu', 'gpu', 'opencl'] assert target in ['cpu', 'gpu', 'opencl']
......
...@@ -10,11 +10,11 @@ from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is ...@@ -10,11 +10,11 @@ from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is
from itertools import product from itertools import product
class AdvancedStreamingBoundaryIndexing: class BetweenTimestepsIndexing:
# ======================================= # ==============================================
# Symbols for usage in boundaries # Symbols for usage in kernel definitions
# ======================================= # ==============================================
@property @property
def proxy_fields(self): def proxy_fields(self):
...@@ -154,7 +154,7 @@ class AdvancedStreamingBoundaryIndexing: ...@@ -154,7 +154,7 @@ class AdvancedStreamingBoundaryIndexing:
return trivials return trivials
def create_code_node(self): def create_code_node(self):
return AdvancedStreamingBoundaryIndexing.TranslationArraysNode(self) return BetweenTimestepsIndexing.TranslationArraysNode(self)
class TranslationArraysNode(CustomCodeNode): class TranslationArraysNode(CustomCodeNode):
...@@ -176,16 +176,16 @@ class AdvancedStreamingBoundaryIndexing: ...@@ -176,16 +176,16 @@ class AdvancedStreamingBoundaryIndexing:
acc_offsets = ", ".join([str(o) for o in offsets[d]]) acc_offsets = ", ".join([str(o) for o in offsets[d]])
code += self._array_pattern(indexing._offsets_dtype, arrsymb.name, acc_offsets) code += self._array_pattern(indexing._offsets_dtype, arrsymb.name, acc_offsets)
super(AdvancedStreamingBoundaryIndexing.TranslationArraysNode, self).__init__( super(BetweenTimestepsIndexing.TranslationArraysNode, self).__init__(
code, symbols_read=set(), symbols_defined=symbols_defined) code, symbols_read=set(), symbols_defined=symbols_defined)
def _array_pattern(self, dtype, name, content): def _array_pattern(self, dtype, name, content):
return f"const {str(dtype)} {name} [] = {{ {content} }}; \n" return f"const {str(dtype)} {name} [] = {{ {content} }}; \n"
def __str__(self): def __str__(self):
return "Boundary Access Translation Arrays" return "Variable PDF Access Translation Arrays"
def __repr__(self): def __repr__(self):
return "Boundary Access Translation Arrays" return "Variable PDF Access Translation Arrays"
# end class AdvancedStreamingIndexing # end class AdvancedStreamingIndexing
...@@ -6,6 +6,7 @@ from lbmpy.fieldaccess import PdfFieldAccessor, \ ...@@ -6,6 +6,7 @@ from lbmpy.fieldaccess import PdfFieldAccessor, \
EsoTwistEvenTimeStepAccessor, \ EsoTwistEvenTimeStepAccessor, \
EsoTwistOddTimeStepAccessor EsoTwistOddTimeStepAccessor
import numpy as np
import pystencils as ps import pystencils as ps
from enum import IntEnum from enum import IntEnum
...@@ -79,20 +80,33 @@ class AccessPdfValues: ...@@ -79,20 +80,33 @@ class AccessPdfValues:
"""Allows to access values from a PDF array correctly depending on """Allows to access values from a PDF array correctly depending on
the streaming pattern.""" the streaming pattern."""
def __init__(self, pdf_field, stencil, streaming_pattern='pull', timestep=Timestep.BOTH, accessor=None): def __init__(self, pdf_field, stencil,
streaming_pattern='pull', timestep=Timestep.BOTH, streaming_dir='out',
accessor=None):
if streaming_dir not in ['in', 'out']:
raise ValueError('Invalid streaming direction.', streaming_dir)
if accessor is None: if accessor is None:
accessor = get_accessor(streaming_pattern, timestep) accessor = get_accessor(streaming_pattern, timestep)
self.read_accs = accessor.read(pdf_field, stencil) self.accs = accessor.read(pdf_field, stencil) \
self.write_accs = accessor.write(pdf_field, stencil) if streaming_dir == 'in' \
else accessor.write(pdf_field, stencil)
def write_pdf(self, pdf_arr, pos, d, value): def write_pdf(self, pdf_arr, pos, d, value):
offsets = self.write_accs[d].offsets offsets = numeric_offsets(self.accs[d])
pos = tuple(p + o for p, o in zip(pos, offsets)) pos = tuple(p + o for p, o in zip(pos, offsets))
i = self.write_accs[d].index[0] i = numeric_index(self.accs[d])[0]
pdf_arr[pos + (i,)] = value pdf_arr[pos + (i,)] = value
def read_pdf(self, pdf_arr, pos, d): def read_pdf(self, pdf_arr, pos, d):
offsets = self.read_accs[d].offsets offsets = numeric_offsets(self.accs[d])
pos = tuple(p + o for p, o in zip(pos, offsets)) pos = tuple(p + o for p, o in zip(pos, offsets))
i = self.read_accs[d].index[0] i = numeric_index(self.accs[d])[0]
return pdf_arr[pos + (i,)] return pdf_arr[pos + (i,)]
def collect_from_index_list(self, pdf_arr, index_list):
def to_coordinate_tuple(idx):
return tuple(idx[v] for v in ('x', 'y', 'z')[:len(idx) - 1])
gen = [self.read_pdf(pdf_arr, to_coordinate_tuple(idx), idx['dir']) for idx in index_list]
return np.array(gen)
...@@ -29,8 +29,8 @@ def test_advanced_streaming_noslip_single_cell(stencil, streaming_pattern, prev_ ...@@ -29,8 +29,8 @@ def test_advanced_streaming_noslip_single_cell(stencil, streaming_pattern, prev_
dim = len(stencil[0]) dim = len(stencil[0])
pdf_field = ps.fields(f'pdfs({q}): [{dim}D]') pdf_field = ps.fields(f'pdfs({q}): [{dim}D]')
prev_pdf_access = AccessPdfValues(pdf_field, stencil, streaming_pattern, prev_timestep) prev_pdf_access = AccessPdfValues(pdf_field, stencil, streaming_pattern, prev_timestep, 'out')
next_pdf_access = AccessPdfValues(pdf_field, stencil, streaming_pattern, prev_timestep.next()) next_pdf_access = AccessPdfValues(pdf_field, stencil, streaming_pattern, prev_timestep.next(), 'in')
pdfs = np.zeros((3,) * dim + (q,)) pdfs = np.zeros((3,) * dim + (q,))
pos = (1,) * dim pos = (1,) * dim
......
...@@ -22,13 +22,15 @@ targets = ['cpu'] ...@@ -22,13 +22,15 @@ targets = ['cpu']
try: try:
import pycuda.autoinit import pycuda.autoinit
targets += ['gpu'] targets += ['gpu']
except ImportError: except Exception:
pass pass
try: try:
import pystencils.opencl.autoinit import pystencils.opencl.autoinit
targets += ['opencl'] from pystencils.opencl.opencljit import get_global_cl_queue
except ImportError: if get_global_cl_queue() is not None:
targets += ['opencl']
except Exception:
pass pass
...@@ -38,7 +40,6 @@ except ImportError: ...@@ -38,7 +40,6 @@ except ImportError:
def test_fully_periodic_flow(target, stencil, streaming_pattern): def test_fully_periodic_flow(target, stencil, streaming_pattern):
if target == 'opencl': if target == 'opencl':
from pystencils.opencl.opencljit import get_global_cl_queue
opencl_queue = get_global_cl_queue() opencl_queue = get_global_cl_queue()
else: else:
opencl_queue = None opencl_queue = None
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment