Commit 7b4c3f2d authored by Martin Bauer's avatar Martin Bauer
Browse files

Refactoring of plotting and stencil plotting

- stencil plotting & transformation now in ps.stencil
- additional documentation & notebooks
parent 0998f2e1
[flake8]
max-line-length=120
exclude=pystencils/jupytersetup.py,
pystencils/plot2d.py
exclude=pystencils/jupyter.py,
pystencils/plot.py
pystencils/session.py
ignore = W293 W503 W291
......@@ -66,7 +66,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"3.84 ms ± 36.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
"3.93 ms ± 40 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
......@@ -132,7 +132,7 @@
],
"source": [
"plt.figure(figsize=(3,3))\n",
"ps.visualize_stencil_expression(symbolic_description.rhs)"
"ps.stencil.plot_expression(symbolic_description.rhs)"
]
},
{
......@@ -180,7 +180,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"639 µs ± 35 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
"643 µs ± 8.66 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
]
}
],
......@@ -615,7 +615,7 @@
"</svg>\n"
],
"text/plain": [
"<graphviz.files.Source at 0x7fc7dc51b2e8>"
"<graphviz.files.Source at 0x7ff8a018e7f0>"
]
},
"execution_count": 19,
......@@ -995,129 +995,129 @@
"<g id=\"graph0\" class=\"graph\" transform=\"scale(.9826 .9826) rotate(0) translate(4 472)\">\n",
"<title>%3</title>\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-472 692.083,-472 692.083,4 -4,4\"/>\n",
"<!-- 140495254316984 -->\n",
"<!-- 140704680405368 -->\n",
"<g id=\"node1\" class=\"node\">\n",
"<title>140495254316984</title>\n",
"<title>140704680405368</title>\n",
"<ellipse fill=\"#a056db\" stroke=\"#000000\" cx=\"219.8449\" cy=\"-450\" rx=\"107.781\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"219.8449\" y=\"-446.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Func: kernel (dst,img,w_2)</text>\n",
"</g>\n",
"<!-- 140495254318440 -->\n",
"<!-- 140704680405256 -->\n",
"<g id=\"node11\" class=\"node\">\n",
"<title>140495254318440</title>\n",
"<title>140704680405256</title>\n",
"<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"219.8449\" cy=\"-378\" rx=\"31.6951\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"219.8449\" y=\"-374.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n",
"</g>\n",
"<!-- 140495254316984&#45;&gt;140495254318440 -->\n",
"<!-- 140704680405368&#45;&gt;140704680405256 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>140495254316984&#45;&gt;140495254318440</title>\n",
"<title>140704680405368&#45;&gt;140704680405256</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M219.8449,-431.8314C219.8449,-424.131 219.8449,-414.9743 219.8449,-406.4166\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"223.345,-406.4132 219.8449,-396.4133 216.345,-406.4133 223.345,-406.4132\"/>\n",
"</g>\n",
"<!-- 140495254317656 -->\n",
"<!-- 140704680405032 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>140495254317656</title>\n",
"<title>140704680405032</title>\n",
"<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"144.8449\" cy=\"-306\" rx=\"61.99\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"144.8449\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22</text>\n",
"</g>\n",
"<!-- 140495254316256 -->\n",
"<!-- 140704680404416 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>140495254316256</title>\n",
"<title>140704680404416</title>\n",
"<ellipse fill=\"#3498db\" stroke=\"#000000\" cx=\"295.8449\" cy=\"-306\" rx=\"70.6878\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"295.8449\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Loop over dim 0</text>\n",
"</g>\n",
"<!-- 140495254316032 -->\n",
"<!-- 140704680404080 -->\n",
"<g id=\"node10\" class=\"node\">\n",
"<title>140495254316032</title>\n",
"<title>140704680404080</title>\n",
"<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"295.8449\" cy=\"-234\" rx=\"31.6951\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"295.8449\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n",
"</g>\n",
"<!-- 140495254316256&#45;&gt;140495254316032 -->\n",
"<!-- 140704680404416&#45;&gt;140704680404080 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>140495254316256&#45;&gt;140495254316032</title>\n",
"<title>140704680404416&#45;&gt;140704680404080</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M295.8449,-287.8314C295.8449,-280.131 295.8449,-270.9743 295.8449,-262.4166\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"299.345,-262.4132 295.8449,-252.4133 292.345,-262.4133 299.345,-262.4132\"/>\n",
"</g>\n",
"<!-- 140495254318496 -->\n",
"<!-- 140704681164528 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>140495254318496</title>\n",
"<title>140704681164528</title>\n",
"<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"57.8449\" cy=\"-162\" rx=\"57.6901\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"57.8449\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_dst_00</text>\n",
"</g>\n",
"<!-- 140495254316592 -->\n",
"<!-- 140704680403520 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>140495254316592</title>\n",
"<title>140704680403520</title>\n",
"<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"208.8449\" cy=\"-162\" rx=\"74.9875\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"208.8449\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22_01</text>\n",
"</g>\n",
"<!-- 140495254317320 -->\n",
"<!-- 140704680403352 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>140495254317320</title>\n",
"<title>140704680403352</title>\n",
"<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"383.8449\" cy=\"-162\" rx=\"81.7856\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"383.8449\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22_0m1</text>\n",
"</g>\n",
"<!-- 140495254318664 -->\n",
"<!-- 140704680404024 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>140495254318664</title>\n",
"<title>140704680404024</title>\n",
"<ellipse fill=\"#3498db\" stroke=\"#000000\" cx=\"554.8449\" cy=\"-162\" rx=\"70.6878\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"554.8449\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Loop over dim 1</text>\n",
"</g>\n",
"<!-- 140495254318776 -->\n",
"<!-- 140704680404360 -->\n",
"<g id=\"node9\" class=\"node\">\n",
"<title>140495254318776</title>\n",
"<title>140704680404360</title>\n",
"<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"554.8449\" cy=\"-90\" rx=\"31.6951\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"554.8449\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n",
"</g>\n",
"<!-- 140495254318664&#45;&gt;140495254318776 -->\n",
"<!-- 140704680404024&#45;&gt;140704680404360 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>140495254318664&#45;&gt;140495254318776</title>\n",
"<title>140704680404024&#45;&gt;140704680404360</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M554.8449,-143.8314C554.8449,-136.131 554.8449,-126.9743 554.8449,-118.4166\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"558.345,-118.4132 554.8449,-108.4133 551.345,-118.4133 558.345,-118.4132\"/>\n",
"</g>\n",
"<!-- 140495254317040 -->\n",
"<!-- 140704680403968 -->\n",
"<g id=\"node8\" class=\"node\">\n",
"<title>140495254317040</title>\n",
"<title>140704680403968</title>\n",
"<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"554.8449\" cy=\"-18\" rx=\"133.4768\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"554.8449\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_dst_00[_stride_dst_1*ctr_1]</text>\n",
"</g>\n",
"<!-- 140495254318776&#45;&gt;140495254317040 -->\n",
"<!-- 140704680404360&#45;&gt;140704680403968 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>140495254318776&#45;&gt;140495254317040</title>\n",
"<title>140704680404360&#45;&gt;140704680403968</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M554.8449,-71.8314C554.8449,-64.131 554.8449,-54.9743 554.8449,-46.4166\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"558.345,-46.4132 554.8449,-36.4133 551.345,-46.4133 558.345,-46.4132\"/>\n",
"</g>\n",
"<!-- 140495254316032&#45;&gt;140495254318496 -->\n",
"<!-- 140704680404080&#45;&gt;140704681164528 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>140495254316032&#45;&gt;140495254318496</title>\n",
"<title>140704680404080&#45;&gt;140704681164528</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M267.6085,-225.4579C228.6723,-213.6789 157.8187,-192.2442 109.3243,-177.5736\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"110.2227,-174.1888 99.6376,-174.6432 108.1957,-180.8889 110.2227,-174.1888\"/>\n",
"</g>\n",
"<!-- 140495254316032&#45;&gt;140495254316592 -->\n",
"<!-- 140704680404080&#45;&gt;140704680403520 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>140495254316032&#45;&gt;140495254316592</title>\n",
"<title>140704680404080&#45;&gt;140704680403520</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M277.8184,-219.0816C266.2777,-209.5306 251.0436,-196.9231 237.8284,-185.9864\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"239.8475,-183.1143 229.9121,-179.4349 235.3845,-188.507 239.8475,-183.1143\"/>\n",
"</g>\n",
"<!-- 140495254316032&#45;&gt;140495254317320 -->\n",
"<!-- 140704680404080&#45;&gt;140704680403352 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>140495254316032&#45;&gt;140495254317320</title>\n",
"<title>140704680404080&#45;&gt;140704680403352</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M314.0785,-219.0816C325.7519,-209.5306 341.1611,-196.9231 354.5282,-185.9864\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"357.0123,-188.4762 362.5355,-179.4349 352.5796,-183.0585 357.0123,-188.4762\"/>\n",
"</g>\n",
"<!-- 140495254316032&#45;&gt;140495254318664 -->\n",
"<!-- 140704680404080&#45;&gt;140704680404024 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>140495254316032&#45;&gt;140495254318664</title>\n",
"<title>140704680404080&#45;&gt;140704680404024</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M324.552,-226.0196C365.9645,-214.5073 443.366,-192.9903 496.9349,-178.0985\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"497.9488,-181.4495 506.646,-175.3989 496.0739,-174.7052 497.9488,-181.4495\"/>\n",
"</g>\n",
"<!-- 140495254318440&#45;&gt;140495254317656 -->\n",
"<!-- 140704680405256&#45;&gt;140704680405032 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>140495254318440&#45;&gt;140495254317656</title>\n",
"<title>140704680405256&#45;&gt;140704680405032</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M203.571,-362.3771C193.8398,-353.0351 181.2651,-340.9635 170.2498,-330.3888\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"172.5648,-327.7594 162.9271,-323.3589 167.7171,-332.8091 172.5648,-327.7594\"/>\n",
"</g>\n",
"<!-- 140495254318440&#45;&gt;140495254316256 -->\n",
"<!-- 140704680405256&#45;&gt;140704680404416 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>140495254318440&#45;&gt;140495254316256</title>\n",
"<title>140704680405256&#45;&gt;140704680404416</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M236.3357,-362.3771C246.1257,-353.1023 258.7558,-341.137 269.86,-330.6172\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"272.3977,-333.0344 277.2501,-323.6161 267.5835,-327.9527 272.3977,-333.0344\"/>\n",
"</g>\n",
......@@ -1125,7 +1125,7 @@
"</svg>\n"
],
"text/plain": [
"<graphviz.files.Source at 0x7fc798393fd0>"
"<graphviz.files.Source at 0x7ff84a432e10>"
]
},
"execution_count": 32,
......
......@@ -70,13 +70,6 @@
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"!\n"
]
},
{
"data": {
"image/png": "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\n",
......@@ -188,9 +181,8 @@
" timeloop(10)\n",
" result = None\n",
"else:\n",
" ps_notebook.set_display_mode('video')\n",
" ani = ps.plot2d.scalar_field_animation(timeloop, rescale=True, frames=300)\n",
" result = ps_notebook.display_animation(ani)\n",
" ani = ps.plot.scalar_field_animation(timeloop, rescale=True, frames=300)\n",
" result = ps.jupyter.display_as_html_video(ani)\n",
"result"
]
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -9,6 +9,7 @@ API Reference
datahandling.rst
configuration.rst
field.rst
stencil.rst
finite_differences.rst
plot.rst
ast.rst
......@@ -2,7 +2,7 @@
Plotting and Animation
**********************
.. automodule:: pystencils.plot2d
.. automodule:: pystencils.plot
:members:
*******
Stencil
*******
.. automodule:: pystencils.stencil
:members:
......@@ -15,6 +15,7 @@ It is a good idea to download them and run them directly to be able to play arou
/notebooks/05_tutorial_phasefield_spinodal_decomposition.ipynb
/notebooks/06_tutorial_phasefield_dentritic_growth.ipynb
/notebooks/demo_assignment_collection.ipynb
/notebooks/demo_plotting_and_animation.ipynb
/notebooks/demo_derivatives.ipynb
/notebooks/demo_benchmark.ipynb
/notebooks/demo_wave_equation.ipynb
......@@ -10,8 +10,8 @@ from .assignment import Assignment, assignment_from_stencil
from .sympyextensions import SymbolCreator
from .datahandling import create_data_handling
from .kernel_decorator import kernel
from .stencils import visualize_stencil_expression
from . import fd
from . import stencil as stencil
__all__ = ['Field', 'FieldType', 'fields',
......@@ -26,4 +26,4 @@ __all__ = ['Field', 'FieldType', 'fields',
'create_data_handling',
'kernel',
'fd',
'visualize_stencil_expression']
'stencil']
......@@ -159,8 +159,8 @@ class FiniteDifferenceStencilDerivation:
self.is_isotropic = is_isotropic
def visualize(self):
from pystencils.stencils import visualize_stencil
visualize_stencil(self.stencil, data=self.weights)
from pystencils.stencil import plot
plot(self.stencil, data=self.weights)
def apply(self, field_access: Field.Access):
f = field_access
......
......@@ -8,7 +8,7 @@ from sympy.core.cache import cacheit
from pystencils.alignedarray import aligned_empty
from pystencils.data_types import create_type, StructType
from pystencils.kernelparameters import FieldShapeSymbol, FieldStrideSymbol
from pystencils.stencils import offset_to_direction_string, direction_string_to_offset
from pystencils.stencil import offset_to_direction_string, direction_string_to_offset
from pystencils.sympyextensions import is_integer_sequence
import pickle
import hashlib
......
import pystencils.plot2d as plt
import pystencils.plot as plt
import matplotlib.animation as animation
from IPython.display import HTML
from tempfile import NamedTemporaryFile
......@@ -125,13 +125,13 @@ def display_in_extra_window(*_, **__):
# ------- Version 3: Animation is shown in images that are updated directly in website --------------
def display_as_html_image(animation, show=True, iterations=10000, *args, **kwargs):
def display_as_html_image(animation, show=True, *args, **kwargs):
from IPython import display
try:
if show:
animation._init_draw()
for i in range(iterations):
for _ in animation.frame_seq:
if show:
fig = plt.gcf()
display.display(fig)
......
......@@ -5,7 +5,6 @@ matplotlib normally uses.
"""
from matplotlib.pyplot import *
from itertools import cycle
from matplotlib.text import Text
def vector_field(array, step=2, **kwargs):
......@@ -67,6 +66,26 @@ def scalar_field(array, **kwargs):
return res
def scalar_field_surface(array, **kwargs):
"""Plots scalar field as 3D surface
Args:
array: the two dimensional numpy array to plot
kwargs: keyword arguments passed to :func:`mpl_toolkits.mplot3d.Axes3D.plot_surface`
"""
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
fig = gcf()
ax = fig.add_subplot(111, projection='3d')
x, y = np.meshgrid(np.arange(array.shape[0]), np.arange(array.shape[1]), indexing='ij')
kwargs.setdefault('rstride', 2)
kwargs.setdefault('cstride', 2)
kwargs.setdefault('color', 'b')
kwargs.setdefault('cmap', cm.coolwarm)
return ax.plot_surface(x, y, array, **kwargs)
def scalar_field_alpha_value(array, color, clip=False, **kwargs):
"""Plots an image with same color everywhere, using the array values as transparency.
......@@ -158,6 +177,7 @@ def phase_plot(phase_field: np.ndarray, linewidth=1.0, clip=True) -> None:
for i in range(phase_field.shape[-1]):
scalar_field_contour(phase_field[..., i], levels=[0.5], colors='k', linewidths=[linewidth])
def sympy_function(expr, x_values=None, **kwargs):
"""Plots the graph of a sympy term that depends on one symbol only.
......@@ -307,14 +327,12 @@ def scalar_field_animation(run_function, plot_setup_function=lambda *_: None, re
return animation.FuncAnimation(fig, update_figure, interval=interval, frames=frames)
def surface_plot_animation(run_function, frames=90, interval=30, **kwargs):
def surface_plot_animation(run_function, frames=90, interval=30, zlim=None, **kwargs):
"""Animation of scalar field as 3D plot."""
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
fig = gcf()
ax = fig.add_subplot(111, projection='3d')
data = run_function()
x, y = np.meshgrid(np.arange(data.shape[0]), np.arange(data.shape[1]), indexing='ij')
......@@ -323,13 +341,15 @@ def surface_plot_animation(run_function, frames=90, interval=30, **kwargs):
kwargs.setdefault('color', 'b')
kwargs.setdefault('cmap', cm.coolwarm)
ax.plot_surface(x, y, data, **kwargs)
ax.set_zlim(-1.0, 1.0)
if zlim is not None:
ax.set_zlim(*zlim)
def update_figure(*_):
d = run_function()
ax.clear()
plot = ax.plot_surface(x, y, d, **kwargs)
ax.set_zlim(-1.0, 1.0)
if zlim is not None:
ax.set_zlim(*zlim)
return plot,
return animation.FuncAnimation(fig, update_figure, interval=interval, frames=frames, blit=False)
import pystencils.sympy_gmpy_bug_workaround
import pystencils.jupyter
import sympy as sp
import numpy as np
import pystencils as ps
import pystencils.plot2d as plt
import pystencils.jupytersetup as ps_notebook
import pystencils.plot as plt
__all__ = ['sp', 'np', 'ps', 'plt', 'ps_notebook']
__all__ = ['sp', 'np', 'ps', 'plt']
"""This submodule offers functions to work with stencils in expression an offset-list form."""
from typing import Sequence
import numpy as np
import sympy as sp
......@@ -5,15 +6,28 @@ from collections import defaultdict
def inverse_direction(direction):
"""Returns inverse i.e. negative of given direction tuple"""
"""Returns inverse i.e. negative of given direction tuple
Example:
>>> inverse_direction((1, -1, 0))
(-1, 1, 0)
"""
return tuple([-i for i in direction])
def is_valid_stencil(stencil, max_neighborhood=None):
def is_valid(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.
Examples:
>>> is_valid([(1, 0), (1, 0, 0)]) # stencil entries have different length
False
>>> is_valid([(2, 0), (1, 0)])
True
>>> is_valid([(2, 0), (1, 0)], max_neighborhood=1)
False
"""
expected_dim = len(stencil[0])
for d in stencil:
......@@ -26,15 +40,30 @@ def is_valid_stencil(stencil, max_neighborhood=None):
return True
def is_symmetric_stencil(stencil):
"""Tests for every direction d, that -d is also in the stencil"""
def is_symmetric(stencil):
"""Tests for every direction d, that -d is also in the stencil
Examples:
>>> is_symmetric([(1, 0), (0, 1)])
False
>>> is_symmetric([(1, 0), (-1, 0)])
True
"""
for d in stencil:
if inverse_direction(d) not in stencil:
return False
return True
def stencils_have_same_entries(s1, s2):
def have_same_entries(s1, s2):
"""Checks if two stencils are the same
Examples:
>>> stencil1 = [(1, 0), (-1, 0), (0, 1), (0, -1)]
>>> stencil2 = [(-1, 0), (0, -1), (1, 0), (0, 1)]
>>> have_same_entries(stencil1, stencil2)
True
"""
if len(s1) != len(s2):
return False
return len(set(s1) - set(s2)) == 0
......@@ -43,7 +72,7 @@ def stencils_have_same_entries(s1, s2):
# -------------------------------------Expression - Coefficient Form Conversion ----------------------------------------
def stencil_coefficient_dict(expr):
def coefficient_dict(expr):
"""Extracts coefficients in front of field accesses in a expression.
Expression may only access a single field at a single index.
......@@ -57,12 +86,12 @@ def stencil_coefficient_dict(expr):
Examples:
>>> import pystencils as ps
>>> f = ps.fields("f(3) : double[2D]")
>>> field, coeffs, nonlinear_part = stencil_coefficient_dict(2 * f[0, 1](1) + 3 * f[-1, 0](1) + 123)
>>> field, coeffs, nonlinear_part = coefficient_dict(2 * f[0, 1](1) + 3 * f[-1, 0](1) + 123)
>>> assert nonlinear_part == 123 and field == f(1)
>>> sorted(coeffs.items())
[((-1, 0), 3), ((0, 1), 2)]
"""
from .field import Field
from pystencils import Field
expr = expr.expand()
field_accesses = expr.atoms(Field.Access)
fields = set(fa.field for fa in field_accesses)
......@@ -77,70 +106,70 @@ def stencil_coefficient_dict(expr):
field = fields.pop()
idx = accessed_indices.pop()
coefficients = defaultdict(lambda: 0)
coefficients.update({fa.offsets: expr.coeff(fa) for fa in field_accesses})
coeffs = defaultdict(lambda: 0)
coeffs.update({fa.offsets: expr.coeff(fa) for fa in field_accesses})
linear_part = sum(c * field[off](*idx) for off, c in coefficients.items())
linear_part = sum(c * field[off](*idx) for off, c in coeffs.items())
nonlinear_part = expr - linear_part
return field(*idx), coefficients, nonlinear_part
return field(*idx), coeffs, nonlinear_part
def stencil_coefficients(expr):
def coefficients(expr):
"""Returns two lists - one with accessed offsets and one with their coefficients.
Same restrictions as `stencil_coefficient_dict` apply. Expression must not have any nonlinear part
Same restrictions as `coefficient_dict` apply. Expression must not have any nonlinear part
>>> import pystencils as ps
>>> f = ps.fields("f(3) : double[2D]")
>>> coff = stencil_coefficients(2 * f[0, 1](1) + 3 * f[-1, 0](1))
>>> coff = coefficients(2 * f[0, 1](1) + 3 * f[-1, 0](1))
"""
field_center, coefficients, nonlinear_part = stencil_coefficient_dict(expr)
field_center, coeffs, nonlinear_part = coefficient_dict(expr)
assert nonlinear_part == 0
stencil = list(coefficients.keys())
entries = [coefficients[c] for c in stencil]
stencil = list(coeffs.keys())
entries = [coeffs[c] for c in stencil]
return stencil, entries
def stencil_coefficient_list(expr, matrix_form=False):
def coefficient_list(expr, matrix_form=False):
"""Returns stencil coefficients in the form of nested lists
Same restrictions as `stencil_coefficient_dict` apply. Expression must not have any nonlinear part
Same restrictions as `coefficient_dict` apply. Expression must not have any nonlinear part
Examples:
>>> import pystencils as ps
>>> f = ps.fields("f: double[2D]")
>>> stencil_coefficient_list(2 * f[0, 1] + 3 * f[-1, 0])
>>> coefficient_list(2 * f[0, 1] + 3 * f[-1, 0])
[[0, 0, 0], [3, 0, 0], [0, 2, 0]]
>>> stencil_coefficient_list(2 * f[0, 1] + 3 * f[-1, 0], matrix_form=True)
>>> coefficient_list(2 * f[0, 1] + 3 * f[-1, 0], matrix_form=True)
Matrix([
[0, 2, 0],
[3, 0, 0],
[0, 0, 0]])
"""
field_center, coefficients, nonlinear_part = stencil_coefficient_dict(expr)
field_center, coeffs, nonlinear_part = coefficient_dict(expr)
assert nonlinear_part == 0
field = field_center.field
dim = field.spatial_dimensions
max_offsets = defaultdict(lambda: 0)
for offset in coefficients.keys():
for offset in coeffs.keys():
for d, off in enumerate(offset):
max_offsets[d] = max(max_offsets[d], abs(off))
if dim == 1:
result = [coefficients[(i,)] for i in range(-max_offsets[0], max_offsets[0] + 1)]
result = [coeffs[(i,)] for i in range(-max_offsets[0], max_offsets[0] + 1)]
return sp.Matrix(result) if matrix_form else result
else: