diff --git a/docs/Makefile b/docs/Makefile
index 2cfffacd09eadf196e4a978e8d503616e7bbecc7..55c0a3c56fac57e573339a9c24c7881d681379a9 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -23,3 +23,8 @@ clean:
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
 %: Makefile
 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+clean:
+	rm -rf source/reference/generated
+	rm -rf source/backend/generated
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
\ No newline at end of file
diff --git a/docs/source/_static/img/pystencils-logo-dark.svg b/docs/source/_static/img/pystencils-logo-dark.svg
index 28c8bcaab7dc8b236768fbc5d8d7f185439c0b43..aeb209218373402703529f3e318a9b58b2a67813 100644
--- a/docs/source/_static/img/pystencils-logo-dark.svg
+++ b/docs/source/_static/img/pystencils-logo-dark.svg
@@ -29,8 +29,8 @@
      inkscape:zoom="4"
      inkscape:cx="73.125"
      inkscape:cy="102.5"
-     inkscape:window-width="1920"
-     inkscape:window-height="1039"
+     inkscape:window-width="2560"
+     inkscape:window-height="1399"
      inkscape:window-x="0"
      inkscape:window-y="0"
      inkscape:window-maximized="1"
@@ -444,18 +444,10 @@
          style="fill:#999999;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4632-1-4)"
          inkscape:label="circle-R" />
     </g>
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11667px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="-4.7506952"
-       y="47.69986"
+    <path
+       style="font-weight:bold;font-size:9.525px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';letter-spacing:0px;word-spacing:0px;fill:#cccccc;stroke-width:0.264583px"
+       d="m -0.08344542,45.62341 c 0,-1.190625 -0.86677496,-2.124075 -1.88594988,-2.124075 -0.409575,0 -0.8001,0.13335 -1.114425,0.371475 -0.00953,-0.219075 -0.09525,-0.32385 -0.43815,-0.32385 h -0.676275 c -0.1809749,0 -0.4571999,0.01905 -0.4571999,0.36195 0,0.3429 0.28575,0.352425 0.4476749,0.352425 h 0.3429 v 4.78155 h -0.333375 c -0.1809749,0 -0.4571999,0.0095 -0.4571999,0.36195 0,0.3429 0.28575,0.352425 0.4476749,0.352425 h 1.476375 c 0.161925,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.276225,-0.36195 -0.4572,-0.36195 h -0.333375 V 47.37601 c 0.36195,0.314325 0.7239,0.381 1.000125,0.381 1.0477499,0 1.99072488,-0.9144 1.99072488,-2.1336 z m -0.78104996,0 c 0,0.8382 -0.60960002,1.419225 -1.22872492,1.419225 -0.676275,0 -0.97155,-0.771525 -0.97155,-1.190625 v -0.676275 c 0,-0.51435 0.504825,-0.962025 1.04775,-0.962025 0.6476999,0 1.15252492,0.6477 1.15252492,1.4097 z m 5.89597128,-1.7145 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 H 3.497951 c -0.17145,0 -0.447675,0.01905 -0.447675,0.352425 0,0.352425 0.2667,0.36195 0.447675,0.36195 h 0.1524 L 2.831201,46.74736 1.888226,44.261335 h 0.123825 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 H 0.92620106 c -0.18097499,0 -0.44767498,0.0095 -0.44767498,0.36195 0,0.3429 0.27622499,0.352425 0.44767498,0.352425 H 1.1643261 L 2.497826,47.62366 c -0.0381,0.104775 -0.238125,0.771525 -0.3429,0.981075 -0.1905,0.36195 -0.485775,0.581025 -0.66675,0.581025 0.00953,-0.0381 0.104775,-0.06668 0.104775,-0.20955 0,-0.276225 -0.200025,-0.47625 -0.4762499,-0.47625 -0.29527503,0 -0.47625003,0.200025 -0.47625003,0.47625 0,0.428625 0.34289999,0.8382 0.83819993,0.8382 0.9525,0 1.419225,-1.266825 1.457325,-1.3716 l 1.4192249,-4.181475 h 0.2286 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 z m 4.6196213,2.5527 c 0,-1.00965 -1.2477749,-1.228725 -1.5620999,-1.27635 l -0.962025,-0.17145 c -0.24765,-0.05715 -0.5048249,-0.161925 -0.5048249,-0.381 0,-0.219075 0.2952749,-0.447675 1.1048999,-0.447675 0.695325,0 0.828675,0.2286 0.85725,0.447675 0.00953,0.1905 0.0381,0.381 0.390525,0.381 0.3905249,0 0.4000499,-0.2286 0.4000499,-0.447675 v -0.6477 c 0,-0.180975 -0.01905,-0.447675 -0.3524249,-0.447675 -0.20955,0 -0.28575,0.08573 -0.32385,0.161925 -0.40005,-0.161925 -0.78105,-0.161925 -0.9525,-0.161925 -1.6287749,0 -1.8383249,0.81915 -1.8383249,1.16205 0,0.89535 1.0001249,1.08585 1.8954749,1.2192 0.4191,0.06668 1.133475,0.180975 1.133475,0.6096 0,0.32385 -0.333375,0.581025 -1.114425,0.581025 -0.409575,0 -0.89535,-0.09525 -1.1144249,-0.771525 -0.05715,-0.20955 -0.104775,-0.32385 -0.40005,-0.32385 -0.390525,0 -0.40005,0.2286 -0.40005,0.4572 v 0.89535 c 0,0.180975 0.00953,0.4572 0.352425,0.4572 0.09525,0 0.257175,0 0.381,-0.314325 0.4476749,0.295275 0.9143999,0.314325 1.1715749,0.314325 1.5335249,0 1.8383249,-0.828675 1.8383249,-1.2954 z m 4.8958458,-0.0095 c 0,-0.200025 0,-0.428625 -0.40005,-0.428625 -0.371475,0 -0.381,0.2286 -0.381,0.4191 -0.0095,0.51435 -0.485775,0.600075 -0.6858,0.600075 -0.638175,0 -0.638175,-0.43815 -0.638175,-0.638175 v -2.143125 h 1.4478 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -1.4478 v -0.6858 c 0,-0.20955 -0.0095,-0.447675 -0.390525,-0.447675 -0.390525,0 -0.40005,0.2286 -0.40005,0.447675 v 0.6858 h -0.733425 c -0.180975,0 -0.447675,0.01905 -0.447675,0.36195 0,0.3429 0.2667,0.352425 0.43815,0.352425 h 0.74295 v 2.19075 c 0,0.942975 0.66675,1.304925 1.39065,1.304925 0.7239,0 1.50495,-0.428625 1.50495,-1.304925 z m 5.153022,0.161925 c 0,-0.32385 -0.333375,-0.333375 -0.40005,-0.333375 -0.20955,0 -0.295275,0.0381 -0.381,0.24765 -0.1905,0.43815 -0.657225,0.51435 -0.89535,0.51435 -0.638175,0 -1.27635,-0.409575 -1.4478,-1.114425 h 2.676525 c 0.238125,0 0.447675,0 0.447675,-0.4191 0,-1.095375 -0.62865,-2.03835 -1.876425,-2.03835 -1.143,0 -2.07645,0.962025 -2.07645,2.143125 0,1.171575 0.97155,2.143125 2.2098,2.143125 1.2954,0 1.743075,-0.89535 1.743075,-1.143 z m -0.81915,-1.39065 H 16.58529 c 0.1524,-0.600075 0.6477,-1.038225 1.23825,-1.038225 0.43815,0 0.9525,0.20955 1.057275,1.038225 z m 6.257922,2.124075 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -0.333375 v -2.07645 c 0,-0.9906 -0.504825,-1.4097 -1.285875,-1.4097 -0.5334,0 -0.9144,0.219075 -1.143,0.40005 -0.0095,-0.238125 -0.0762,-0.352425 -0.447675,-0.352425 h -0.676275 c -0.180975,0 -0.447675,0.01905 -0.447675,0.36195 0,0.3429 0.28575,0.352425 0.43815,0.352425 h 0.3429 v 2.72415 h -0.333375 c -0.180975,0 -0.447675,0.0095 -0.447675,0.36195 0,0.3429 0.28575,0.352425 0.43815,0.352425 h 1.476375 c 0.161925,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.276225,-0.36195 -0.4572,-0.36195 H 21.928812 V 45.41386 c 0,-0.866775 0.6477,-1.20015 1.08585,-1.20015 0.447675,0 0.55245,0.238125 0.55245,0.74295 v 2.028825 h -0.28575 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.295275,0.352425 0.4572,0.352425 h 1.419225 c 0.1524,0 0.43815,-0.0095 0.43815,-0.352425 z m 4.58152,-0.733425 c 0,-0.32385 -0.333375,-0.333375 -0.40005,-0.333375 -0.180975,0 -0.295275,0.01905 -0.381,0.24765 -0.04763,0.1143 -0.238125,0.51435 -0.847725,0.51435 -0.74295,0 -1.381125,-0.619125 -1.381125,-1.419225 0,-0.428625 0.24765,-1.438275 1.438275,-1.438275 l 0.485775,0.0095 c 0.0095,0.381 0.219075,0.523875 0.47625,0.523875 0.2667,0 0.4953,-0.180975 0.4953,-0.4953 0,-0.7239 -1.00965,-0.752475 -1.457325,-0.752475 -1.647825,0 -2.22885,1.304925 -2.22885,2.15265 0,1.152525 0.904875,2.1336 2.11455,2.1336 1.362075,0 1.685925,-0.981075 1.685925,-1.143 z m 4.895846,0.733425 c 0,-0.352425 -0.28575,-0.36195 -0.4572,-0.36195 h -0.89535 V 44.00416 c 0,-0.3429 -0.06668,-0.4572 -0.447675,-0.4572 h -1.31445 c -0.17145,0 -0.4572,0.01905 -0.4572,0.352425 0,0.352425 0.28575,0.36195 0.4572,0.36195 h 0.97155 v 2.72415 h -1.04775 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.4572,0.352425 h 2.733675 c 0.17145,0 0.4572,-0.0095 0.4572,-0.352425 z m -1.31445,-4.886325 c 0,-0.295275 -0.238125,-0.5334 -0.542925,-0.5334 -0.3048,0 -0.542925,0.238125 -0.542925,0.5334 0,0.3048 0.238125,0.542925 0.542925,0.542925 0.3048,0 0.542925,-0.238125 0.542925,-0.542925 z m 6.429372,4.886325 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -1.133475 v -4.6482 c 0,-0.3429 -0.06668,-0.4572 -0.447675,-0.4572 h -1.46685 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 H 37.3593 v 4.391025 h -1.12395 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 h 3.057525 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 z m 4.924422,-0.885825 c 0,-1.00965 -1.247775,-1.228725 -1.5621,-1.27635 l -0.962025,-0.17145 c -0.24765,-0.05715 -0.504825,-0.161925 -0.504825,-0.381 0,-0.219075 0.295275,-0.447675 1.1049,-0.447675 0.695325,0 0.828675,0.2286 0.85725,0.447675 0.0095,0.1905 0.0381,0.381 0.390525,0.381 0.390525,0 0.40005,-0.2286 0.40005,-0.447675 v -0.6477 c 0,-0.180975 -0.01905,-0.447675 -0.352425,-0.447675 -0.20955,0 -0.28575,0.08573 -0.32385,0.161925 -0.40005,-0.161925 -0.78105,-0.161925 -0.9525,-0.161925 -1.628775,0 -1.838325,0.81915 -1.838325,1.16205 0,0.89535 1.000125,1.08585 1.895475,1.2192 0.4191,0.06668 1.133475,0.180975 1.133475,0.6096 0,0.32385 -0.333375,0.581025 -1.114425,0.581025 -0.409575,0 -0.89535,-0.09525 -1.114425,-0.771525 -0.05715,-0.20955 -0.104775,-0.32385 -0.40005,-0.32385 -0.390525,0 -0.40005,0.2286 -0.40005,0.4572 v 0.89535 c 0,0.180975 0.0095,0.4572 0.352425,0.4572 0.09525,0 0.257175,0 0.381,-0.314325 0.447675,0.295275 0.9144,0.314325 1.171575,0.314325 1.533525,0 1.838325,-0.828675 1.838325,-1.2954 z"
        id="text1392-1"
-       inkscape:export-xdpi="70.669998"
-       inkscape:export-ydpi="70.669998"><tspan
-         sodipodi:role="line"
-         id="tspan1390-1"
-         x="-4.7506952"
-         y="47.69986"
-         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:9.525px;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#cccccc;fill-opacity:1;stroke-width:0.264583px">pystencils</tspan></text>
+       aria-label="pystencils" />
   </g>
 </svg>
diff --git a/docs/source/_static/img/pystencils-logo-light.svg b/docs/source/_static/img/pystencils-logo-light.svg
index 519a4816aa4b660364ddd498b535554c24f900bb..c59a25519edd719586d66f91b6c05ba14b3db9c3 100644
--- a/docs/source/_static/img/pystencils-logo-light.svg
+++ b/docs/source/_static/img/pystencils-logo-light.svg
@@ -27,10 +27,10 @@
      inkscape:lockguides="false"
      showgrid="false"
      inkscape:zoom="2.8284271"
-     inkscape:cx="33.410795"
-     inkscape:cy="140.00714"
-     inkscape:window-width="1920"
-     inkscape:window-height="1039"
+     inkscape:cx="33.410796"
+     inkscape:cy="139.65359"
+     inkscape:window-width="2560"
+     inkscape:window-height="1399"
      inkscape:window-x="0"
      inkscape:window-y="0"
      inkscape:window-maximized="1"
@@ -446,20 +446,12 @@
            style="fill:#999999;fill-opacity:1;stroke:none;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4632-1-4)"
            inkscape:label="circle-R" />
       </g>
