Commit b5ac8c01 authored by Frederik Hennig's avatar Frederik Hennig
Browse files

Integrated exotic boundaries

parent dd1cbd09
This diff is collapsed.
...@@ -9,9 +9,11 @@ from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is ...@@ -9,9 +9,11 @@ from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is
from itertools import product from itertools import product
def _array_pattern(dtype, name, content): def _array_pattern(dtype, name, content):
return f"const {str(dtype)} {name} [] = {{ {','.join(str(c) for c in content)} }}; \n" return f"const {str(dtype)} {name} [] = {{ {','.join(str(c) for c in content)} }}; \n"
class BetweenTimestepsIndexing: class BetweenTimestepsIndexing:
# ============================================== # ==============================================
...@@ -187,12 +189,13 @@ class BetweenTimestepsIndexing: ...@@ -187,12 +189,13 @@ class BetweenTimestepsIndexing:
# end class AdvancedStreamingIndexing # end class AdvancedStreamingIndexing
class NeighbourOffsetArraysForStencil(CustomCodeNode):
class NeighbourOffsetArrays(CustomCodeNode):
@staticmethod @staticmethod
def symbolic_neighbour_offset_from_dir(dir_idx, dim): def symbolic_neighbour_offset(dir_idx, dim):
return tuple([sp.IndexedBase(symbol, shape=(1,))[dir_idx] return tuple([sp.IndexedBase(symbol, shape=(1,))[dir_idx]
for symbol in NeighbourOffsetArraysForStencil._offset_symbols(dim)]) for symbol in NeighbourOffsetArrays._offset_symbols(dim)])
@staticmethod @staticmethod
def _offset_symbols(dim): def _offset_symbols(dim):
...@@ -202,11 +205,11 @@ class NeighbourOffsetArraysForStencil(CustomCodeNode): ...@@ -202,11 +205,11 @@ class NeighbourOffsetArraysForStencil(CustomCodeNode):
offsets_dtype = create_type(offsets_dtype) offsets_dtype = create_type(offsets_dtype)
dim = len(stencil[0]) dim = len(stencil[0])
array_symbols = NeighbourOffsetArraysForStencil._offset_symbols(dim) array_symbols = NeighbourOffsetArrays._offset_symbols(dim)
code = "\n" code = "\n"
for i, arrsymb in enumerate(array_symbols): for i, arrsymb in enumerate(array_symbols):
code += _array_pattern(offsets_dtype, arrsymb.name, (d[i] for d in stencil)) code += _array_pattern(offsets_dtype, arrsymb.name, (d[i] for d in stencil))
offset_symbols = NeighbourOffsetArraysForStencil._offset_symbols(dim) offset_symbols = NeighbourOffsetArrays._offset_symbols(dim)
super(NeighbourOffsetArraysForStencil, self).__init__(code, symbols_read=set(), super(NeighbourOffsetArrays, self).__init__(code, symbols_read=set(),
symbols_defined=set(offset_symbols)) symbols_defined=set(offset_symbols))
\ No newline at end of file
...@@ -114,5 +114,3 @@ class AccessPdfValues: ...@@ -114,5 +114,3 @@ class AccessPdfValues:
return tuple(idx[v] for v in ('x', 'y', 'z')[:len(idx) - 1] + ('dir',)) return tuple(idx[v] for v in ('x', 'y', 'z')[:len(idx) - 1] + ('dir',))
return self.read_multiple(pdf_arr, (to_index_tuple(idx) for idx in index_list)) return self.read_multiple(pdf_arr, (to_index_tuple(idx) for idx in index_list))
...@@ -4,7 +4,7 @@ from lbmpy.boundaries.boundaryhandling import LbmWeightInfo ...@@ -4,7 +4,7 @@ from lbmpy.boundaries.boundaryhandling import LbmWeightInfo
from pystencils.data_types import create_type from pystencils.data_types import create_type
from pystencils.sympyextensions import get_symmetric_part from pystencils.sympyextensions import get_symmetric_part
from lbmpy.simplificationfactory import create_simplification_strategy from lbmpy.simplificationfactory import create_simplification_strategy
from lbmpy.advanced_streaming.indexing import NeighbourOffsetArraysForStencil from lbmpy.advanced_streaming.indexing import NeighbourOffsetArrays
class Boundary: class Boundary:
...@@ -127,18 +127,17 @@ class UBB(Boundary): ...@@ -127,18 +127,17 @@ class UBB(Boundary):
return self._velocity return self._velocity
def get_additional_code_nodes(self, lb_method): def get_additional_code_nodes(self, lb_method):
return [LbmWeightInfo(lb_method), NeighbourOffsetArraysForStencil(lb_method.stencil)] return [LbmWeightInfo(lb_method), NeighbourOffsetArrays(lb_method.stencil)]
def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field): def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
vel_from_idx_field = callable(self._velocity) vel_from_idx_field = callable(self._velocity)
vel = [index_field(f'vel_{i}') for i in range(self.dim)] if vel_from_idx_field else self._velocity vel = [index_field(f'vel_{i}') for i in range(self.dim)] if vel_from_idx_field else self._velocity
direction = dir_symbol direction = dir_symbol
assert self.dim == lb_method.dim, f"Dimension of UBB ({self.dim}) does not match dimension of method ({lb_method.dim})" assert self.dim == lb_method.dim, \
f"Dimension of UBB ({self.dim}) does not match dimension of method ({lb_method.dim})"
neighbor_offset = NeighbourOffsetArraysForStencil.symbolic_neighbour_offset_from_dir( neighbor_offset = NeighbourOffsetArrays.symbolic_neighbour_offset(direction, lb_method.dim)
direction, lb_method.dim)
velocity = tuple(v_i.get_shifted(*neighbor_offset) velocity = tuple(v_i.get_shifted(*neighbor_offset)
if isinstance(v_i, Field.Access) and not vel_from_idx_field if isinstance(v_i, Field.Access) and not vel_from_idx_field
...@@ -153,8 +152,8 @@ class UBB(Boundary): ...@@ -153,8 +152,8 @@ class UBB(Boundary):
c_s_sq = sp.Rational(1, 3) c_s_sq = sp.Rational(1, 3)
weight_of_direction = LbmWeightInfo.weight_of_direction weight_of_direction = LbmWeightInfo.weight_of_direction
vel_term = 2 / c_s_sq \ vel_term = 2 / c_s_sq \
* sum([d_i * v_i for d_i, v_i in zip(neighbor_offset, velocity)]) \ * sum([d_i * v_i for d_i, v_i in zip(neighbor_offset, velocity)]) \
* weight_of_direction(direction) * weight_of_direction(direction)
# Better alternative: in conserved value computation # Better alternative: in conserved value computation
# rename what is currently called density to "virtual_density" # rename what is currently called density to "virtual_density"
...@@ -174,17 +173,16 @@ class UBB(Boundary): ...@@ -174,17 +173,16 @@ class UBB(Boundary):
f_out(direction) - vel_term)] f_out(direction) - vel_term)]
# end class UBB # end class UBB
# TODO
class FixedDensity(Boundary): class FixedDensity(Boundary):
def __init__(self, density, name=None): def __init__(self, density, name=None):
raise NotImplementedError() # not yet operable
if name is None: if name is None:
name = "Fixed Density " + str(density) name = "Fixed Density " + str(density)
super(FixedDensity, self).__init__(name) super(FixedDensity, self).__init__(name)
self._density = density self._density = density
def __call__(self, pdf_field, direction_symbol, lb_method, **kwargs): def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
"""Boundary condition that fixes the density/pressure at the obstacle""" """Boundary condition that fixes the density/pressure at the obstacle"""
def remove_asymmetric_part_of_main_assignments(assignment_collection, degrees_of_freedom): def remove_asymmetric_part_of_main_assignments(assignment_collection, degrees_of_freedom):
...@@ -192,14 +190,11 @@ class FixedDensity(Boundary): ...@@ -192,14 +190,11 @@ class FixedDensity(Boundary):
for a in assignment_collection.main_assignments] for a in assignment_collection.main_assignments]
return assignment_collection.copy(new_main_assignments) return assignment_collection.copy(new_main_assignments)
neighbor = BoundaryOffsetInfo.offset_from_dir(direction_symbol, lb_method.dim)
inverse_dir = BoundaryOffsetInfo.inv_dir(direction_symbol)
cqc = lb_method.conserved_quantity_computation cqc = lb_method.conserved_quantity_computation
velocity = cqc.defined_symbols()['velocity'] velocity = cqc.defined_symbols()['velocity']
symmetric_eq = remove_asymmetric_part_of_main_assignments(lb_method.get_equilibrium(), symmetric_eq = remove_asymmetric_part_of_main_assignments(lb_method.get_equilibrium(),
degrees_of_freedom=velocity) degrees_of_freedom=velocity)
substitutions = {sym: pdf_field(i) for i, sym in enumerate(lb_method.pre_collision_pdf_symbols)} substitutions = {sym: f_out(i) for i, sym in enumerate(lb_method.pre_collision_pdf_symbols)}
symmetric_eq = symmetric_eq.new_with_substitutions(substitutions) symmetric_eq = symmetric_eq.new_with_substitutions(substitutions)
simplification = create_simplification_strategy(lb_method) simplification = create_simplification_strategy(lb_method)
...@@ -214,24 +209,27 @@ class FixedDensity(Boundary): ...@@ -214,24 +209,27 @@ class FixedDensity(Boundary):
assert density_eq.lhs == density_symbol assert density_eq.lhs == density_symbol
transformed_density = density_eq.rhs transformed_density = density_eq.rhs
conditions = [(eq_i.rhs, sp.Equality(direction_symbol, i)) conditions = [(eq_i.rhs, sp.Equality(dir_symbol, i))
for i, eq_i in enumerate(symmetric_eq.main_assignments)] + [(0, True)] for i, eq_i in enumerate(symmetric_eq.main_assignments)] + [(0, True)]
eq_component = sp.Piecewise(*conditions) eq_component = sp.Piecewise(*conditions)
subexpressions = [Assignment(eq.lhs, transformed_density if eq.lhs == density_symbol else eq.rhs) subexpressions = [Assignment(eq.lhs, transformed_density if eq.lhs == density_symbol else eq.rhs)
for eq in symmetric_eq.subexpressions] for eq in symmetric_eq.subexpressions]
return subexpressions + [Assignment(pdf_field[neighbor](inverse_dir), return subexpressions + [Assignment(f_in(inv_dir[dir_symbol]),
2 * eq_component - pdf_field(direction_symbol))] 2 * eq_component - f_out(dir_symbol))]
# end class FixedDensity
class NeumannByCopy(Boundary): class NeumannByCopy(Boundary):
def __call__(self, pdf_field, direction_symbol, lb_method, **kwargs):
raise NotImplementedError() # not yet operable def get_additional_code_nodes(self, lb_method):
neighbor = BoundaryOffsetInfo.offset_from_dir(direction_symbol, lb_method.dim) return [NeighbourOffsetArrays(lb_method.stencil)]
inverse_dir = BoundaryOffsetInfo.inv_dir(direction_symbol)
return [Assignment(pdf_field[neighbor](inverse_dir), pdf_field(inverse_dir)), def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
Assignment(pdf_field[neighbor](direction_symbol), pdf_field(direction_symbol))] neighbour_offset = NeighbourOffsetArrays.symbolic_neighbour_offset(dir_symbol, lb_method.dim)
return [Assignment(f_in(inv_dir[dir_symbol]), f_out(inv_dir[dir_symbol])),
Assignment(f_out[neighbour_offset](dir_symbol), f_out(dir_symbol))]
def __hash__(self): def __hash__(self):
# All boundaries of these class behave equal -> should also be equal # All boundaries of these class behave equal -> should also be equal
...@@ -239,19 +237,21 @@ class NeumannByCopy(Boundary): ...@@ -239,19 +237,21 @@ class NeumannByCopy(Boundary):
def __eq__(self, other): def __eq__(self, other):
return type(other) == NeumannByCopy return type(other) == NeumannByCopy
# end class NeumannByCopy
class StreamInConstant(Boundary): class StreamInConstant(Boundary):
def __init__(self, constant, name=None): def __init__(self, constant, name=None):
raise NotImplementedError() # not yet operable
super(StreamInConstant, self).__init__(name) super(StreamInConstant, self).__init__(name)
self._constant = constant self._constant = constant
def __call__(self, pdf_field, direction_symbol, lb_method, **kwargs): def get_additional_code_nodes(self, lb_method):
neighbor = BoundaryOffsetInfo.offset_from_dir(direction_symbol, lb_method.dim) return [NeighbourOffsetArrays(lb_method.stencil)]
inverse_dir = BoundaryOffsetInfo.inv_dir(direction_symbol)
return [Assignment(pdf_field[neighbor](inverse_dir), self._constant), def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
Assignment(pdf_field[neighbor](direction_symbol), self._constant)] neighbour_offset = NeighbourOffsetArrays.symbolic_neighbour_offset(dir_symbol, lb_method.dim)
return [Assignment(f_in(inv_dir[dir_symbol]), self._constant),
Assignment(f_out[neighbour_offset](dir_symbol), self._constant)]
def __hash__(self): def __hash__(self):
# All boundaries of these class behave equal -> should also be equal # All boundaries of these class behave equal -> should also be equal
...@@ -259,3 +259,4 @@ class StreamInConstant(Boundary): ...@@ -259,3 +259,4 @@ class StreamInConstant(Boundary):
def __eq__(self, other): def __eq__(self, other):
return type(other) == StreamInConstant return type(other) == StreamInConstant
# end class StreamInConstant
...@@ -23,7 +23,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -23,7 +23,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
self._inplace = is_inplace(streaming_pattern) self._inplace = is_inplace(streaming_pattern)
self._prev_timestep = None self._prev_timestep = None
super(LatticeBoltzmannBoundaryHandling, self).__init__(data_handling, pdf_field_name, lb_method.stencil, super(LatticeBoltzmannBoundaryHandling, self).__init__(data_handling, pdf_field_name, lb_method.stencil,
name, flag_interface, target, openmp) name, flag_interface, target, openmp)
# ------------------------- Overridden methods of pystencils.BoundaryHandling ------------------------- # ------------------------- Overridden methods of pystencils.BoundaryHandling -------------------------
...@@ -121,7 +121,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -121,7 +121,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
method = self._lb_method method = self._lb_method
stencil = np.array(method.stencil) stencil = np.array(method.stencil)
inv_direction = np.array([method.stencil.index(inverse_direction(d)) inv_direction = np.array([method.stencil.index(inverse_direction(d))
for d in method.stencil]) for d in method.stencil])
result = np.zeros(self.dim) result = np.zeros(self.dim)
for b in dh.iterate(ghost_layers=ff_ghost_layers): for b in dh.iterate(ghost_layers=ff_ghost_layers):
......
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