Commit 248a5e0d by Markus Holzer Committed by Markus Holzer

### implemented derivation of gradient weights via rotation

derive gradient weights of other direction with
already calculated weights of one direction
via rotation and apply them to a field.

as_matrix gives now a deprecated warning and as_array is no newly implemented to replace it. as_array works with MutableDenseNDimArray now instead of Matrix
parent 3d00d87f
 from collections import defaultdict import sympy as sp import numpy as np from pystencils.field import Field from pystencils.sympyextensions import multidimensional_sum, prod from pystencils.utils import LinearEquationSystem, fully_contains import warnings class FiniteDifferenceStencilDerivation: """Derives finite difference stencils. ... ... @@ -169,6 +172,9 @@ class FiniteDifferenceStencilDerivation: return sum(f.get_shifted(*offset) * weight for offset, weight in zip(self.stencil, self.weights)) def as_matrix(self): warnings.warn("as_matrix is deprecated and may be removed in the near future." "Please use as_array instead which will return an MutableDenseNDimArray." "as_array therefore can also work in 3 dimensions", category=DeprecationWarning) dim = len(self.stencil[0]) assert dim == 2 max_offset = max(max(abs(e) for e in direction) for direction in self.stencil) ... ... @@ -177,6 +183,49 @@ class FiniteDifferenceStencilDerivation: result[max_offset - direction[1], max_offset + direction[0]] = weight return result def as_array(self): dim = len(self.stencil[0]) assert (dim == 2 or dim == 3), "Only 2D or 3D matrix representations are available" max_offset = max(max(abs(e) for e in direction) for direction in self.stencil) shape_list = [] for i in range(dim): shape_list.append(2 * max_offset + 1) number_of_elements = np.prod(shape_list) shape = tuple(shape_list) result = sp.MutableDenseNDimArray([0] * number_of_elements, shape) if dim == 2: for direction, weight in zip(self.stencil, self.weights): result[max_offset - direction[1], max_offset + direction[0]] = weight if dim == 3: for direction, weight in zip(self.stencil, self.weights): result[max_offset - direction[1], max_offset + direction[0], max_offset + direction[2]] = weight return result def rotate_weights_and_apply(self, field_access: Field.Access, axis): """derive gradient weights of other direction with already calculated weights of one direction via rotation and apply them to a field.""" dim = len(self.stencil[0]) assert (dim == 2 or dim == 3), "This function is only for 2D or 3D stencils available" rotated_weights = np.rot90(np.array(self.as_array()).reshape(self.as_array().shape), 1, axis) result = [] max_offset = max(max(abs(e) for e in direction) for direction in self.stencil) if dim == 2: for direction in self.stencil: result.append(rotated_weights[max_offset - direction[1], max_offset + direction[0]]) if dim == 3: for direction in self.stencil: result.append(rotated_weights[max_offset - direction[1], max_offset + direction[0], max_offset + direction[2]]) f = field_access return sum(f.get_shifted(*offset) * weight for offset, weight in zip(self.stencil, result)) def __repr__(self): return "Finite difference stencil of accuracy {}, isotropic error: {}".format(self.accuracy, self.is_isotropic)
 %% Cell type:code id: tags:  python from pystencils.session import * from pystencils.fd.derivation import *  %% Cell type:markdown id: tags: # 2D standard stencils %% Cell type:code id: tags:  python stencil = [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)] standard_2d_00 = FiniteDifferenceStencilDerivation((0,0), stencil) f = ps.fields("f: [2D]") standard_2d_00_res = standard_2d_00.get_stencil() res = standard_2d_00_res.apply(f.center) expected = f[-1, 0] - 2 * f[0, 0] + f[1, 0] assert res == expected  %% Cell type:code id: tags:  python assert standard_2d_00_res.accuracy == 2 assert not standard_2d_00_res.is_isotropic standard_2d_00_res  %% Output Finite difference stencil of accuracy 2, isotropic error: False %% Cell type:code id: tags:  python standard_2d_00.get_stencil().as_matrix()  %% Output $$\left[\begin{matrix}0 & 0 & 0\\1 & -2 & 1\\0 & 0 & 0\end{matrix}\right]$$ ⎡0 0 0⎤ ⎢ ⎥ ⎢1 -2 1⎥ ⎢ ⎥ ⎣0 0 0⎦ --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) in ----> 1 standard_2d_00.get_stencil().as_matrix() ~/pystencils/pystencils/pystencils/fd/derivation.py in as_matrix(self) 185 for direction, weight in zip(self.stencil, self.weights): 186 result[max_offset - direction[1], max_offset + direction[0]] = weight --> 187 result.tomatrix().tomatrix() 188 print("test") 189 if dim == 3: ~/anaconda3/envs/pystencils/lib/python3.7/site-packages/sympy/matrices/matrices.py in __getattr__(self, attr) 2139 else: 2140 raise AttributeError( -> 2141 "%s has no attribute %s." % (self.__class__.__name__, attr)) 2142 2143 def __len__(self): AttributeError: MutableDenseMatrix has no attribute tomatrix. %% Cell type:markdown id: tags: # 2D isotropic stencils ## second x-derivative %% Cell type:code id: tags:  python stencil = [(i, j) for i in (-1, 0, 1) for j in (-1, 0, 1)] isotropic_2d_00 = FiniteDifferenceStencilDerivation((0,0), stencil) isotropic_2d_00_res = isotropic_2d_00.get_stencil(isotropic=True) assert isotropic_2d_00_res.is_isotropic assert isotropic_2d_00_res.accuracy == 2 isotropic_2d_00_res  %% Output Finite difference stencil of accuracy 2, isotropic error: True %% Cell type:code id: tags:  python isotropic_2d_00_res.as_matrix()  %% Output $$\left[\begin{matrix}\frac{1}{12} & - \frac{1}{6} & \frac{1}{12}\\\frac{5}{6} & - \frac{5}{3} & \frac{5}{6}\\\frac{1}{12} & - \frac{1}{6} & \frac{1}{12}\end{matrix}\right]$$ ⎡1/12 -1/6 1/12⎤ ⎢ ⎥ ⎢5/6 -5/3 5/6 ⎥ ⎢ ⎥ ⎣1/12 -1/6 1/12⎦ %% Cell type:code id: tags:  python plt.figure(figsize=(2,2)) isotropic_2d_00_res.visualize()  %% Output %% Cell type:code id: tags:  python expected_result = sp.Matrix([[1, -2, 1], [10, -20, 10], [1, -2, 1]]) / 12 assert expected_result == isotropic_2d_00_res.as_matrix()  %% Cell type:code id: tags:  python type(isotropic_2d_00_res.as_matrix())  %% Cell type:code id: tags:  python type(expected_result)  %% Cell type:markdown id: tags: ## Isotropic laplacian %% Cell type:code id: tags:  python isotropic_2d_11 = FiniteDifferenceStencilDerivation((1,1), stencil) isotropic_2d_11_res = isotropic_2d_11.get_stencil(isotropic=True) iso_laplacian = isotropic_2d_00_res.as_matrix() + isotropic_2d_11_res.as_matrix() iso_laplacian  %% Output $$\left[\begin{matrix}\frac{1}{6} & \frac{2}{3} & \frac{1}{6}\\\frac{2}{3} & - \frac{10}{3} & \frac{2}{3}\\\frac{1}{6} & \frac{2}{3} & \frac{1}{6}\end{matrix}\right]$$ ⎡1/6 2/3 1/6⎤ ⎢ ⎥ ⎢2/3 -10/3 2/3⎥ ⎢ ⎥ ⎣1/6 2/3 1/6⎦ %% Cell type:code id: tags:  python expected_result = sp.Matrix([[1, 4, 1], [4, -20, 4], [1, 4, 1]]) / 6 assert iso_laplacian == expected_result  ... ...
 %% Cell type:code id: tags:  python from pystencils.session import * from pystencils.fd.derivation import *  %% Cell type:markdown id: tags: # 2D isotropic stencils %% Cell type:code id: tags: ` python stencil_2D = ((0, 0), (0, 1), (0, -1), (-1, 0), (1, 0),