From db66c16bba4b774ea600bef3d94f7b5af8bbdba6 Mon Sep 17 00:00:00 2001 From: Martin Bauer <martin.bauer@fau.de> Date: Fri, 11 Jan 2019 14:49:13 +0100 Subject: [PATCH] Added forth order FD stencil for 2D, first derivatives --- fd/spatial.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/fd/spatial.py b/fd/spatial.py index 43e88eaea..610756f12 100644 --- a/fd/spatial.py +++ b/fd/spatial.py @@ -1,8 +1,11 @@ +from typing import Tuple import sympy as sp from functools import partial +from pystencils.cache import memorycache from pystencils import AssignmentCollection, Field from pystencils.fd import Diff from .derivative import diff_args +from .derivation import FiniteDifferenceStencilDerivation def fd_stencils_standard(indices, dx, fa): @@ -51,6 +54,19 @@ def fd_stencils_isotropic(indices, dx, fa): raise NotImplementedError("Supports only derivatives up to order 2 for 1D and 2D setups") +def fd_stencils_forth_order_isotropic(indices, dx, fa): + order = len(indices) + if order != 1: + raise NotImplementedError("Forth order finite difference discretization is " + "currently only supported for first derivatives") + dim = indices[0] + if dim not in (0, 1): + raise NotImplementedError("Forth order finite difference discretization is only implemented for 2D") + + stencils = forth_order_2d_derivation() + return stencils[dim].apply(fa) / dx + + def fd_stencils_isotropic_high_density_code(indices, dx, fa): dim = fa.field.spatial_dimensions if dim == 1: @@ -106,3 +122,29 @@ def discretize_spatial(expr, dx, stencil=fd_stencils_standard): else: new_args = [discretize_spatial(a, dx, stencil) for a in expr.args] return expr.func(*new_args) if new_args else expr + + +# -------------------------------------- special stencils -------------------------------------------------------------- + +@memorycache(maxsize=1) +def forth_order_2d_derivation() -> Tuple[FiniteDifferenceStencilDerivation.Result, ...]: + # Symmetry, isotropy and 4th order conditions are not enough to fully specify the stencil + # one weight has to be specifically set to a somewhat arbitrary value + second_neighbor_weight = sp.Rational(1, 10) + second_neighbor_stencil = [(i, j) + for i in (-2, -1, 0, 1, 2) + for j in (-2, -1, 0, 1, 2) + ] + x_diff = FiniteDifferenceStencilDerivation((0,), second_neighbor_stencil) + x_diff.set_weight((2, 0), second_neighbor_weight) + x_diff.assume_symmetric(0, anti_symmetric=True) + x_diff.assume_symmetric(1) + x_diff_stencil = x_diff.get_stencil(isotropic=True) + + y_diff = FiniteDifferenceStencilDerivation((1,), second_neighbor_stencil) + y_diff.set_weight((0, 2), second_neighbor_weight) + y_diff.assume_symmetric(1, anti_symmetric=True) + y_diff.assume_symmetric(0) + y_diff_stencil = y_diff.get_stencil(isotropic=True) + + return x_diff_stencil, y_diff_stencil -- GitLab