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
from itertools import product
def _array_pattern(dtype, name, content):
return f"const {str(dtype)} {name} [] = {{ {','.join(str(c) for c in content)} }}; \n"
class BetweenTimestepsIndexing:
# ==============================================
......@@ -187,12 +189,13 @@ class BetweenTimestepsIndexing:
# end class AdvancedStreamingIndexing
class NeighbourOffsetArraysForStencil(CustomCodeNode):
class NeighbourOffsetArrays(CustomCodeNode):
@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]
for symbol in NeighbourOffsetArraysForStencil._offset_symbols(dim)])
for symbol in NeighbourOffsetArrays._offset_symbols(dim)])
@staticmethod
def _offset_symbols(dim):
......@@ -202,11 +205,11 @@ class NeighbourOffsetArraysForStencil(CustomCodeNode):
offsets_dtype = create_type(offsets_dtype)
dim = len(stencil[0])
array_symbols = NeighbourOffsetArraysForStencil._offset_symbols(dim)
array_symbols = NeighbourOffsetArrays._offset_symbols(dim)
code = "\n"
for i, arrsymb in enumerate(array_symbols):
code += _array_pattern(offsets_dtype, arrsymb.name, (d[i] for d in stencil))
offset_symbols = NeighbourOffsetArraysForStencil._offset_symbols(dim)
super(NeighbourOffsetArraysForStencil, self).__init__(code, symbols_read=set(),
symbols_defined=set(offset_symbols))
\ No newline at end of file
offset_symbols = NeighbourOffsetArrays._offset_symbols(dim)
super(NeighbourOffsetArrays, self).__init__(code, symbols_read=set(),
symbols_defined=set(offset_symbols))
......@@ -114,5 +114,3 @@ class AccessPdfValues:
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))
......@@ -4,7 +4,7 @@ from lbmpy.boundaries.boundaryhandling import LbmWeightInfo
from pystencils.data_types import create_type
from pystencils.sympyextensions import get_symmetric_part
from lbmpy.simplificationfactory import create_simplification_strategy
from lbmpy.advanced_streaming.indexing import NeighbourOffsetArraysForStencil
from lbmpy.advanced_streaming.indexing import NeighbourOffsetArrays
class Boundary:
......@@ -127,18 +127,17 @@ class UBB(Boundary):
return self._velocity
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):
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
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(
direction, lb_method.dim)
neighbor_offset = NeighbourOffsetArrays.symbolic_neighbour_offset(direction, lb_method.dim)
velocity = tuple(v_i.get_shifted(*neighbor_offset)
if isinstance(v_i, Field.Access) and not vel_from_idx_field
......@@ -153,8 +152,8 @@ class UBB(Boundary):
c_s_sq = sp.Rational(1, 3)
weight_of_direction = LbmWeightInfo.weight_of_direction
vel_term = 2 / c_s_sq \
* sum([d_i * v_i for d_i, v_i in zip(neighbor_offset, velocity)]) \
* weight_of_direction(direction)
* sum([d_i * v_i for d_i, v_i in zip(neighbor_offset, velocity)]) \
* weight_of_direction(direction)
# Better alternative: in conserved value computation
# rename what is currently called density to "virtual_density"
......@@ -174,17 +173,16 @@ class UBB(Boundary):
f_out(direction) - vel_term)]
# end class UBB
# TODO
class FixedDensity(Boundary):
def __init__(self, density, name=None):
raise NotImplementedError() # not yet operable
if name is None:
name = "Fixed Density " + str(density)
super(FixedDensity, self).__init__(name)
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"""
def remove_asymmetric_part_of_main_assignments(assignment_collection, degrees_of_freedom):
......@@ -192,14 +190,11 @@ class FixedDensity(Boundary):
for a in assignment_collection.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
velocity = cqc.defined_symbols()['velocity']
symmetric_eq = remove_asymmetric_part_of_main_assignments(lb_method.get_equilibrium(),
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)
simplification = create_simplification_strategy(lb_method)
......@@ -214,24 +209,27 @@ class FixedDensity(Boundary):
assert density_eq.lhs == density_symbol
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)]
eq_component = sp.Piecewise(*conditions)
subexpressions = [Assignment(eq.lhs, transformed_density if eq.lhs == density_symbol else eq.rhs)
for eq in symmetric_eq.subexpressions]
return subexpressions + [Assignment(pdf_field[neighbor](inverse_dir),
2 * eq_component - pdf_field(direction_symbol))]
return subexpressions + [Assignment(f_in(inv_dir[dir_symbol]),
2 * eq_component - f_out(dir_symbol))]
# end class FixedDensity
class NeumannByCopy(Boundary):
def __call__(self, pdf_field, direction_symbol, lb_method, **kwargs):
raise NotImplementedError() # not yet operable
neighbor = BoundaryOffsetInfo.offset_from_dir(direction_symbol, lb_method.dim)
inverse_dir = BoundaryOffsetInfo.inv_dir(direction_symbol)
return [Assignment(pdf_field[neighbor](inverse_dir), pdf_field(inverse_dir)),
Assignment(pdf_field[neighbor](direction_symbol), pdf_field(direction_symbol))]
def get_additional_code_nodes(self, lb_method):
return [NeighbourOffsetArrays(lb_method.stencil)]
def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
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):
# All boundaries of these class behave equal -> should also be equal
......@@ -239,19 +237,21 @@ class NeumannByCopy(Boundary):
def __eq__(self, other):
return type(other) == NeumannByCopy
# end class NeumannByCopy
class StreamInConstant(Boundary):
def __init__(self, constant, name=None):
raise NotImplementedError() # not yet operable
super(StreamInConstant, self).__init__(name)
self._constant = constant
def __call__(self, pdf_field, direction_symbol, lb_method, **kwargs):
neighbor = BoundaryOffsetInfo.offset_from_dir(direction_symbol, lb_method.dim)
inverse_dir = BoundaryOffsetInfo.inv_dir(direction_symbol)
return [Assignment(pdf_field[neighbor](inverse_dir), self._constant),
Assignment(pdf_field[neighbor](direction_symbol), self._constant)]
def get_additional_code_nodes(self, lb_method):
return [NeighbourOffsetArrays(lb_method.stencil)]
def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field):
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):
# All boundaries of these class behave equal -> should also be equal
......@@ -259,3 +259,4 @@ class StreamInConstant(Boundary):
def __eq__(self, other):
return type(other) == StreamInConstant
# end class StreamInConstant
......@@ -23,7 +23,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
self._inplace = is_inplace(streaming_pattern)
self._prev_timestep = None
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 -------------------------
......@@ -121,7 +121,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
method = self._lb_method
stencil = np.array(method.stencil)
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)
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