-      <text
-         xml:space="preserve"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11667px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#252525;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         x="-4.7508764"
-         y="47.699944"
+      <path
+         style="font-weight:bold;font-size:9.525px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';letter-spacing:0px;word-spacing:0px;fill:#252525;stroke-width:0.264583px"
+         d="m -0.08362661,45.623494 c 0,-1.190625 -0.86677497,-2.124075 -1.88594989,-2.124075 -0.409575,0 -0.8001,0.13335 -1.114425,0.371475 -0.00953,-0.219075 -0.09525,-0.32385 -0.43815,-0.32385 h -0.6762749 c -0.180975,0 -0.4572,0.01905 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 h 0.3428999 v 4.781549 h -0.3333749 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 h 1.4763749 c 0.161925,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.276225,-0.36195 -0.4572,-0.36195 h -0.333375 v -1.666874 c 0.36195,0.314325 0.7239,0.381 1.000125,0.381 1.0477499,0 1.99072489,-0.9144 1.99072489,-2.1336 z m -0.78104997,0 c 0,0.8382 -0.60960002,1.419225 -1.22872492,1.419225 -0.676275,0 -0.97155,-0.771525 -0.97155,-1.190625 v -0.676275 c 0,-0.51435 0.504825,-0.962025 1.04775,-0.962025 0.6476999,0 1.15252492,0.6477 1.15252492,1.4097 z m 5.89597128,-1.7145 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 H 3.4977698 c -0.17145,0 -0.447675,0.01905 -0.447675,0.352425 0,0.352425 0.2667,0.36195 0.447675,0.36195 h 0.1524 l -0.81915,2.486025 -0.942975,-2.486025 h 0.123825 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 H 0.92601987 c -0.180975,0 -0.44767499,0.0095 -0.44767499,0.36195 0,0.3429 0.27622499,0.352425 0.44767499,0.352425 H 1.1641449 l 1.3334999,3.362325 c -0.0381,0.104775 -0.238125,0.771525 -0.3429,0.981075 -0.1905,0.361949 -0.485775,0.581024 -0.66675,0.581024 0.00953,-0.0381 0.104775,-0.06667 0.104775,-0.20955 0,-0.276224 -0.200025,-0.476249 -0.4762499,-0.476249 -0.29527503,0 -0.47625002,0.200025 -0.47625002,0.476249 0,0.428625 0.34289998,0.8382 0.83819992,0.8382 0.9525,0 1.419225,-1.266824 1.457325,-1.371599 l 1.4192249,-4.181475 h 0.2286 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 z m 4.6196213,2.5527 c 0,-1.00965 -1.2477749,-1.228725 -1.5620999,-1.27635 l -0.962025,-0.17145 c -0.24765,-0.05715 -0.5048249,-0.161925 -0.5048249,-0.381 0,-0.219075 0.2952749,-0.447675 1.1048999,-0.447675 0.695325,0 0.828675,0.2286 0.85725,0.447675 0.00953,0.1905 0.0381,0.381 0.390525,0.381 0.3905249,0 0.4000499,-0.2286 0.4000499,-0.447675 v -0.6477 c 0,-0.180975 -0.01905,-0.447675 -0.3524249,-0.447675 -0.20955,0 -0.28575,0.08573 -0.32385,0.161925 -0.40005,-0.161925 -0.78105,-0.161925 -0.9525,-0.161925 -1.6287749,0 -1.8383249,0.81915 -1.8383249,1.16205 0,0.89535 1.0001249,1.08585 1.8954749,1.2192 0.4191,0.06667 1.133475,0.180975 1.133475,0.6096 0,0.32385 -0.333375,0.581025 -1.114425,0.581025 -0.409575,0 -0.89535,-0.09525 -1.1144249,-0.771525 -0.05715,-0.20955 -0.104775,-0.32385 -0.40005,-0.32385 -0.390525,0 -0.40005,0.2286 -0.40005,0.4572 v 0.89535 c 0,0.180975 0.00953,0.4572 0.352425,0.4572 0.09525,0 0.257175,0 0.381,-0.314325 0.4476749,0.295275 0.9143999,0.314325 1.1715749,0.314325 1.5335249,0 1.8383249,-0.828675 1.8383249,-1.2954 z m 4.895846,-0.0095 c 0,-0.200025 0,-0.428625 -0.40005,-0.428625 -0.371475,0 -0.381,0.2286 -0.381,0.4191 -0.0095,0.51435 -0.485775,0.600075 -0.6858,0.600075 -0.638175,0 -0.638175,-0.43815 -0.638175,-0.638175 v -2.143125 h 1.4478 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -1.4478 v -0.6858 c 0,-0.20955 -0.0095,-0.447675 -0.390525,-0.447675 -0.390525,0 -0.40005,0.2286 -0.40005,0.447675 v 0.6858 h -0.733425 c -0.180975,0 -0.447675,0.01905 -0.447675,0.36195 0,0.3429 0.2667,0.352425 0.43815,0.352425 h 0.74295 v 2.19075 c 0,0.942975 0.66675,1.304925 1.39065,1.304925 0.7239,0 1.50495,-0.428625 1.50495,-1.304925 z m 5.153022,0.161925 c 0,-0.32385 -0.333375,-0.333375 -0.40005,-0.333375 -0.20955,0 -0.295275,0.0381 -0.381,0.24765 -0.1905,0.43815 -0.657225,0.51435 -0.89535,0.51435 -0.638175,0 -1.27635,-0.409575 -1.4478,-1.114425 h 2.676525 c 0.238125,0 0.447675,0 0.447675,-0.4191 0,-1.095375 -0.62865,-2.03835 -1.876425,-2.03835 -1.143,0 -2.07645,0.962025 -2.07645,2.143125 0,1.171575 0.97155,2.143125 2.2098,2.143125 1.2954,0 1.743075,-0.89535 1.743075,-1.143 z m -0.81915,-1.39065 h -2.295525 c 0.1524,-0.600075 0.6477,-1.038225 1.23825,-1.038225 0.43815,0 0.9525,0.20955 1.057275,1.038225 z m 6.257921,2.124075 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -0.333375 v -2.07645 c 0,-0.9906 -0.504824,-1.4097 -1.285874,-1.4097 -0.5334,0 -0.9144,0.219075 -1.143,0.40005 -0.0095,-0.238125 -0.0762,-0.352425 -0.447675,-0.352425 h -0.676275 c -0.180975,0 -0.447675,0.01905 -0.447675,0.36195 0,0.3429 0.28575,0.352425 0.43815,0.352425 h 0.3429 v 2.72415 h -0.333375 c -0.180975,0 -0.447675,0.0095 -0.447675,0.36195 0,0.3429 0.28575,0.352425 0.43815,0.352425 h 1.476375 c 0.161925,0 0.447675,-0.0095 0.447675,-0.352425 0,-0.352425 -0.276225,-0.36195 -0.4572,-0.36195 h -0.333375 v -1.571625 c 0,-0.866775 0.6477,-1.20015 1.08585,-1.20015 0.447675,0 0.55245,0.238125 0.55245,0.74295 v 2.028825 h -0.28575 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.295275,0.352425 0.4572,0.352425 h 1.419224 c 0.1524,0 0.43815,-0.0095 0.43815,-0.352425 z m 4.58152,-0.733425 c 0,-0.32385 -0.333375,-0.333375 -0.40005,-0.333375 -0.180975,0 -0.295275,0.01905 -0.381,0.24765 -0.04763,0.1143 -0.238125,0.51435 -0.847725,0.51435 -0.74295,0 -1.381125,-0.619125 -1.381125,-1.419225 0,-0.428625 0.24765,-1.438275 1.438275,-1.438275 l 0.485775,0.0095 c 0.0095,0.381 0.219075,0.523875 0.47625,0.523875 0.2667,0 0.4953,-0.180975 0.4953,-0.4953 0,-0.7239 -1.00965,-0.752475 -1.457325,-0.752475 -1.647825,0 -2.228849,1.304925 -2.228849,2.15265 0,1.152525 0.904874,2.1336 2.114549,2.1336 1.362075,0 1.685925,-0.981075 1.685925,-1.143 z m 4.895847,0.733425 c 0,-0.352425 -0.28575,-0.36195 -0.4572,-0.36195 h -0.89535 v -2.981325 c 0,-0.3429 -0.06667,-0.4572 -0.447675,-0.4572 h -1.31445 c -0.17145,0 -0.4572,0.01905 -0.4572,0.352425 0,0.352425 0.28575,0.36195 0.4572,0.36195 h 0.97155 v 2.72415 h -1.04775 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.4572,0.352425 h 2.733675 c 0.17145,0 0.4572,-0.0095 0.4572,-0.352425 z m -1.31445,-4.886325 c 0,-0.295275 -0.238125,-0.5334 -0.542925,-0.5334 -0.3048,0 -0.542925,0.238125 -0.542925,0.5334 0,0.3048 0.238125,0.542925 0.542925,0.542925 0.3048,0 0.542925,-0.238125 0.542925,-0.542925 z m 6.429372,4.886325 c 0,-0.352425 -0.2667,-0.36195 -0.447675,-0.36195 h -1.133475 v -4.6482 c 0,-0.3429 -0.06667,-0.4572 -0.447675,-0.4572 h -1.46685 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 h 1.133475 v 4.391025 h -1.12395 c -0.180975,0 -0.4572,0.0095 -0.4572,0.36195 0,0.3429 0.28575,0.352425 0.447675,0.352425 h 3.057525 c 0.17145,0 0.447675,-0.0095 0.447675,-0.352425 z m 4.924422,-0.885825 c 0,-1.00965 -1.247775,-1.228725 -1.5621,-1.27635 l -0.962025,-0.17145 c -0.24765,-0.05715 -0.504825,-0.161925 -0.504825,-0.381 0,-0.219075 0.295275,-0.447675 1.1049,-0.447675 0.695325,0 0.828675,0.2286 0.85725,0.447675 0.0095,0.1905 0.0381,0.381 0.390525,0.381 0.390525,0 0.40005,-0.2286 0.40005,-0.447675 v -0.6477 c 0,-0.180975 -0.01905,-0.447675 -0.352425,-0.447675 -0.20955,0 -0.28575,0.08573 -0.32385,0.161925 -0.40005,-0.161925 -0.78105,-0.161925 -0.9525,-0.161925 -1.628775,0 -1.838325,0.81915 -1.838325,1.16205 0,0.89535 1.000125,1.08585 1.895475,1.2192 0.4191,0.06667 1.133475,0.180975 1.133475,0.6096 0,0.32385 -0.333375,0.581025 -1.114425,0.581025 -0.409575,0 -0.89535,-0.09525 -1.114425,-0.771525 -0.05715,-0.20955 -0.104775,-0.32385 -0.40005,-0.32385 -0.390525,0 -0.40005,0.2286 -0.40005,0.4572 v 0.89535 c 0,0.180975 0.0095,0.4572 0.352425,0.4572 0.09525,0 0.257175,0 0.381,-0.314325 0.447675,0.295275 0.9144,0.314325 1.171575,0.314325 1.533525,0 1.838325,-0.828675 1.838325,-1.2954 z"
          id="text1392-1"
