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
Pipeline #15208 passed with stage
in 3 minutes and 34 seconds
[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
......@@ -71,11 +71,11 @@
%% Cell type:code id: tags:
``` python
plt.figure(figsize=(3,3))
ps.visualize_stencil_expression(symbolic_description.rhs)
ps.stencil.plot_expression(symbolic_description.rhs)
```
%%%% Output: display_data
![](data:image/png;base64,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)
......@@ -266,11 +266,11 @@
```
%%%% Output: execute_result
![](data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN""http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- Generated by graphviz version 2.40.1 (20161225.0304)--><!-- Title: %3 Pages: 1 --><svg width="422pt" height="260pt"viewBox="0.00 0.00 422.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)"><title>%3</title><polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-256 418,-256 418,4 -4,4"/><!-- Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_() --><g id="node1" class="node"><title>Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_()</title><ellipse fill="none" stroke="#000000" cx="135" cy="-234" rx="27" ry="18"/><text text-anchor="middle" x="135" y="-230.3" font-family="Times,serif" font-size="14.00" fill="#000000">Add</text></g><!-- Pow(Symbol(x), Integer(2))_(0,) --><g id="node2" class="node"><title>Pow(Symbol(x), Integer(2))_(0,)</title><ellipse fill="none" stroke="#000000" cx="99" cy="-162" rx="27" ry="18"/><text text-anchor="middle" x="99" y="-158.3" font-family="Times,serif" font-size="14.00" fill="#000000">Pow</text></g><!-- Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_()&#45;&gt;Pow(Symbol(x), Integer(2))_(0,) --><g id="edge1" class="edge"><title>Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_()&#45;&gt;Pow(Symbol(x), Integer(2))_(0,)</title><path fill="none" stroke="#000000" d="M126.2854,-216.5708C122.0403,-208.0807 116.8464,-197.6929 112.1337,-188.2674"/><polygon fill="#000000" stroke="#000000" points="115.237,-186.6477 107.6343,-179.2687 108.976,-189.7782 115.237,-186.6477"/></g><!-- Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,) --><g id="node5" class="node"><title>Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)</title><ellipse fill="none" stroke="#000000" cx="171" cy="-162" rx="27" ry="18"/><text text-anchor="middle" x="171" y="-158.3" font-family="Times,serif" font-size="14.00" fill="#000000">Mul</text></g><!-- Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_()&#45;&gt;Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,) --><g id="edge2" class="edge"><title>Add(Pow(Symbol(x), Integer(2)), Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y))))_()&#45;&gt;Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)</title><path fill="none" stroke="#000000" d="M143.7146,-216.5708C147.9597,-208.0807 153.1536,-197.6929 157.8663,-188.2674"/><polygon fill="#000000" stroke="#000000" points="161.024,-189.7782 162.3657,-179.2687 154.763,-186.6477 161.024,-189.7782"/></g><!-- Symbol(x)_(0, 0) --><g id="node3" class="node"><title>Symbol(x)_(0, 0)</title><ellipse fill="none" stroke="#000000" cx="27" cy="-90" rx="27" ry="18"/><text text-anchor="middle" x="27" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">x</text></g><!-- Pow(Symbol(x), Integer(2))_(0,)&#45;&gt;Symbol(x)_(0, 0) --><g id="edge3" class="edge"><title>Pow(Symbol(x), Integer(2))_(0,)&#45;&gt;Symbol(x)_(0, 0)</title><path fill="none" stroke="#000000" d="M83.7307,-146.7307C73.803,-136.803 60.6847,-123.6847 49.5637,-112.5637"/><polygon fill="#000000" stroke="#000000" points="51.7933,-109.8436 42.2473,-105.2473 46.8436,-114.7933 51.7933,-109.8436"/></g><!-- Integer(2)_(0, 1) --><g id="node4" class="node"><title>Integer(2)_(0, 1)</title><ellipse fill="none" stroke="#000000" cx="99" cy="-90" rx="27" ry="18"/><text text-anchor="middle" x="99" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">2</text></g><!-- Pow(Symbol(x), Integer(2))_(0,)&#45;&gt;Integer(2)_(0, 1) --><g id="edge4" class="edge"><title>Pow(Symbol(x), Integer(2))_(0,)&#45;&gt;Integer(2)_(0, 1)</title><path fill="none" stroke="#000000" d="M99,-143.8314C99,-136.131 99,-126.9743 99,-118.4166"/><polygon fill="#000000" stroke="#000000" points="102.5001,-118.4132 99,-108.4133 95.5001,-118.4133 102.5001,-118.4132"/></g><!-- Pow(Symbol(x), Integer(2))_(1, 0) --><g id="node6" class="node"><title>Pow(Symbol(x), Integer(2))_(1, 0)</title><ellipse fill="none" stroke="#000000" cx="171" cy="-90" rx="27" ry="18"/><text text-anchor="middle" x="171" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">Pow</text></g><!-- Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)&#45;&gt;Pow(Symbol(x), Integer(2))_(1, 0) --><g id="edge5" class="edge"><title>Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)&#45;&gt;Pow(Symbol(x), Integer(2))_(1, 0)</title><path fill="none" stroke="#000000" d="M171,-143.8314C171,-136.131 171,-126.9743 171,-118.4166"/><polygon fill="#000000" stroke="#000000" points="174.5001,-118.4132 171,-108.4133 167.5001,-118.4133 174.5001,-118.4132"/></g><!-- Add(Integer(5), Symbol(x), Symbol(y))_(1, 1) --><g id="node9" class="node"><title>Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)</title><ellipse fill="none" stroke="#000000" cx="279" cy="-90" rx="27" ry="18"/><text text-anchor="middle" x="279" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">Add</text></g><!-- Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)&#45;&gt;Add(Integer(5), Symbol(x), Symbol(y))_(1, 1) --><g id="edge6" class="edge"><title>Mul(Pow(Symbol(x), Integer(2)), Add(Integer(5), Symbol(x), Symbol(y)))_(1,)&#45;&gt;Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)</title><path fill="none" stroke="#000000" d="M190.3082,-149.1278C207.3555,-137.763 232.4019,-121.0654 251.5344,-108.3104"/><polygon fill="#000000" stroke="#000000" points="253.4799,-111.2199 259.8589,-102.7607 249.5969,-105.3956 253.4799,-111.2199"/></g><!-- Symbol(x)_(1, 0, 0) --><g id="node7" class="node"><title>Symbol(x)_(1, 0, 0)</title><ellipse fill="none" stroke="#000000" cx="99" cy="-18" rx="27" ry="18"/><text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00" fill="#000000">x</text></g><!-- Pow(Symbol(x), Integer(2))_(1, 0)&#45;&gt;Symbol(x)_(1, 0, 0) --><g id="edge7" class="edge"><title>Pow(Symbol(x), Integer(2))_(1, 0)&#45;&gt;Symbol(x)_(1, 0, 0)</title><path fill="none" stroke="#000000" d="M155.7307,-74.7307C145.803,-64.803 132.6847,-51.6847 121.5637,-40.5637"/><polygon fill="#000000" stroke="#000000" points="123.7933,-37.8436 114.2473,-33.2473 118.8436,-42.7933 123.7933,-37.8436"/></g><!-- Integer(2)_(1, 0, 1) --><g id="node8" class="node"><title>Integer(2)_(1, 0, 1)</title><ellipse fill="none" stroke="#000000" cx="171" cy="-18" rx="27" ry="18"/><text text-anchor="middle" x="171" y="-14.3" font-family="Times,serif" font-size="14.00" fill="#000000">2</text></g><!-- Pow(Symbol(x), Integer(2))_(1, 0)&#45;&gt;Integer(2)_(1, 0, 1) --><g id="edge8" class="edge"><title>Pow(Symbol(x), Integer(2))_(1, 0)&#45;&gt;Integer(2)_(1, 0, 1)</title><path fill="none" stroke="#000000" d="M171,-71.8314C171,-64.131 171,-54.9743 171,-46.4166"/><polygon fill="#000000" stroke="#000000" points="174.5001,-46.4132 171,-36.4133 167.5001,-46.4133 174.5001,-46.4132"/></g><!-- Integer(5)_(1, 1, 0) --><g id="node10" class="node"><title>Integer(5)_(1, 1, 0)</title><ellipse fill="none" stroke="#000000" cx="243" cy="-18" rx="27" ry="18"/><text text-anchor="middle" x="243" y="-14.3" font-family="Times,serif" font-size="14.00" fill="#000000">5</text></g><!-- Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Integer(5)_(1, 1, 0) --><g id="edge9" class="edge"><title>Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Integer(5)_(1, 1, 0)</title><path fill="none" stroke="#000000" d="M270.2854,-72.5708C266.0403,-64.0807 260.8464,-53.6929 256.1337,-44.2674"/><polygon fill="#000000" stroke="#000000" points="259.237,-42.6477 251.6343,-35.2687 252.976,-45.7782 259.237,-42.6477"/></g><!-- Symbol(x)_(1, 1, 1) --><g id="node11" class="node"><title>Symbol(x)_(1, 1, 1)</title><ellipse fill="none" stroke="#000000" cx="315" cy="-18" rx="27" ry="18"/><text text-anchor="middle" x="315" y="-14.3" font-family="Times,serif" font-size="14.00" fill="#000000">x</text></g><!-- Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Symbol(x)_(1, 1, 1) --><g id="edge10" class="edge"><title>Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Symbol(x)_(1, 1, 1)</title><path fill="none" stroke="#000000" d="M287.7146,-72.5708C291.9597,-64.0807 297.1536,-53.6929 301.8663,-44.2674"/><polygon fill="#000000" stroke="#000000" points="305.024,-45.7782 306.3657,-35.2687 298.763,-42.6477 305.024,-45.7782"/></g><!-- Symbol(y)_(1, 1, 2) --><g id="node12" class="node"><title>Symbol(y)_(1, 1, 2)</title><ellipse fill="none" stroke="#000000" cx="387" cy="-18" rx="27" ry="18"/><text text-anchor="middle" x="387" y="-14.3" font-family="Times,serif" font-size="14.00" fill="#000000">y</text></g><!-- Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Symbol(y)_(1, 1, 2) --><g id="edge11" class="edge"><title>Add(Integer(5), Symbol(x), Symbol(y))_(1, 1)&#45;&gt;Symbol(y)_(1, 1, 2)</title><path fill="none" stroke="#000000" d="M298.3082,-77.1278C315.3555,-65.763 340.4019,-49.0654 359.5344,-36.3104"/><polygon fill="#000000" stroke="#000000" points="361.4799,-39.2199 367.8589,-30.7607 357.5969,-33.3956 361.4799,-39.2199"/></g></g></svg>)
<graphviz.files.Source at 0x7fc7dc51b2e8>
<graphviz.files.Source at 0x7ff8a018e7f0>
%% Cell type:markdown id: tags:
Programatically the children node type is acessible as ``expr.func`` and its children as ``expr.args``.
With these members a tree can be traversed and modified.
......@@ -482,12 +482,12 @@
ps.to_dot(ast, graph_style={'size': "9.5,12.5"})
```
%%%% Output: execute_result
![](data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN""http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- Generated by graphviz version 2.40.1 (20161225.0304)--><!-- Title: %3 Pages: 1 --><svg width="684pt" height="468pt"viewBox="0.00 0.00 684.00 467.74" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="graph0" class="graph" transform="scale(.9826 .9826) rotate(0) translate(4 472)"><title>%3</title><polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-472 692.083,-472 692.083,4 -4,4"/><!-- 140495254316984 --><g id="node1" class="node"><title>140495254316984</title><ellipse fill="#a056db" stroke="#000000" cx="219.8449" cy="-450" rx="107.781" ry="18"/><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></g><!-- 140495254318440 --><g id="node11" class="node"><title>140495254318440</title><ellipse fill="#dbc256" stroke="#000000" cx="219.8449" cy="-378" rx="31.6951" ry="18"/><text text-anchor="middle" x="219.8449" y="-374.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140495254316984&#45;&gt;140495254318440 --><g id="edge10" class="edge"><title>140495254316984&#45;&gt;140495254318440</title><path fill="none" stroke="#000000" d="M219.8449,-431.8314C219.8449,-424.131 219.8449,-414.9743 219.8449,-406.4166"/><polygon fill="#000000" stroke="#000000" points="223.345,-406.4132 219.8449,-396.4133 216.345,-406.4133 223.345,-406.4132"/></g><!-- 140495254317656 --><g id="node2" class="node"><title>140495254317656</title><ellipse fill="#56db7f" stroke="#000000" cx="144.8449" cy="-306" rx="61.99" ry="18"/><text text-anchor="middle" x="144.8449" y="-302.3" font-family="Times,serif" font-size="14.00" fill="#000000">_data_img_22</text></g><!-- 140495254316256 --><g id="node3" class="node"><title>140495254316256</title><ellipse fill="#3498db" stroke="#000000" cx="295.8449" cy="-306" rx="70.6878" ry="18"/><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></g><!-- 140495254316032 --><g id="node10" class="node"><title>140495254316032</title><ellipse fill="#dbc256" stroke="#000000" cx="295.8449" cy="-234" rx="31.6951" ry="18"/><text text-anchor="middle" x="295.8449" y="-230.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140495254316256&#45;&gt;140495254316032 --><g id="edge7" class="edge"><title>140495254316256&#45;&gt;140495254316032</title><path fill="none" stroke="#000000" d="M295.8449,-287.8314C295.8449,-280.131 295.8449,-270.9743 295.8449,-262.4166"/><polygon fill="#000000" stroke="#000000" points="299.345,-262.4132 295.8449,-252.4133 292.345,-262.4133 299.345,-262.4132"/></g><!-- 140495254318496 --><g id="node4" class="node"><title>140495254318496</title><ellipse fill="#56db7f" stroke="#000000" cx="57.8449" cy="-162" rx="57.6901" ry="18"/><text text-anchor="middle" x="57.8449" y="-158.3" font-family="Times,serif" font-size="14.00" fill="#000000">_data_dst_00</text></g><!-- 140495254316592 --><g id="node5" class="node"><title>140495254316592</title><ellipse fill="#56db7f" stroke="#000000" cx="208.8449" cy="-162" rx="74.9875" ry="18"/><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></g><!-- 140495254317320 --><g id="node6" class="node"><title>140495254317320</title><ellipse fill="#56db7f" stroke="#000000" cx="383.8449" cy="-162" rx="81.7856" ry="18"/><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></g><!-- 140495254318664 --><g id="node7" class="node"><title>140495254318664</title><ellipse fill="#3498db" stroke="#000000" cx="554.8449" cy="-162" rx="70.6878" ry="18"/><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></g><!-- 140495254318776 --><g id="node9" class="node"><title>140495254318776</title><ellipse fill="#dbc256" stroke="#000000" cx="554.8449" cy="-90" rx="31.6951" ry="18"/><text text-anchor="middle" x="554.8449" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140495254318664&#45;&gt;140495254318776 --><g id="edge2" class="edge"><title>140495254318664&#45;&gt;140495254318776</title><path fill="none" stroke="#000000" d="M554.8449,-143.8314C554.8449,-136.131 554.8449,-126.9743 554.8449,-118.4166"/><polygon fill="#000000" stroke="#000000" points="558.345,-118.4132 554.8449,-108.4133 551.345,-118.4133 558.345,-118.4132"/></g><!-- 140495254317040 --><g id="node8" class="node"><title>140495254317040</title><ellipse fill="#56db7f" stroke="#000000" cx="554.8449" cy="-18" rx="133.4768" ry="18"/><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></g><!-- 140495254318776&#45;&gt;140495254317040 --><g id="edge1" class="edge"><title>140495254318776&#45;&gt;140495254317040</title><path fill="none" stroke="#000000" d="M554.8449,-71.8314C554.8449,-64.131 554.8449,-54.9743 554.8449,-46.4166"/><polygon fill="#000000" stroke="#000000" points="558.345,-46.4132 554.8449,-36.4133 551.345,-46.4133 558.345,-46.4132"/></g><!-- 140495254316032&#45;&gt;140495254318496 --><g id="edge3" class="edge"><title>140495254316032&#45;&gt;140495254318496</title><path fill="none" stroke="#000000" d="M267.6085,-225.4579C228.6723,-213.6789 157.8187,-192.2442 109.3243,-177.5736"/><polygon fill="#000000" stroke="#000000" points="110.2227,-174.1888 99.6376,-174.6432 108.1957,-180.8889 110.2227,-174.1888"/></g><!-- 140495254316032&#45;&gt;140495254316592 --><g id="edge4" class="edge"><title>140495254316032&#45;&gt;140495254316592</title><path fill="none" stroke="#000000" d="M277.8184,-219.0816C266.2777,-209.5306 251.0436,-196.9231 237.8284,-185.9864"/><polygon fill="#000000" stroke="#000000" points="239.8475,-183.1143 229.9121,-179.4349 235.3845,-188.507 239.8475,-183.1143"/></g><!-- 140495254316032&#45;&gt;140495254317320 --><g id="edge5" class="edge"><title>140495254316032&#45;&gt;140495254317320</title><path fill="none" stroke="#000000" d="M314.0785,-219.0816C325.7519,-209.5306 341.1611,-196.9231 354.5282,-185.9864"/><polygon fill="#000000" stroke="#000000" points="357.0123,-188.4762 362.5355,-179.4349 352.5796,-183.0585 357.0123,-188.4762"/></g><!-- 140495254316032&#45;&gt;140495254318664 --><g id="edge6" class="edge"><title>140495254316032&#45;&gt;140495254318664</title><path fill="none" stroke="#000000" d="M324.552,-226.0196C365.9645,-214.5073 443.366,-192.9903 496.9349,-178.0985"/><polygon fill="#000000" stroke="#000000" points="497.9488,-181.4495 506.646,-175.3989 496.0739,-174.7052 497.9488,-181.4495"/></g><!-- 140495254318440&#45;&gt;140495254317656 --><g id="edge8" class="edge"><title>140495254318440&#45;&gt;140495254317656</title><path fill="none" stroke="#000000" d="M203.571,-362.3771C193.8398,-353.0351 181.2651,-340.9635 170.2498,-330.3888"/><polygon fill="#000000" stroke="#000000" points="172.5648,-327.7594 162.9271,-323.3589 167.7171,-332.8091 172.5648,-327.7594"/></g><!-- 140495254318440&#45;&gt;140495254316256 --><g id="edge9" class="edge"><title>140495254318440&#45;&gt;140495254316256</title><path fill="none" stroke="#000000" d="M236.3357,-362.3771C246.1257,-353.1023 258.7558,-341.137 269.86,-330.6172"/><polygon fill="#000000" stroke="#000000" points="272.3977,-333.0344 277.2501,-323.6161 267.5835,-327.9527 272.3977,-333.0344"/></g></g></svg>)
<graphviz.files.Source at 0x7fc798393fd0>
![](data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN""http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- Generated by graphviz version 2.40.1 (20161225.0304)--><!-- Title: %3 Pages: 1 --><svg width="684pt" height="468pt"viewBox="0.00 0.00 684.00 467.74" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="graph0" class="graph" transform="scale(.9826 .9826) rotate(0) translate(4 472)"><title>%3</title><polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-472 692.083,-472 692.083,4 -4,4"/><!-- 140704680405368 --><g id="node1" class="node"><title>140704680405368</title><ellipse fill="#a056db" stroke="#000000" cx="219.8449" cy="-450" rx="107.781" ry="18"/><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></g><!-- 140704680405256 --><g id="node11" class="node"><title>140704680405256</title><ellipse fill="#dbc256" stroke="#000000" cx="219.8449" cy="-378" rx="31.6951" ry="18"/><text text-anchor="middle" x="219.8449" y="-374.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140704680405368&#45;&gt;140704680405256 --><g id="edge10" class="edge"><title>140704680405368&#45;&gt;140704680405256</title><path fill="none" stroke="#000000" d="M219.8449,-431.8314C219.8449,-424.131 219.8449,-414.9743 219.8449,-406.4166"/><polygon fill="#000000" stroke="#000000" points="223.345,-406.4132 219.8449,-396.4133 216.345,-406.4133 223.345,-406.4132"/></g><!-- 140704680405032 --><g id="node2" class="node"><title>140704680405032</title><ellipse fill="#56db7f" stroke="#000000" cx="144.8449" cy="-306" rx="61.99" ry="18"/><text text-anchor="middle" x="144.8449" y="-302.3" font-family="Times,serif" font-size="14.00" fill="#000000">_data_img_22</text></g><!-- 140704680404416 --><g id="node3" class="node"><title>140704680404416</title><ellipse fill="#3498db" stroke="#000000" cx="295.8449" cy="-306" rx="70.6878" ry="18"/><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></g><!-- 140704680404080 --><g id="node10" class="node"><title>140704680404080</title><ellipse fill="#dbc256" stroke="#000000" cx="295.8449" cy="-234" rx="31.6951" ry="18"/><text text-anchor="middle" x="295.8449" y="-230.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140704680404416&#45;&gt;140704680404080 --><g id="edge7" class="edge"><title>140704680404416&#45;&gt;140704680404080</title><path fill="none" stroke="#000000" d="M295.8449,-287.8314C295.8449,-280.131 295.8449,-270.9743 295.8449,-262.4166"/><polygon fill="#000000" stroke="#000000" points="299.345,-262.4132 295.8449,-252.4133 292.345,-262.4133 299.345,-262.4132"/></g><!-- 140704681164528 --><g id="node4" class="node"><title>140704681164528</title><ellipse fill="#56db7f" stroke="#000000" cx="57.8449" cy="-162" rx="57.6901" ry="18"/><text text-anchor="middle" x="57.8449" y="-158.3" font-family="Times,serif" font-size="14.00" fill="#000000">_data_dst_00</text></g><!-- 140704680403520 --><g id="node5" class="node"><title>140704680403520</title><ellipse fill="#56db7f" stroke="#000000" cx="208.8449" cy="-162" rx="74.9875" ry="18"/><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></g><!-- 140704680403352 --><g id="node6" class="node"><title>140704680403352</title><ellipse fill="#56db7f" stroke="#000000" cx="383.8449" cy="-162" rx="81.7856" ry="18"/><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></g><!-- 140704680404024 --><g id="node7" class="node"><title>140704680404024</title><ellipse fill="#3498db" stroke="#000000" cx="554.8449" cy="-162" rx="70.6878" ry="18"/><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></g><!-- 140704680404360 --><g id="node9" class="node"><title>140704680404360</title><ellipse fill="#dbc256" stroke="#000000" cx="554.8449" cy="-90" rx="31.6951" ry="18"/><text text-anchor="middle" x="554.8449" y="-86.3" font-family="Times,serif" font-size="14.00" fill="#000000">Block</text></g><!-- 140704680404024&#45;&gt;140704680404360 --><g id="edge2" class="edge"><title>140704680404024&#45;&gt;140704680404360</title><path fill="none" stroke="#000000" d="M554.8449,-143.8314C554.8449,-136.131 554.8449,-126.9743 554.8449,-118.4166"/><polygon fill="#000000" stroke="#000000" points="558.345,-118.4132 554.8449,-108.4133 551.345,-118.4133 558.345,-118.4132"/></g><!-- 140704680403968 --><g id="node8" class="node"><title>140704680403968</title><ellipse fill="#56db7f" stroke="#000000" cx="554.8449" cy="-18" rx="133.4768" ry="18"/><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></g><!-- 140704680404360&#45;&gt;140704680403968 --><g id="edge1" class="edge"><title>140704680404360&#45;&gt;140704680403968</title><path fill="none" stroke="#000000" d="M554.8449,-71.8314C554.8449,-64.131 554.8449,-54.9743 554.8449,-46.4166"/><polygon fill="#000000" stroke="#000000" points="558.345,-46.4132 554.8449,-36.4133 551.345,-46.4133 558.345,-46.4132"/></g><!-- 140704680404080&#45;&gt;140704681164528 --><g id="edge3" class="edge"><title>140704680404080&#45;&gt;140704681164528</title><path fill="none" stroke="#000000" d="M267.6085,-225.4579C228.6723,-213.6789 157.8187,-192.2442 109.3243,-177.5736"/><polygon fill="#000000" stroke="#000000" points="110.2227,-174.1888 99.6376,-174.6432 108.1957,-180.8889 110.2227,-174.1888"/></g><!-- 140704680404080&#45;&gt;140704680403520 --><g id="edge4" class="edge"><title>140704680404080&#45;&gt;140704680403520</title><path fill="none" stroke="#000000" d="M277.8184,-219.0816C266.2777,-209.5306 251.0436,-196.9231 237.8284,-185.9864"/><polygon fill="#000000" stroke="#000000" points="239.8475,-183.1143 229.9121,-179.4349 235.3845,-188.507 239.8475,-183.1143"/></g><!-- 140704680404080&#45;&gt;140704680403352 --><g id="edge5" class="edge"><title>140704680404080&#45;&gt;140704680403352</title><path fill="none" stroke="#000000" d="M314.0785,-219.0816C325.7519,-209.5306 341.1611,-196.9231 354.5282,-185.9864"/><polygon fill="#000000" stroke="#000000" points="357.0123,-188.4762 362.5355,-179.4349 352.5796,-183.0585 357.0123,-188.4762"/></g><!-- 140704680404080&#45;&gt;140704680404024 --><g id="edge6" class="edge"><title>140704680404080&#45;&gt;140704680404024</title><path fill="none" stroke="#000000" d="M324.552,-226.0196C365.9645,-214.5073 443.366,-192.9903 496.9349,-178.0985"/><polygon fill="#000000" stroke="#000000" points="497.9488,-181.4495 506.646,-175.3989 496.0739,-174.7052 497.9488,-181.4495"/></g><!-- 140704680405256&#45;&gt;140704680405032 --><g id="edge8" class="edge"><title>140704680405256&#45;&gt;140704680405032</title><path fill="none" stroke="#000000" d="M203.571,-362.3771C193.8398,-353.0351 181.2651,-340.9635 170.2498,-330.3888"/><polygon fill="#000000" stroke="#000000" points="172.5648,-327.7594 162.9271,-323.3589 167.7171,-332.8091 172.5648,-327.7594"/></g><!-- 140704680405256&#45;&gt;140704680404416 --><g id="edge9" class="edge"><title>140704680405256&#45;&gt;140704680404416</title><path fill="none" stroke="#000000" d="M236.3357,-362.3771C246.1257,-353.1023 258.7558,-341.137 269.86,-330.6172"/><polygon fill="#000000" stroke="#000000" points="272.3977,-333.0344 277.2501,-323.6161 267.5835,-327.9527 272.3977,-333.0344"/></g></g></svg>)
<graphviz.files.Source at 0x7ff84a432e10>
%% Cell type:markdown id: tags:
*pystencils* also builds a tree structure of the program, where each `Assignment` node internally again has a *sympy* AST which is not printed here. Out of this representation *C* code can be generated:
......
......@@ -106,13 +106,12 @@
``` python
if 'is_test_run' in globals():
timeloop(10)
result = None
else:
ps_notebook.set_display_mode('video')
ani = ps.plot2d.scalar_field_animation(timeloop, rescale=True, frames=300)
result = ps_notebook.display_animation(ani)
ani = ps.plot.scalar_field_animation(timeloop, rescale=True, frames=300)
result = ps.jupyter.display_as_html_video(ani)
result
```
%%%% Output: execute_result
......
This diff is collapsed.
This diff is collapsed.
......@@ -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:
y_range = list(range(-max_offsets[1], max_offsets[1] + 1))
if matrix_form:
y_range.reverse()
if dim == 2:
result = [[coefficients[(i, j)]
result = [[coeffs[(i, j)]
for i in range(-max_offsets[0], max_offsets[0] + 1)]
for j in y_range]
return sp.Matrix(result) if matrix_form else result
elif dim == 3:
result = [[[coefficients[(i, j, k)]
result = [[[coeffs[(i, j, k)]
for i in range(-max_offsets[0], max_offsets[0] + 1)]
for j in y_range]
for k in range(-max_offsets[2], max_offsets[2] + 1)]
......@@ -256,10 +285,10 @@ def direction_string_to_offset(direction: str, dim: int = 3):
# -------------------------------------- Visualization -----------------------------------------------------------------
def visualize_stencil(stencil, **kwargs):
def plot(stencil, **kwargs):
dim = len(stencil[0])
if dim == 2:
visualize_stencil_2d(stencil, **kwargs)
plot_2d(stencil, **kwargs)
else:
slicing = False
if 'slice' in kwargs:
......@@ -267,12 +296,12 @@ def visualize_stencil(stencil, **kwargs):
del kwargs['slice']
if slicing:
visualize_stencil_3d_by_slicing(stencil, **kwargs)
plot_3d_slicing(stencil, **kwargs)
else:
visualize_stencil_3d(stencil, **kwargs)
plot_3d(stencil, **kwargs)
def visualize_stencil_2d(stencil, axes=None, figure=None, data=None, textsize='12', **kwargs):
def plot_2d(stencil, axes=None, figure=None, data=None, textsize='12', **kwargs):
"""
Creates a matplotlib 2D plot of the stencil
......@@ -328,7 +357,7 @@ def visualize_stencil_2d(stencil, axes=None, figure=None, data=None, textsize='1
axes.set_ylim([-border - max_offsets[1], border + max_offsets[1]])
def visualize_stencil_3d_by_slicing(stencil, slice_axis=2, figure=None, data=None, **kwargs):
def plot_3d_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:
......@@ -357,12 +386,12 @@ def visualize_stencil_3d_by_slicing(stencil, slice_axis=2, figure=None, data=Non
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)
plot_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))
axes[i + 1].set_title("Cut at %s=%d" % (axes_names[slice_axis], i), y=1.08)
def visualize_stencil_3d(stencil, figure=None, axes=None, data=None, textsize='8'):
def plot_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)))``
......@@ -434,14 +463,14 @@ def visualize_stencil_3d(stencil, figure=None, axes=None, data=None, textsize='8
axes.set_axis_off()
def visualize_stencil_expression(expr, **kwargs):
def plot_expression(expr, **kwargs):
"""Displays coefficients of a linear update expression of a single field as matplotlib arrow drawing."""
stencil, coefficients = stencil_coefficients(expr)
stencil, coeffs = coefficients(expr)
dim = len(stencil[0])
assert 0 < dim <= 3
if dim == 1:
return stencil_coefficient_list(expr, matrix_form=True)
return coefficient_list(expr, matrix_form=True)
elif dim == 2:
return visualize_stencil_2d(stencil, data=coefficients, **kwargs)
return plot_2d(stencil, data=coeffs, **kwargs)
elif dim == 3:
return visualize_stencil_3d_by_slicing(stencil, data=coefficients, **kwargs)
return plot_3d_slicing(stencil, data=coeffs, **kwargs)
......@@ -3,7 +3,7 @@
import numpy as np
from pystencils import Field, FieldType, Assignment, create_kernel
from pystencils.field import layout_string_to_tuple, create_numpy_array_with_layout
from pystencils.stencils import direction_string_to_offset
from pystencils.stencil import direction_string_to_offset
from pystencils.slicing import add_ghost_layers, get_slice_before_ghost_layer, get_ghost_region_slice
......
......@@ -3,7 +3,7 @@
import numpy as np
from pystencils import Field, FieldType, Assignment
from pystencils.field import layout_string_to_tuple, create_numpy_array_with_layout
from pystencils.stencils import direction_string_to_offset
from pystencils.stencil import direction_string_to_offset
from pystencils.gpucuda import make_python_function, create_cuda_kernel
from pystencils.slicing import add_ghost_layers, get_slice_before_ghost_layer, get_ghost_region_slice
import pytest
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment