diff --git a/listlbm.py b/listlbm.py new file mode 100644 index 0000000000000000000000000000000000000000..fd798463bd6273a95ed505deafd0b2ce58aa25b3 --- /dev/null +++ b/listlbm.py @@ -0,0 +1,100 @@ +import numpy as np + + +def get_fluid_cell_array(flag_arr, fluid_flag, ghost_layers): + inner_slice = [slice(ghost_layers, -ghost_layers)] * len(flag_arr.shape) + flag_arr_no_gl = flag_arr[inner_slice] + return np.argwhere(np.bitwise_and(flag_arr_no_gl, fluid_flag)) + ghost_layers + + +def get_cell_index(fluid_cell_arr, cell): + assert len(fluid_cell_arr.shape) == len(cell) + first_coord = [slice(None, None)] + [0] * (len(fluid_cell_arr.shape) - 1) + begin = np.searchsorted(fluid_cell_arr[first_coord], cell[0], 'left') + end = np.searchsorted(fluid_cell_arr[first_coord], cell[0], 'right') + if begin == end: + raise ValueError("Element not found") + + if len(fluid_cell_arr.shape) == 1: + return begin + else: + sub_array = fluid_cell_arr[begin:end, 1] + return begin + get_cell_index(sub_array, cell[1:]) + + +def get_index_array(fluid_cell_arr, flag_arr, ghost_layers, stencil, fluid_flag, noslip_flag): + + def pdf_index(cell_index, direction_index): + return cell_index + direction_index * len(fluid_cell_arr) + + def inverse_idx(idx): + return stencil.index(tuple(-d_i for d_i in stencil[idx])) + + result = [] + ctr = 0 + for direction_idx, direction in enumerate(stencil): + for own_cell_idx, cell in enumerate(fluid_cell_arr): + inv_neighbor_cell = np.array([cell_i - dir_i for cell_i, dir_i in zip(cell, direction)]) + + if flag_arr[tuple(inv_neighbor_cell)] & fluid_flag: + neighbor_cell_idx = get_cell_index(fluid_cell_arr, inv_neighbor_cell) + result.append(pdf_index(neighbor_cell_idx, direction_idx)) + elif flag_arr[tuple(inv_neighbor_cell)] & noslip_flag: # no-slip before periodicity! + result.append(pdf_index(own_cell_idx, inverse_idx(direction_idx))) + else: + # periodicity handling + # print(inv_neighbor_cell, end="") + at_border = False + for i, x_i in enumerate(inv_neighbor_cell): + if x_i == (ghost_layers - 1): + inv_neighbor_cell[i] += flag_arr.shape[i] - (2 * ghost_layers) + at_border = True + elif x_i == flag_arr.shape[i] - ghost_layers: + inv_neighbor_cell[i] -= flag_arr.shape[i] - (2 * ghost_layers) + at_border = True + if at_border: + assert flag_arr[tuple(inv_neighbor_cell)] & fluid_flag + neighbor_cell_idx = get_cell_index(fluid_cell_arr, inv_neighbor_cell) + result.append(pdf_index(neighbor_cell_idx, direction_idx)) + else: + raise ValueError("Could not find neighbor for {} direction {}".format(cell, direction)) + + ctr += 1 # TODO + return np.array(result, dtype=np.uint32) + + +def plot_index_array(fluid_cell_arr, stencil, ghost_layers=1, index_arr=None, **kwargs): + """Visualizes index array. + + Args: + fluid_cell_arr: array of fluid cells + stencil: stencil + ghost_layers: number of ghost layers + index_arr: index array, or None to show pdf index + **kwargs: passed to LbGrid.add_arrow + + Returns: + LbGrid + """ + from lbmpy.plot2d import LbGrid + x_max, y_max = np.max(fluid_cell_arr, axis=0) + grid = LbGrid(x_max + 1 - ghost_layers, y_max + 1 - ghost_layers) + index = 0 + for direction in stencil: + for fluid_cell in fluid_cell_arr: + annotation = index_arr[index] if index_arr is not None else index + grid.add_arrow((fluid_cell[0] - ghost_layers, fluid_cell[1] - ghost_layers), + direction, direction, str(annotation), **kwargs) + index += 1 + return grid + + +if __name__ == '__main__': + x = np.arange(9 * 7).reshape(9, 7) + ind = np.argwhere(x > 50) + print(ind) + res = get_cell_index(ind, (7, 2)) + print("result index", res) + print("element ", ind[res]) + + diff --git a/plot2d.py b/plot2d.py index d25231590804bb8f79bfa06f04e874156e645056..6c8bf45798bd75ceca7fd529f305997c1086e3ad 100644 --- a/plot2d.py +++ b/plot2d.py @@ -1,5 +1,6 @@ from itertools import cycle import matplotlib.patches as patches +from matplotlib.text import Text from pystencils import make_slice from pystencils.plot2d import * @@ -102,7 +103,8 @@ class LbGrid: self._patches.append(patches.Rectangle((x, y), 1.0, 1.0, fill=False, linewidth=3, color='#bbbbbb')) self._cellBoundaries = dict() # mapping cell to rectangle patch - self._arrows = dict() # mapping (cell, direction) tuples to arrow patches + self.arrows = dict() # mapping (cell, direction) tuples to arrow patches + self.annotations = dict() def add_cell_boundary(self, cell, **kwargs): """Draws a rectangle around a single cell. Keyword arguments are passed to the matplotlib Rectangle patch""" @@ -117,14 +119,16 @@ class LbGrid: for y in range(self._yCells): self.add_cell_boundary((x, y), **kwargs) - def add_arrow(self, cell, arrow_position, arrow_direction, **kwargs): + def add_arrow(self, cell, arrow_position, arrow_direction, annotation='', **kwargs): """ Draws an arrow in a cell. If an arrow exists already at this position, it is replaced. - :param cell: cell coordinate as tuple (x,y) - :param arrow_position: each cell has 9 possible positions specified as tuple e.g. upper left (-1, 1) - :param arrow_direction: direction of the arrow as (x,y) tuple - :param kwargs: arguments passed directly to the FancyArrow patch of matplotlib + Args: + cell: cell coordinate as tuple (x,y) + arrow_position: each cell has 9 possible positions specified as tuple e.g. upper left (-1, 1) + arrow_direction: direction of the arrow as (x,y) tuple + annotation: text to display at end of arrow + kwargs: arguments passed directly to the FancyArrow patch of matplotlib """ cell_midpoint = (0.5 + cell[0], 0.5 + cell[1]) @@ -133,19 +137,22 @@ class LbGrid: if arrow_position == (0, 0): del kwargs['width'] - self._arrows[(cell, arrow_position)] = patches.Circle(cell_midpoint, radius=0.03, **kwargs) + self.arrows[(cell, arrow_position)] = patches.Circle(cell_midpoint, radius=0.03, **kwargs) + if annotation: + self.annotations[(cell, arrow_position)] = Text(*cell_midpoint, annotation) else: arrow_midpoint = (cell_midpoint[0] + arrow_position[0] * 0.25, cell_midpoint[1] + arrow_position[1] * 0.25) length = 0.75 arrow_start = (arrow_midpoint[0] - arrow_direction[0] * 0.25 * length, arrow_midpoint[1] - arrow_direction[1] * 0.25 * length) - - patch = patches.FancyArrow(arrow_start[0], arrow_start[1], - 0.25 * length * arrow_direction[0], - 0.25 * length * arrow_direction[1], - **kwargs) - self._arrows[(cell, arrow_position)] = patch + arrow_direction = (0.25 * length * arrow_direction[0], + 0.25 * length * arrow_direction[1]) + arrow_end = tuple(a + b for a, b in zip(arrow_start, arrow_direction)) + patch = patches.FancyArrow(*arrow_start, *arrow_direction, **kwargs) + self.arrows[(cell, arrow_position)] = patch + if annotation: + self.annotations[(cell, arrow_position)] = Text(*arrow_end, annotation) def fill_with_default_arrows(self, **kwargs): """Fills the complete grid with the default pdf arrows""" @@ -164,9 +171,12 @@ class LbGrid: for p in self._patches: ax.add_patch(p) - for arrow_patch in self._arrows.values(): + for arrow_patch in self.arrows.values(): ax.add_patch(arrow_patch) + for text_obj in self.annotations.values(): + ax.add_artist(text_obj) + offset = 0.1 ax.set_xlim(-offset, self._xCells+offset) ax.set_xlim(-offset, self._xCells + offset)