-         inkscape:export-xdpi="70.669998"
-         inkscape:export-ydpi="70.669998"
-         inkscape:label="text1392-1"><tspan
-           sodipodi:role="line"
-           id="tspan1390-1"
-           x="-4.7508764"
-           y="47.699944"
-           style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:9.525px;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#252525;fill-opacity:1;stroke-width:0.264583px">pystencils</tspan></text>
+         inkscape:label="text1392-1"
+         aria-label="pystencils" />
     </g>
   </g>
 </svg>
diff --git a/docs/source/installation.md b/docs/source/installation.md
index dcc5b04746e034724e50a15f4d79e541b2726652..cea0acd2feba1c45f2e73b0d52292a92aaa28d07 100644
--- a/docs/source/installation.md
+++ b/docs/source/installation.md
@@ -3,7 +3,7 @@
 
 ## Install pystencils
 
-The latest development version of *pystencils 2.0* in one of two ways.
+There are two ways to install the latest development version of pystencils 2.0.
 You can either install it directly from our git repository:
 
 ```bash
@@ -24,13 +24,14 @@ in square brackets (e.g. `pip install -e pystencils[feature1, feature2]`).
 The following feature sets are available:
 
 - `interactive` (**recommended**): Install dependencies for using pystencils interactively from
-  within Jupyter notebooks
+  within Jupyter notebooks.
+  Setting this flag will cause pip to install `jupyter`, `matplotlib`, and `graphviz`, among others, alongside pystencils.
 - `alltrafos` (**recommended**): Install dependencies to enable a wider set of code transformation.
   These include [islpy](https://pypi.org/project/islpy/) for polyhedral loop transformations,
   and [py-cpuinfo](https://pypi.org/project/py-cpuinfo/) for detecting the current hardware in order
   to select optimal vector instructions.
 - `use_cython`: Install [Cython](https://cython.org/), which is used internally by pystencils
-  to accelerate the setup of boundary conditions
+  to accelerate the setup of boundary conditions.
 
 :::{dropdown} For Developers
 
diff --git a/docs/source/reference/api/codegen.rst b/docs/source/reference/api/codegen.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6418f32f6fe6d78267a373150fe7a2257c5e0b97
--- /dev/null
+++ b/docs/source/reference/api/codegen.rst
@@ -0,0 +1,29 @@
+Code Generator and Configuration
+================================
+
+.. module:: pystencils.kernelcreation
+
+.. autosummary::
+  :toctree: generated
+  :nosignatures:
+
+  create_kernel
+
+.. module:: pystencils.config
+
+.. autosummary::
+  :toctree: generated
+  :nosignatures:
+  :template: autosummary/entire_class.rst
+
+  CreateKernelConfig
+  CpuOptimConfig
+  OpenMpConfig
+  VectorizationConfig
+  GpuIndexingConfig
+
+.. autosummary::
+  :toctree: generated
+  :nosignatures:
+
+  AUTO
\ No newline at end of file
diff --git a/docs/source/reference/api/index.rst b/docs/source/reference/api/index.rst
index 7a824422ef51ce612683c2d25acf04b51d3f779a..b19c6303eb578f4b621febe507519ae3822df20a 100644
--- a/docs/source/reference/api/index.rst
+++ b/docs/source/reference/api/index.rst
@@ -10,3 +10,4 @@ Modules
 
     field
     sympyextensions
+    codegen
diff --git a/docs/source/reference/gpu_kernels.md b/docs/source/reference/gpu_kernels.md
index 700a9cf7f647962c26d5a942116a92f2f8b4fb8e..7fb0febb46d59988787e1c506640e27b35e1ece9 100644
--- a/docs/source/reference/gpu_kernels.md
+++ b/docs/source/reference/gpu_kernels.md
@@ -49,19 +49,31 @@ ps.inspect(kernel)
 ```
 
 The `kernel` object returned by the code generator in above snippet is an instance
-of the {py:class}`GpuKernel` class.
-It extends {py:class}`Kernel` with some GPU-specific information.
-In particular, it defines the {any}`threads_range <GpuKernel.threads_range>`
+of the {py:class}`GpuKernelFunction` class.
+It extends {py:class}`KernelFunction` with some GPU-specific information.
+In particular, it defines the {any}`threads_range <GpuKernelFunction.threads_range>`
 property, which tells us how many threads the kernel is expecting to be executed with:
 
 ```{code-cell} ipython3
 kernel.threads_range
 ```
 
-If a GPU is available and [cupy] is installed in the current environment,
+If a GPU is available and [CuPy][cupy] is installed in the current environment,
 the kernel can be compiled and run immediately.
-To execute the kernel, a {any}`cupy.ndarray` has to be passed for each field;
-this is the GPU analogue to {any}`numpy.ndarray`:
+To execute the kernel, a {any}`cupy.ndarray` has to be passed for each field.
+
+:::{note}
+[CuPy][cupy] is a Python library for numerical computations on GPU arrays,
+which operates much in the same way that [NumPy][numpy] works on CPU arrays.
+Cupy and NumPy expose nearly the same APIs for array operations;
+the difference being that CuPy allocates all its arrays on the GPU
+and performs its operations as CUDA kernels.
+Also, CuPy exposes a just-in-time-compiler for GPU kernels, which internally calls [nvcc].
+In pystencils, we use CuPy both to compile and provide executable kernels on-demand from within Python code,
+and to allocate and manage the data these kernels can be executed on.
+
+For more information on CuPy, refer to [their documentation][cupy-docs].
+:::
 
 ```{code-cell} ipython3
 :tags: [raises-exception]
@@ -78,19 +90,26 @@ kfunc(f=f_arr, g=g_arr)
 ### Modifying the Launch Grid
 
 The `kernel.compile()` invocation in the above code produces a {any}`CupyKernelWrapper` callable object.
-Its interface allows us to customize the GPU launch grid.
-We can manually set both the number of threads per block, and the number of blocks on the grid:
+This object holds the kernel's launch grid configuration
+(i.e. the number of thread blocks, and the number of threads per block.)
+Pystencils specifies a default value for the block size and if possible, 
+the number of blocks is automatically inferred in order to cover the entire iteration space.
+In addition, the wrapper's interface allows us to customize the GPU launch grid,
+by manually setting both the number of threads per block, and the number of blocks on the grid:
 
 ```{code-cell} ipython3
 kfunc.block_size = (16, 8, 8)
 kfunc.num_blocks = (1, 2, 2)
 ```
 
-In most cases, the number of blocks is automatically inferred from the block size
-in order to cover the entire iteration space, so it does not need to be specified.
-Setting a launch grid that is larger than the iteration space is also possible,
-but will cause any threads working outside of the iteration bounds to idle.
+For most kernels, setting only the `block_size` is sufficient since pystencils will
+automatically compute the number of blocks;
+for exceptions to this, see [](#manual_launch_grids).
+If `num_blocks` is set manually and the launch grid thus specified is too small, only
+a part of the iteration space will be traversed by the kernel;
+similarily, if it is too large, it will cause any threads working outside of the iteration bounds to idle.
 
+(manual_launch_grids)=
 ### Manual Launch Grids and Non-Cuboid Iteration Patterns
 
 In some cases, it will be unavoidable to set the launch grid size manually;
@@ -193,8 +212,8 @@ only a part of the triangle is being processed.
   :nosignatures:
   :template: autosummary/recursive_class.rst
 
-  pystencils.codegen.GpuKernel
-  pystencils.jit.gpu_cupy.CupyKernelWrapper
+  pystencils.backend.kernelfunction.GpuKernelFunction
+  pystencils.backend.jit.gpu_cupy.CupyKernelWrapper
 ```
 
 :::{admonition} Developers To Do:
@@ -205,3 +224,6 @@ only a part of the triangle is being processed.
 
 
 [cupy]: https://cupy.dev "CuPy Homepage"
+[numpy]: https://numpy.org "NumPy Homepage"
+[nvcc]: https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html "NVIDIA CUDA Compiler Driver"
+[cupy-docs]: https://docs.cupy.dev/en/stable/overview.html "CuPy Documentation"
diff --git a/docs/source/reference/kernelcreation.md b/docs/source/reference/kernelcreation.md
index a8d926f2ea830dfd4c15bd6e8dd0734ed1bc5d7b..2a504578535604e0f4f28746a3b9eb3d7765de21 100644
--- a/docs/source/reference/kernelcreation.md
+++ b/docs/source/reference/kernelcreation.md
@@ -40,27 +40,28 @@ It takes two arguments:
 - and a configuration object, an instance of {any}`CreateKernelConfig <pystencils.codegen.config.CreateKernelConfig>`.
 
 ```{eval-rst}
-.. module:: pystencils.kernelcreation
-
 .. autosummary::
-  :toctree: generated
   :nosignatures:
 
-  create_kernel
+  pystencils.kernelcreation.create_kernel
+  pystencils.config.CreateKernelConfig
 ```
 
 For a simple kernel, an invocation of the code generator might look like this:
 
 ```{code-cell} ipython3
+# Symbol and field definitions
 u_src, u_dst, f = ps.fields("u_src, u_dst, f: float32[2D]")
 h = sp.Symbol("h")
 
+# Kernel definition
 update = [
   ps.Assignment(
     u_dst[0,0], (h**2 * f[0, 0] + u_src[1, 0] + u_src[-1, 0] + u_src[0, 1] + u_src[0, -1]) / 4
   )
 ]
 
+# Code Generator Configuration
 cfg = ps.CreateKernelConfig(
   target=ps.Target.CUDA,
   default_dtype="float32",
@@ -71,9 +72,9 @@ kernel = ps.create_kernel(update, cfg)
 ```
 
 The above snippet defines a five-point-stencil Jacobi update. A few noteworthy things are going on:
-- The target data type of the kernel is to be `float64`. This is explicitly specified for the three fields `u`, `u_tmp` and `f`;
-  but left implicit for the symbol `h`. To make sure the data type is correctly applied to the whole kernel,
-  it must also be passed to the configuration as its `default_dtype`.
+- The target data type of the kernel is to be `float32`.
+  This is explicitly specified for the three fields `u`, `u_tmp` and `f`.
+  For the symbol `h`, this is left implicit; `h` therefore learns its data type from the `default_dtype` configuration option.
 - The target hardware for this kernel are Nvidia GPUs; this is reflected by the `target` property being set to `Target.CUDA`.
 - As the five-point stencil reads data from neighbors offset by one cell, it can not be legally executed on the outermost
   layer of nodes of the fields' 2D arrays. Here, we ensure that these outer layers are excluded by setting `ghost_layers=1`.
@@ -103,28 +104,6 @@ The code generation engine can be configured using a wide range of options.
 This section aims at explaining the majority of these options,
 their interaction and effects, use cases and caveats.
 
-```{eval-rst}
-
-.. module:: pystencils.codegen.config
-
-.. autosummary::
-  :toctree: generated
-  :nosignatures:
-  :template: autosummary/entire_class.rst
-
-  CreateKernelConfig
-  CpuOptimConfig
-  OpenMpConfig
-  VectorizationConfig
-  GpuIndexingConfig
-
-.. autosummary::
-  :toctree: generated
-  :nosignatures:
-
-  AUTO
-```
-
 
 ### Target Specification
 
@@ -197,9 +176,9 @@ are using the `int32` data type, as specified in {py:data}`index_dtype <CreateKe
 ```{code-cell} ipython3
 :tags: [remove-input]
 
-driver = ps.codegen.get_driver(cfg, retain_intermediates=True)
+driver = ps.kernelcreation.get_driver(cfg, retain_intermediates=True)
 kernel = driver(assignments)
-ps.inspect(driver.intermediates.materialized_ispace)
+ps.inspect(driver.intermediates.materialized_ispace, show_cpp=False)
 ```
 
 :::{note}
@@ -241,7 +220,7 @@ only one of which can be specified at a time:
 :::
 
 ```{eval-rst}
-.. currentmodule:: pystencils.codegen
+.. currentmodule:: pystencils.codegen.config
 
 .. autosummary::
   :nosignatures:
@@ -288,7 +267,8 @@ of its stencil -- that is, the maximum neighbor offset encountered in any field
 If, for instance, a neighbor node in $x$-direction with offset $k$ is accessed by the kernel,
 it cannot legally execute on the outermost $k$ layers of nodes in that direction since it would
 access memory out-of-bounds.
-Therefore, an automatic number of $k$ ghost layers is inferred.
+Therefore, an automatic number of $k$ ghost layers at each domain border is inferred.
+As we can see in the example below, the number of inferred ghost layers at each domain border will be set to the maximum required in any dimension.
 
 ```{code-cell} ipython3
 :tags: [remove-cell]
@@ -299,13 +279,13 @@ u, v = ps.fields("u, v: [2D]")
 To illustrate, the following kernel accesses neighbor nodes with a maximum offset of two:
 
 ```{code-cell} ipython3
-ranged_update = ps.Assignment(u.center(), v[-2, -2] + v[2, 2])
+ranged_update = ps.Assignment(u.center(), v[-2, -1] + v[2, 1])
 
-cfg = ps.CreateKernelConfig(ghost_layers=ps.AUTO)
+cfg = ps.CreateKernelConfig(ghost_layers=ps.config.AUTO)
 kernel = ps.create_kernel(ranged_update, cfg)
 ```
 
-With `ghost_layers=ps.AUTO`, its iteration space will look like this (yellow cells are included, purple cells excluded):
+With `ghost_layers=ps.AUTO`, its iteration space will look like this (yellow cells are included, purple cells excluded).
 
 ```{code-cell} ipython3
 :tags: [remove-input]
@@ -376,7 +356,7 @@ _show_ispace(cfg)
 #### Iteration Slices
 
 Using the `iteration_slice` option, we can assert much finer control on the kernel's iteration space
-by specifying it using sequences of Python `slice` objects.
+by specifying it using sequences of Python {py:class}`slice` objects.
 
 We can quickly create those using `ps.make_slice`, using the `start:stop:step` slice notation.
 The easiest case is to set the iteration space with fixed numerical limits:
@@ -443,8 +423,18 @@ _show_ispace(cfg)
 
 Using a case distinction for the second dimension's start index, we can even produce
 a checkerboard pattern, as required for e.g. red-black Gauss-Seidel-type smoothers.
