From f8dfaaad37f61012fc0c7ea139c4d712211231bf Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Wed, 19 Sep 2018 12:50:08 +0200 Subject: [PATCH] Moved stencils from lbmpy->pystencils, New coeff extraction funcs - new functions to easily extract stencil coefficients and visualize them - Moved stencil functions from lbmpy to pystencils --- boundaries/boundaryhandling.py | 2 +- creationfunctions.py | 3 +- fieldaccess.py | 2 +- methods/creationfunctions.py | 3 +- moments.py | 3 +- stencils.py | 207 --------------------------------- 6 files changed, 8 insertions(+), 212 deletions(-) diff --git a/boundaries/boundaryhandling.py b/boundaries/boundaryhandling.py index 8e7e64c2..722984da 100644 --- a/boundaries/boundaryhandling.py +++ b/boundaries/boundaryhandling.py @@ -4,7 +4,7 @@ from pystencils import TypedSymbol, create_indexed_kernel, Assignment from pystencils.backends.cbackend import CustomCppCode from pystencils.boundaries import BoundaryHandling from pystencils.boundaries.boundaryhandling import BoundaryOffsetInfo -from lbmpy.stencils import inverse_direction +from pystencils.stencils import inverse_direction class LatticeBoltzmannBoundaryHandling(BoundaryHandling): diff --git a/creationfunctions.py b/creationfunctions.py index 3f6dbf3e..c291a72f 100644 --- a/creationfunctions.py +++ b/creationfunctions.py @@ -173,7 +173,8 @@ from lbmpy.methods import create_srt, create_trt, create_mrt_orthogonal, create_ from lbmpy.methods.entropic import add_iterative_entropy_condition, add_entropy_condition from lbmpy.methods.entropic_eq_srt import create_srt_entropic from lbmpy.relaxationrates import relaxation_rate_from_magic_number -from lbmpy.stencils import get_stencil, stencils_have_same_entries +from lbmpy.stencils import get_stencil +from pystencils.stencils import stencils_have_same_entries import lbmpy.forcemodels as forcemodels from lbmpy.simplificationfactory import create_simplification_strategy from lbmpy.fieldaccess import StreamPullTwoFieldsAccessor, PeriodicTwoFieldsAccessor, CollideOnlyInplaceAccessor diff --git a/fieldaccess.py b/fieldaccess.py index 093ade64..214d1f58 100644 --- a/fieldaccess.py +++ b/fieldaccess.py @@ -1,6 +1,6 @@ import sympy as sp import abc -from lbmpy.stencils import inverse_direction +from pystencils.stencils import inverse_direction from pystencils import Field diff --git a/methods/creationfunctions.py b/methods/creationfunctions.py index c12cd5d1..e9e0ae5b 100644 --- a/methods/creationfunctions.py +++ b/methods/creationfunctions.py @@ -7,7 +7,8 @@ import operator import itertools from lbmpy.methods.cumulantbased import CumulantBasedLbMethod from lbmpy.methods.momentbased import MomentBasedLbMethod -from lbmpy.stencils import stencils_have_same_entries, get_stencil +from lbmpy.stencils import get_stencil +from pystencils.stencils import stencils_have_same_entries from lbmpy.moments import is_even, gram_schmidt, get_default_moment_set_for_stencil, MOMENT_SYMBOLS, \ exponents_to_polynomial_representations, moments_of_order, moments_up_to_component_order, \ sort_moments_into_groups_of_same_order, get_order, discrete_moment diff --git a/moments.py b/moments.py index 85c4a1e1..188fd23b 100644 --- a/moments.py +++ b/moments.py @@ -384,7 +384,8 @@ def get_default_moment_set_for_stencil(stencil): """ Returns a sequence of moments that are commonly used to construct a LBM equilibrium for the given stencil """ - from lbmpy.stencils import get_stencil, stencils_have_same_entries + from lbmpy.stencils import get_stencil + from pystencils.stencils import stencils_have_same_entries to_poly = exponents_to_polynomial_representations diff --git a/stencils.py b/stencils.py index 0c2b0625..17a6b066 100644 --- a/stencils.py +++ b/stencils.py @@ -1,6 +1,3 @@ -import sympy as sp - - def get_stencil(name, ordering='walberla'): """ Stencils are tuples of discrete velocities. They are commonly labeled in the 'DxQy' notation, where d is the @@ -84,207 +81,3 @@ get_stencil.data = { (1, 1, -1), (-1, 1, -1), (1, -1, -1), (-1, -1, -1)) } } - - -def inverse_direction(direction): - """Returns inverse i.e. negative of given direction tuple""" - return tuple([-i for i in direction]) - - -def is_valid_stencil(stencil, max_neighborhood=None): - """ - Tests if a nested sequence is a valid stencil i.e. all the inner sequences have the same length. - If max_neighborhood is specified, it is also verified that the stencil does not contain any direction components - with absolute value greater than the maximal neighborhood. - """ - expected_dim = len(stencil[0]) - for d in stencil: - if len(d) != expected_dim: - return False - if max_neighborhood is not None: - for d_i in d: - if abs(d_i) > max_neighborhood: - return False - return True - - -def is_symmetric_stencil(stencil): - """Tests for every direction d, that -d is also in the stencil""" - for d in stencil: - if inverse_direction(d) not in stencil: - return False - return True - - -def stencils_have_same_entries(s1, s2): - if len(s1) != len(s2): - return False - return len(set(s1) - set(s2)) == 0 - - -# -------------------------------------- Visualization ----------------------------------------------------------------- - -def visualize_stencil(stencil, **kwargs): - dim = len(stencil[0]) - if dim == 2: - visualize_stencil_2d(stencil, **kwargs) - else: - slicing = False - if 'slice' in kwargs: - slicing = kwargs['slice'] - del kwargs['slice'] - - if slicing: - visualize_stencil_3d_by_slicing(stencil, **kwargs) - else: - visualize_stencil_3d(stencil, **kwargs) - - -def visualize_stencil_2d(stencil, axes=None, figure=None, data=None, textsize='12', **kwargs): - """ - Creates a matplotlib 2D plot of the stencil - - :param stencil: sequence of directions - :param axes: optional matplotlib axes - :param data: data to annotate the directions with, if none given, the indices are used - :param textsize: size of annotation text - """ - from matplotlib.patches import BoxStyle - import matplotlib.pyplot as plt - - if axes is None: - if figure is None: - figure = plt.gcf() - axes = figure.gca() - - text_box_style = BoxStyle("Round", pad=0.3) - head_length = 0.1 - text_offset = 1.25 - - if data is None: - data = list(range(len(stencil))) - - for direction, annotation in zip(stencil, data): - assert len(direction) == 2, "Works only for 2D stencils" - - if not(direction[0] == 0 and direction[1] == 0): - axes.arrow(0, 0, direction[0], direction[1], head_width=0.08, head_length=head_length, color='k') - - if isinstance(annotation, sp.Basic): - annotation = "$" + sp.latex(annotation) + "$" - else: - annotation = str(annotation) - axes.text(direction[0] * text_offset, direction[1] * text_offset, annotation, verticalalignment='center', - zorder=30, horizontalalignment='center', size=textsize, - bbox=dict(boxstyle=text_box_style, facecolor='#00b6eb', alpha=0.85, linewidth=0)) - - axes.set_axis_off() - axes.set_aspect('equal') - axes.set_xlim([-text_offset * 1.1, text_offset * 1.1]) - axes.set_ylim([-text_offset * 1.1, text_offset * 1.1]) - - -def visualize_stencil_3d_by_slicing(stencil, slice_axis=2, figure=None, data=None, **kwargs): - """Visualizes a 3D, first-neighborhood stencil by plotting 3 slices along a given axis. - - Args: - stencil: stencil as sequence of directions - slice_axis: 0, 1, or 2 indicating the axis to slice through - data: optional data to print as text besides the arrows - """ - import matplotlib.pyplot as plt - - for d in stencil: - for element in d: - assert element == -1 or element == 0 or element == 1, "This function can only first neighborhood stencils" - - if figure is None: - figure = plt.gcf() - - axes = [figure.add_subplot(1, 3, i + 1) for i in range(3)] - splitted_directions = [[], [], []] - splitted_data = [[], [], []] - axes_names = ['x', 'y', 'z'] - - for i, d in enumerate(stencil): - split_idx = d[slice_axis] + 1 - reduced_dir = tuple([element for j, element in enumerate(d) if j != slice_axis]) - splitted_directions[split_idx].append(reduced_dir) - splitted_data[split_idx].append(i if data is None else data[i]) - - for i in range(3): - visualize_stencil_2d(splitted_directions[i], axes=axes[i], data=splitted_data[i], **kwargs) - for i in [-1, 0, 1]: - axes[i + 1].set_title("Cut at %s=%d" % (axes_names[slice_axis], i)) - - -def visualize_stencil_3d(stencil, figure=None, axes=None, data=None, textsize='8'): - """ - Draws 3D stencil into a 3D coordinate system, parameters are similar to :func:`visualize_stencil_2d` - If data is None, no labels are drawn. To draw the labels as in the 2D case, use ``data=list(range(len(stencil)))`` - """ - from matplotlib.patches import FancyArrowPatch - from mpl_toolkits.mplot3d import proj3d - import matplotlib.pyplot as plt - from matplotlib.patches import BoxStyle - from itertools import product, combinations - import numpy as np - - class Arrow3D(FancyArrowPatch): - def __init__(self, xs, ys, zs, *args, **kwargs): - FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs) - self._verts3d = xs, ys, zs - - def draw(self, renderer): - xs3d, ys3d, zs3d = self._verts3d - xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) - self.set_positions((xs[0], ys[0]), (xs[1], ys[1])) - FancyArrowPatch.draw(self, renderer) - - if axes is None: - if figure is None: - figure = plt.figure() - axes = figure.gca(projection='3d') - axes.set_aspect("equal") - - if data is None: - data = [None] * len(stencil) - - text_offset = 1.25 - text_box_style = BoxStyle("Round", pad=0.3) - - # Draw cell (cube) - r = [-1, 1] - for s, e in combinations(np.array(list(product(r, r, r))), 2): - if np.sum(np.abs(s - e)) == r[1] - r[0]: - axes.plot3D(*zip(s, e), color="k", alpha=0.5) - - for d, annotation in zip(stencil, data): - assert len(d) == 3, "Works only for 3D stencils" - if not (d[0] == 0 and d[1] == 0 and d[2] == 0): - if d[0] == 0: - color = '#348abd' - elif d[1] == 0: - color = '#fac364' - elif sum([abs(d) for d in d]) == 2: - color = '#95bd50' - else: - color = '#808080' - - a = Arrow3D([0, d[0]], [0, d[1]], [0, d[2]], mutation_scale=20, lw=2, arrowstyle="-|>", color=color) - axes.add_artist(a) - - if annotation: - if isinstance(annotation, sp.Basic): - annotation = "$" + sp.latex(annotation) + "$" - else: - annotation = str(annotation) - - axes.text(d[0] * text_offset, d[1] * text_offset, d[2] * text_offset, - annotation, verticalalignment='center', zorder=30, - size=textsize, bbox=dict(boxstyle=text_box_style, facecolor='#777777', alpha=0.6, linewidth=0)) - - axes.set_xlim([-text_offset * 1.1, text_offset * 1.1]) - axes.set_ylim([-text_offset * 1.1, text_offset * 1.1]) - axes.set_zlim([-text_offset * 1.1, text_offset * 1.1]) - axes.set_axis_off() -- GitLab