-We use the integer remainder (`int_rem`) to distinguish between even- and odd-numbered rows,
-set the start value accordingly, and use a step size of two:
+We use the integer remainder ({any}`int_rem`) to distinguish between even- and odd-numbered rows,
+set the start value accordingly using {any}`sp.Piecewise <sympy.functions.elementary.piecewise.Piecewise>`,
+and use a step size of two:
+
+$$
+  start(y)=
+    \begin{cases}
+      0 & \quad \text{if } y \; \mathrm{rem} \; 2 = 0 \\ 
+      1 & \quad \text{otherwise}
+    \end{cases}
+$$
+
 
 ```{code-cell} ipython3
 from pystencils.sympyextensions.integer_functions import int_rem
diff --git a/src/pystencils/codegen/config.py b/src/pystencils/codegen/config.py
index 9bd9cc9a3aff1b9b005c167c995f4640598f9fcd..01161620c4a86355ba69daf613b1d468835e58c1 100644
--- a/src/pystencils/codegen/config.py
+++ b/src/pystencils/codegen/config.py
@@ -32,7 +32,12 @@ class _AUTO_TYPE: ...  # noqa: E701
 
 
 AUTO = _AUTO_TYPE()
-"""Special value that can be passed to some options for invoking automatic behaviour."""
+"""Special value that can be passed to some options for invoking automatic behaviour.
+
+Currently, these options permit `AUTO`:
+
+- `ghost_layers <CreateKernelConfig.ghost_layers>`
+"""
 
 
 @dataclass
diff --git a/src/pystencils/codegen/target.py b/src/pystencils/codegen/target.py
index 7f26c4466f8a9cd08de8b00bf4e7002bbc820fe0..5d897dd7ebd0415494161b42c2192d4eaf08adbd 100644
--- a/src/pystencils/codegen/target.py
+++ b/src/pystencils/codegen/target.py
@@ -87,7 +87,7 @@ class Target(Flag):
     """
 
     GPU = CUDA
-    """Alias for backward compatibility."""
+    """Alias for `Target.CUDA`, for backward compatibility."""
 
     SYCL = _GPU | _SYCL
     """SYCL kernel target.
diff --git a/src/pystencils/field.py b/src/pystencils/field.py
index 2eb4b884e3569736f1937610d36f89dc53486285..1a3a13b73125bd07e6161a1694a6bf03dc2ba506 100644
--- a/src/pystencils/field.py
+++ b/src/pystencils/field.py
@@ -988,24 +988,35 @@ def create_numpy_array_with_layout(shape, layout, alignment=False, byte_offset=0
 
 
 def spatial_layout_string_to_tuple(layout_str: str, dim: int) -> Tuple[int, ...]:
-    if layout_str in ('fzyx', 'zyxf'):
-        assert dim <= 3
-        return tuple(reversed(range(dim)))
+    if dim <= 0:
+        raise ValueError("Dimensionality must be positive")
+    
+    layout_str = layout_str.lower()
 
-    if layout_str in ('fzyx', 'f', 'reverse_numpy', 'SoA'):
+    if layout_str in ('fzyx', 'zyxf', 'soa', 'aos'):
+        if dim > 3:
+            raise ValueError(f"Invalid spatial dimensionality for layout descriptor {layout_str}: May be at most 3.")
+        return tuple(reversed(range(dim)))
+    
+    if layout_str in ('f', 'reverse_numpy'):
         return tuple(reversed(range(dim)))
-    elif layout_str in ('c', 'numpy', 'AoS'):
+    elif layout_str in ('c', 'numpy'):
         return tuple(range(dim))
     raise ValueError("Unknown layout descriptor " + layout_str)
 
 
 def layout_string_to_tuple(layout_str, dim):
+    if dim <= 0:
+        raise ValueError("Dimensionality must be positive")
+    
     layout_str = layout_str.lower()
     if layout_str == 'fzyx' or layout_str == 'soa':
-        assert dim <= 4
+        if dim > 4:
+            raise ValueError(f"Invalid total dimensionality for layout descriptor {layout_str}: May be at most 4.")
         return tuple(reversed(range(dim)))
     elif layout_str == 'zyxf' or layout_str == 'aos':
-        assert dim <= 4
+        if dim > 4:
+            raise ValueError(f"Invalid total dimensionality for layout descriptor {layout_str}: May be at most 4.")
         return tuple(reversed(range(dim - 1))) + (dim - 1,)
     elif layout_str == 'f' or layout_str == 'reverse_numpy':
         return tuple(reversed(range(dim)))
diff --git a/src/pystencils/inspection.py b/src/pystencils/inspection.py
index 7f050c745d34cad374644109ca527db592822db4..2c43fc73ddeb92748d9c571bb422ab7dcf1a64fc 100644
--- a/src/pystencils/inspection.py
+++ b/src/pystencils/inspection.py
@@ -102,20 +102,31 @@ class AstInspection(CodeInspectionBase):
     explore an abstract syntax tree.
     """
 
-    def __init__(self, ast: PsAstNode):
+    def __init__(
+        self,
+        ast: PsAstNode,
+        show_ir: bool = True,
+        show_cpp: bool = True,
+        show_graph: bool = True,
+    ):
         super().__init__()
         self._ast = ast
+        self._show_ir = show_ir
+        self._show_cpp = show_cpp
+        self._show_graph = show_graph
 
     def _widget(self):
         import ipywidgets as widgets
 
-        tabs = widgets.Tab(
-            children=[
-                self._ir_tab(self._ast),
-                self._cpp_tab(self._ast),
-                self._graphviz_tab(self._ast),
-            ]
-        )
+        tabs = []
+        if self._show_ir:
+            tabs.append(self._ir_tab(self._ast))
+        if self._show_cpp:
+            tabs.append(self._cpp_tab(self._ast))
+        if self._show_graph:
+            tabs.append(self._graphviz_tab(self._ast))
+
+        tabs = widgets.Tab(children=tabs)
         tabs.titles = ["IR Code", "C Code", "AST Visualization"]
 
         tabs.layout.height = "250pt"
@@ -124,20 +135,31 @@ class AstInspection(CodeInspectionBase):
 
 
 class KernelInspection(CodeInspectionBase):
-    def __init__(self, kernel: Kernel) -> None:
+    def __init__(
+        self,
+        kernel: Kernel,
+        show_ir: bool = True,
+        show_cpp: bool = True,
+        show_graph: bool = True,
+    ) -> None:
         super().__init__()
         self._kernel = kernel
+        self._show_ir = show_ir
+        self._show_cpp = show_cpp
+        self._show_graph = show_graph
 
     def _widget(self):
         import ipywidgets as widgets
 
-        tabs = widgets.Tab(
-            children=[
-                self._ir_tab(self._kernel),
-                self._cpp_tab(self._kernel),
-                self._graphviz_tab(self._kernel),
-            ]
-        )
+        tabs = []
+        if self._show_ir:
+            tabs.append(self._ir_tab(self._kernel))
+        if self._show_cpp:
+            tabs.append(self._cpp_tab(self._kernel))
+        if self._show_graph:
+            tabs.append(self._graphviz_tab(self._kernel))
+
+        tabs = widgets.Tab(children=tabs)
         tabs.titles = ["IR Code", "C Code", "AST Visualization"]
 
         tabs.layout.height = "250pt"
@@ -146,8 +168,17 @@ class KernelInspection(CodeInspectionBase):
 
 
 class IntermediatesInspection:
-    def __init__(self, intermediates: CodegenIntermediates):
+    def __init__(
+        self,
+        intermediates: CodegenIntermediates,
+        show_ir: bool = True,
+        show_cpp: bool = True,
+        show_graph: bool = True,
+    ):
         self._intermediates = intermediates
+        self._show_ir = show_ir
+        self._show_cpp = show_cpp
+        self._show_graph = show_graph
 
     def _ipython_display_(self):
         from IPython.display import display
@@ -155,7 +186,15 @@ class IntermediatesInspection:
 
         stages = self._intermediates.available_stages
 
-        previews: list[AstInspection] = [AstInspection(stage.ast) for stage in stages]
+        previews: list[AstInspection] = [
+            AstInspection(
+                stage.ast,
+                show_ir=self._show_ir,
+                show_cpp=self._show_cpp,
+                show_graph=self._show_graph,
+            )
+            for stage in stages
+        ]
         labels: list[str] = [stage.label for stage in stages]
 
         code_views = [p._widget() for p in previews]
@@ -201,9 +240,9 @@ def inspect(obj: StageResult): ...
 def inspect(obj: CodegenIntermediates): ...
 
 
-def inspect(obj):
+def inspect(obj, show_ir: bool = True, show_cpp: bool = True, show_graph: bool = True):
     """Interactively inspect various products of the code generator.
-    
+
     When run inside a Jupyter notebook, this function displays an inspection widget
     for the following types of objects:
     - `PsAstNode`
@@ -216,13 +255,21 @@ def inspect(obj):
 
     match obj:
         case PsAstNode():
-            preview = AstInspection(obj)
+            preview = AstInspection(
+                obj, show_ir=show_ir, show_cpp=show_cpp, show_graph=show_cpp
+            )
         case Kernel():
-            preview = KernelInspection(obj)
+            preview = KernelInspection(
+                obj, show_ir=show_ir, show_cpp=show_cpp, show_graph=show_cpp
+            )
         case StageResult(ast, _):
-            preview = AstInspection(ast)
+            preview = AstInspection(
+                ast, show_ir=show_ir, show_cpp=show_cpp, show_graph=show_cpp
+            )
         case CodegenIntermediates():
-            preview = IntermediatesInspection(obj)
+            preview = IntermediatesInspection(
+                obj, show_ir=show_ir, show_cpp=show_cpp, show_graph=show_cpp
+            )
         case _:
             raise ValueError(f"Cannot inspect object of type {type(obj)}")
 
diff --git a/tests/frontend/test_field.py b/tests/frontend/test_field.py
index 6cd1c223dbe6d280db74a74926baf1293a5cc92b..dc804491bee8023e7b0e1b665d5f9cd252d64c1d 100644
--- a/tests/frontend/test_field.py
+++ b/tests/frontend/test_field.py
@@ -3,23 +3,39 @@ import pytest
 import sympy as sp
 
 import pystencils as ps
-from pystencils import TypedSymbol, DEFAULTS
-from pystencils.types import create_type
-from pystencils.field import Field, FieldType, layout_string_to_tuple
+from pystencils import DEFAULTS
+from pystencils.field import (
+    Field,
+    FieldType,
+    layout_string_to_tuple,
+    spatial_layout_string_to_tuple,
+)
 
 
 def test_field_basic():
-    f = Field.create_generic('f', spatial_dimensions=2)
+    f = Field.create_generic("f", spatial_dimensions=2)
     assert FieldType.is_generic(f)
-    assert f['E'] == f[1, 0]
-    assert f['N'] == f[0, 1]
-    assert '_' in f.center._latex('dummy')
-
-    assert f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[0] == 0
-    assert f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[1] == 0
-
-    assert f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[0] == 0
-    assert f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[1] == 0
+    assert f["E"] == f[1, 0]
+    assert f["N"] == f[0, 1]
+    assert "_" in f.center._latex("dummy")
+
+    assert (
+        f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[0]
+        == 0
+    )
+    assert (
+        f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[1]
+        == 0
+    )
+
+    assert (
+        f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[0]
+        == 0
+    )
+    assert (
+        f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[1]
+        == 0
+    )
 
     f1 = f.new_field_with_different_name("f1")
     assert f1.ndim == f.ndim
@@ -28,7 +44,7 @@ def test_field_basic():
     fixed = ps.fields("f(5, 5) : double[20, 20]")
     assert fixed.neighbor_vector((1, 1)).shape == (5, 5)
 
-    f = Field.create_fixed_size('f', (10, 10), strides=(80, 8), dtype=np.float64)
+    f = Field.create_fixed_size("f", (10, 10), strides=(80, 8), dtype=np.float64)
     assert f.spatial_strides == (10, 1)
     assert f.index_strides == ()
     assert f.center_vector == sp.Matrix([f.center])
@@ -37,84 +53,99 @@ def test_field_basic():
     assert f1.ndim == f.ndim
     assert f1.values_per_cell() == f.values_per_cell()
 
-    f = Field.create_fixed_size('f', (8, 8, 2, 2), index_dimensions=2)
-    assert f.center_vector == sp.Matrix([[f(0, 0), f(0, 1)],
-                                         [f(1, 0), f(1, 1)]])
+    f = Field.create_fixed_size("f", (8, 8, 2, 2), index_dimensions=2)
+    assert f.center_vector == sp.Matrix([[f(0, 0), f(0, 1)], [f(1, 0), f(1, 1)]])
     field_access = f[1, 1]
     assert field_access.nr_of_coordinates == 2
-    assert field_access.offset_name == 'NE'
+    assert field_access.offset_name == "NE"
     neighbor = field_access.neighbor(coord_id=0, offset=-2)
     assert neighbor.offsets == (-1, 1)
-    assert '_' in neighbor._latex('dummy')
+    assert "_" in neighbor._latex("dummy")
 
-    f = Field.create_fixed_size('f', (8, 8, 2, 2, 2), index_dimensions=3)
-    assert f.center_vector == sp.Array([[[f(i, j, k) for k in range(2)] for j in range(2)] for i in range(2)])
+    f = Field.create_fixed_size("f", (8, 8, 2, 2, 2), index_dimensions=3)
+    assert f.center_vector == sp.Array(
+        [[[f(i, j, k) for k in range(2)] for j in range(2)] for i in range(2)]
+    )
 
-    f = Field.create_generic('f', spatial_dimensions=5, index_dimensions=2)
+    f = Field.create_generic("f", spatial_dimensions=5, index_dimensions=2)
     field_access = f[1, -1, 2, -3, 0](1, 0)
     assert field_access.offsets == (1, -1, 2, -3, 0)
     assert field_access.index == (1, 0)
 
 
 def test_error_handling():
-    struct_dtype = np.dtype([('a', np.int32), ('b', np.float64), ('c', np.uint32)], align=True)
-    Field.create_generic('f', spatial_dimensions=2, index_dimensions=0, dtype=struct_dtype)
+    struct_dtype = np.dtype(
+        [("a", np.int32), ("b", np.float64), ("c", np.uint32)], align=True
+    )
+    Field.create_generic(
+        "f", spatial_dimensions=2, index_dimensions=0, dtype=struct_dtype
+    )
     with pytest.raises(ValueError) as e:
-        Field.create_generic('f', spatial_dimensions=2, index_dimensions=1, dtype=struct_dtype)
-    assert 'index dimension' in str(e.value)
+        Field.create_generic(
+            "f", spatial_dimensions=2, index_dimensions=1, dtype=struct_dtype
+        )
+    assert "index dimension" in str(e.value)
 
-    arr = np.array([[[(1,)*3, (2,)*3, (3,)*3]]*2], dtype=struct_dtype)
-    Field.create_from_numpy_array('f', arr, index_dimensions=0)
+    arr = np.array([[[(1,) * 3, (2,) * 3, (3,) * 3]] * 2], dtype=struct_dtype)
+    Field.create_from_numpy_array("f", arr, index_dimensions=0)
     with pytest.raises(ValueError) as e:
-        Field.create_from_numpy_array('f', arr, index_dimensions=1)
-    assert 'Structured arrays' in str(e.value)
+        Field.create_from_numpy_array("f", arr, index_dimensions=1)
+    assert "Structured arrays" in str(e.value)
 
     arr = np.zeros([3, 3, 3])
-    Field.create_from_numpy_array('f', arr, index_dimensions=2)
+    Field.create_from_numpy_array("f", arr, index_dimensions=2)
     with pytest.raises(ValueError) as e:
-        Field.create_from_numpy_array('f', arr, index_dimensions=3)
-    assert 'Too many' in str(e.value)
+        Field.create_from_numpy_array("f", arr, index_dimensions=3)
+    assert "Too many" in str(e.value)
 
-    Field.create_fixed_size('f', (3, 2, 4), index_dimensions=0, dtype=struct_dtype, layout='reverse_numpy')
+    Field.create_fixed_size(
+        "f", (3, 2, 4), index_dimensions=0, dtype=struct_dtype, layout="reverse_numpy"
+    )
     with pytest.raises(ValueError) as e:
-        Field.create_fixed_size('f', (3, 2, 4), index_dimensions=1, dtype=struct_dtype, layout='reverse_numpy')
-    assert 'Structured arrays' in str(e.value)
-
-    f = Field.create_fixed_size('f', (10, 10))
+        Field.create_fixed_size(
+            "f",
+            (3, 2, 4),
+            index_dimensions=1,
+            dtype=struct_dtype,
+            layout="reverse_numpy",
+        )
+    assert "Structured arrays" in str(e.value)
+
+    f = Field.create_fixed_size("f", (10, 10))
     with pytest.raises(ValueError) as e:
         f[1]
-    assert 'Wrong number of spatial indices' in str(e.value)
+    assert "Wrong number of spatial indices" in str(e.value)
 
-    f = Field.create_generic('f', spatial_dimensions=2, index_shape=(3,))
+    f = Field.create_generic("f", spatial_dimensions=2, index_shape=(3,))
     with pytest.raises(ValueError) as e:
         f(3)
-    assert 'out of bounds' in str(e.value)
+    assert "out of bounds" in str(e.value)
 
-    f = Field.create_fixed_size('f', (10, 10, 3, 4), index_dimensions=2)
+    f = Field.create_fixed_size("f", (10, 10, 3, 4), index_dimensions=2)
     with pytest.raises(ValueError) as e:
         f(3, 0)
-    assert 'out of bounds' in str(e.value)
+    assert "out of bounds" in str(e.value)
 
     with pytest.raises(ValueError) as e:
         f(1, 0)(1, 0)
-    assert 'Indexing an already indexed' in str(e.value)
+    assert "Indexing an already indexed" in str(e.value)
 
     with pytest.raises(ValueError) as e:
         f(1)
-    assert 'Wrong number of indices' in str(e.value)
+    assert "Wrong number of indices" in str(e.value)
 
     with pytest.raises(ValueError) as e:
-        Field.create_generic('f', spatial_dimensions=2, layout='wrong')
-    assert 'Unknown layout descriptor' in str(e.value)
+        Field.create_generic("f", spatial_dimensions=2, layout="wrong")
+    assert "Unknown layout descriptor" in str(e.value)
 
-    assert layout_string_to_tuple('fzyx', dim=4) == (3, 2, 1, 0)
+    assert layout_string_to_tuple("fzyx", dim=4) == (3, 2, 1, 0)
     with pytest.raises(ValueError) as e:
-        layout_string_to_tuple('wrong', dim=4)
-    assert 'Unknown layout descriptor' in str(e.value)
+        layout_string_to_tuple("wrong", dim=4)
+    assert "Unknown layout descriptor" in str(e.value)
 
 
 def test_decorator_scoping():
-    dst = ps.fields('dst : double[2D]')
+    dst = ps.fields("dst : double[2D]")
 
     def f1():
         a = sp.Symbol("a")
@@ -134,7 +165,7 @@ def test_decorator_scoping():
 
 
 def test_string_creation():
-    x, y, z = ps.fields('  x(4),    y(3,5) z : double[  3,  47]')
+    x, y, z = ps.fields("  x(4),    y(3,5) z : double[  3,  47]")
     assert x.index_shape == (4,)
     assert y.index_shape == (3, 5)
     assert z.spatial_shape == (3, 47)
@@ -142,19 +173,85 @@ def test_string_creation():
 
 def test_itemsize():
 
-    x = ps.fields('x: float32[1d]')
-    y = ps.fields('y:  float64[2d]')
-    i = ps.fields('i:  int16[1d]')
+    x = ps.fields("x: float32[1d]")
+    y = ps.fields("y:  float64[2d]")
+    i = ps.fields("i:  int16[1d]")
 
     assert x.itemsize == 4
     assert y.itemsize == 8
     assert i.itemsize == 2
 
 
+def test_spatial_memory_layout_descriptors():
+    assert (
+        spatial_layout_string_to_tuple("AoS", 3)
+        == spatial_layout_string_to_tuple("aos", 3)
+        == spatial_layout_string_to_tuple("ZYXF", 3)
+        == spatial_layout_string_to_tuple("zyxf", 3)
+        == (2, 1, 0)
+    )
+    assert (
+        spatial_layout_string_to_tuple("SoA", 3)
+        == spatial_layout_string_to_tuple("soa", 3)
+        == spatial_layout_string_to_tuple("FZYX", 3)
+        == spatial_layout_string_to_tuple("fzyx", 3)
+        == spatial_layout_string_to_tuple("f", 3)
+        == spatial_layout_string_to_tuple("F", 3)
+        == (2, 1, 0)
+    )
+    assert (
+        spatial_layout_string_to_tuple("c", 3)
+        == spatial_layout_string_to_tuple("C", 3)
+        == (0, 1, 2)
+    )
+
+    assert spatial_layout_string_to_tuple("C", 5) == (0, 1, 2, 3, 4)
+
+    with pytest.raises(ValueError):
+        spatial_layout_string_to_tuple("aos", -1)
+
+    with pytest.raises(ValueError):
+        spatial_layout_string_to_tuple("aos", 4)
+
+
+def test_memory_layout_descriptors():
+    assert (
+        layout_string_to_tuple("AoS", 4)
+        == layout_string_to_tuple("aos", 4)
+        == layout_string_to_tuple("ZYXF", 4)
+        == layout_string_to_tuple("zyxf", 4)
+        == (2, 1, 0, 3)
+    )
+    assert (
+        layout_string_to_tuple("SoA", 4)
+        == layout_string_to_tuple("soa", 4)
+        == layout_string_to_tuple("FZYX", 4)
+        == layout_string_to_tuple("fzyx", 4)
+        == layout_string_to_tuple("f", 4)
+        == layout_string_to_tuple("F", 4)
+        == (3, 2, 1, 0)
+    )
+    assert (
+        layout_string_to_tuple("c", 4)
+        == layout_string_to_tuple("C", 4)
+        == (0, 1, 2, 3)
+    )
+
+    assert layout_string_to_tuple("C", 5) == (0, 1, 2, 3, 4)
+
+    with pytest.raises(ValueError):
+        layout_string_to_tuple("aos", -1)
+
+    with pytest.raises(ValueError):
+        layout_string_to_tuple("aos", 5)
+
+
 def test_staggered():
 
     # D2Q5
-    j1, j2, j3 = ps.fields('j1(2), j2(2,2), j3(2,2,2) : double[2D]', field_type=FieldType.STAGGERED)
+    j1, j2, j3 = ps.fields(
+        "j1(2), j2(2,2), j3(2,2,2) : double[2D]", field_type=FieldType.STAGGERED
+    )
 
     assert j1[0, 1](1) == j1.staggered_access((0, sp.Rational(1, 2)))
     assert j1[0, 1](1) == j1.staggered_access(np.array((0, sp.Rational(1, 2))))
@@ -163,44 +260,68 @@ def test_staggered():
     assert j1[0, 1](1) == j1.staggered_access("N")
     assert j1[0, 0](1) == j1.staggered_access("S")
     assert j1.staggered_vector_access("N") == sp.Matrix([j1.staggered_access("N")])
-    assert j1.staggered_stencil_name == 'D2Q5'
+    assert j1.staggered_stencil_name == "D2Q5"
 
     assert j1.physical_coordinates[0] == DEFAULTS.spatial_counters[0]
     assert j1.physical_coordinates[1] == DEFAULTS.spatial_counters[1]
     assert j1.physical_coordinates_staggered[0] == DEFAULTS.spatial_counters[0] + 0.5
     assert j1.physical_coordinates_staggered[1] == DEFAULTS.spatial_counters[1] + 0.5
-    assert j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[0] == 0.5
-    assert j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[1] == 0.5
-    assert j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[0] == -0.5
-    assert j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[1] == -0.5
+    assert (
+        j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[0]
+        == 0.5
+    )
+    assert (
+        j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[1]
+        == 0.5
+    )
+    assert (
+        j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[0]
+        == -0.5
+    )
+    assert (
+        j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[1]
+        == -0.5
+    )
 
     assert j2[0, 1](1, 1) == j2.staggered_access((0, sp.Rational(1, 2)), 1)
     assert j2[0, 1](1, 1) == j2.staggered_access("N", 1)
-    assert j2.staggered_vector_access("N") == sp.Matrix([j2.staggered_access("N", 0), j2.staggered_access("N", 1)])
+    assert j2.staggered_vector_access("N") == sp.Matrix(
+        [j2.staggered_access("N", 0), j2.staggered_access("N", 1)]
+    )
 
     assert j3[0, 1](1, 1, 1) == j3.staggered_access((0, sp.Rational(1, 2)), (1, 1))
     assert j3[0, 1](1, 1, 1) == j3.staggered_access("N", (1, 1))
-    assert j3.staggered_vector_access("N") == sp.Matrix([[j3.staggered_access("N", (i, j))
-                                                        for j in range(2)] for i in range(2)])
+    assert j3.staggered_vector_access("N") == sp.Matrix(
+        [[j3.staggered_access("N", (i, j)) for j in range(2)] for i in range(2)]
+    )
 
     # D2Q9
-    k1, k2 = ps.fields('k1(4), k2(2) : double[2D]', field_type=FieldType.STAGGERED)
+    k1, k2 = ps.fields("k1(4), k2(2) : double[2D]", field_type=FieldType.STAGGERED)
 
     assert k1[1, 1](2) == k1.staggered_access("NE")
     assert k1[0, 0](2) == k1.staggered_access("SW")
     assert k1[0, 0](3) == k1.staggered_access("NW")
-    
+
     a = k1.staggered_access("NE")
-    assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(1, 2), sp.Rational(1, 2)]
+    assert a._staggered_offset(a.offsets, a.index[0]) == [
+        sp.Rational(1, 2),
+        sp.Rational(1, 2),
+    ]
     a = k1.staggered_access("SW")
-    assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(-1, 2), sp.Rational(-1, 2)]
+    assert a._staggered_offset(a.offsets, a.index[0]) == [
+        sp.Rational(-1, 2),
+        sp.Rational(-1, 2),
+    ]
     a = k1.staggered_access("NW")
-    assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(-1, 2), sp.Rational(1, 2)]
+    assert a._staggered_offset(a.offsets, a.index[0]) == [
+        sp.Rational(-1, 2),
+        sp.Rational(1, 2),
+    ]
 
     # sign reversed when using as flux field
-    r = ps.fields('r(2) : double[2D]', field_type=FieldType.STAGGERED_FLUX)
+    r = ps.fields("r(2) : double[2D]", field_type=FieldType.STAGGERED_FLUX)
     assert r[0, 0](0) == r.staggered_access("W")
     assert -r[1, 0](0) == r.staggered_access("E")
 
 
-# test_staggered()
\ No newline at end of file
+# test_staggered()