Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Sparse
  • WallLaw
  • improved_comm
  • master
  • mr_refactor_wfb
  • release/0.2.1
  • release/0.2.10
  • release/0.2.11
  • release/0.2.12
  • release/0.2.13
  • release/0.2.14
  • release/0.2.15
  • release/0.2.2
  • release/0.2.3
  • release/0.2.4
  • release/0.2.5
  • release/0.2.6
  • release/0.2.7
  • release/0.2.8
  • release/0.2.9
  • release/0.3.0
  • release/0.3.1
  • release/0.3.2
  • release/0.3.3
  • release/0.3.4
  • release/0.4.0
  • release/0.4.1
  • release/0.4.2
  • release/0.4.3
  • release/0.4.4
  • release/1.0
  • release/1.0.1
  • release/1.1
  • release/1.1.1
  • release/1.2
  • release/1.3
  • release/1.3.1
  • release/1.3.2
  • release/1.3.3
  • release/1.3.4
  • release/1.3.5
  • release/1.3.6
  • release/1.3.7
43 results

Target

Select target project
  • ravi.k.ayyala/lbmpy
  • brendan-waters/lbmpy
  • anirudh.jonnalagadda/lbmpy
  • jbadwaik/lbmpy
  • alexander.reinauer/lbmpy
  • itischler/lbmpy
  • he66coqe/lbmpy
  • ev81oxyl/lbmpy
  • Bindgen/lbmpy
  • da15siwa/lbmpy
  • holzer/lbmpy
  • RudolfWeeber/lbmpy
  • pycodegen/lbmpy
13 results
Select Git revision
  • iMEM
  • master
2 results
Show changes
Commits on Source (10)
Showing
with 1410 additions and 312 deletions
...@@ -21,6 +21,9 @@ doc/bibtex.json ...@@ -21,6 +21,9 @@ doc/bibtex.json
/src/lbmpy/phasefield/simplex_projection.*.so /src/lbmpy/phasefield/simplex_projection.*.so
/src/lbmpy/phasefield/simplex_projection.c /src/lbmpy/phasefield/simplex_projection.c
test-report
report.xml
# macOS # macOS
**/.DS_Store **/.DS_Store
*.uuid *.uuid
......
stages: stages:
- pretest - "Code Quality"
- test - "Tests"
- "Prerelease-Tests"
- integration
- nightly - nightly
- docs - docs
- deploy - deploy
# -------------------------- Templates ------------------------------------------------------------------------------------ # -------------------------- Code Quality --------------------------------------------------------------------------------
# Base configuration for jobs meant to run at every commit
.every-commit:
rules:
- if: $CI_PIPELINE_SOURCE != "schedule"
# Configuration for jobs meant to run on each commit to pycodegen/pystencils/master
.every-commit-master:
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule" && $CI_PROJECT_PATH == "pycodegen/lbmpy" && $CI_COMMIT_BRANCH == "master"'
# Linter for code formatting
flake8-lint:
stage: "Code Quality"
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:alpine
script:
- nox -s lint
tags:
- docker
# Base configuration for jobs meant to run at a schedule
.scheduled:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
# -------------------------- Pre Tests -------------------------------------------------------------------------------- # -------------------------- Tests --------------------------------------------------------------------------------
# Normal test - runs on every commit all but "long run" tests # Normal test - runs on every commit all but "long run" tests
tests-and-coverage: testsuite-cuda-py3.10:
stage: pretest stage: "Tests"
extends: .every-commit image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:ubuntu24.04-cuda12.6
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full needs: []
script: script:
# - pip install sympy --upgrade
- export NUM_CORES=$(nproc --all)
- mkdir -p ~/.config/matplotlib - mkdir -p ~/.config/matplotlib
- echo "backend:template" > ~/.config/matplotlib/matplotlibrc - echo "backend:template" > ~/.config/matplotlib/matplotlibrc
- mkdir public - nox -s "testsuite_gpu-3.10(cupy12)"
- pip install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils
- env
- pip list
- py.test -v -n $NUM_CORES --cov-report html --cov-report xml --cov-report term --cov=. -m "not longrun" --junitxml=report.xml
- python3 -m coverage xml
tags: tags:
- docker - docker
- cuda11 - cuda
- cudaComputeCapability6.1
- AVX - AVX
coverage: /Total coverage:\s\d+.\d+\%/ coverage: /Total coverage:\s\d+.\d+\%/
artifacts: artifacts:
when: always when: always
paths: paths:
- coverage_report - coverage_report
- test-report
reports: reports:
coverage_report: coverage_report:
coverage_format: cobertura coverage_format: cobertura
path: coverage.xml path: coverage.xml
junit: report.xml junit: report.xml
testsuite-cpu-py3.13:
stage: "Tests"
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:alpine
needs: []
script:
- mkdir -p ~/.config/matplotlib
- echo "backend:template" > ~/.config/matplotlib/matplotlibrc
- nox -s "testsuite_cpu-3.13"
tags:
- docker
- AVX
artifacts:
when: always
paths:
- test-report
reports:
junit: report.xml
# Normal test with longruns # Normal test with longruns
tests-and-coverage-with-longrun: tests-and-coverage-with-longrun:
stage: test stage: "Tests"
when: manual when: manual
allow_failure: true allow_failure: true
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
...@@ -74,155 +86,88 @@ tests-and-coverage-with-longrun: ...@@ -74,155 +86,88 @@ tests-and-coverage-with-longrun:
- py.test -v -n $NUM_CORES - py.test -v -n $NUM_CORES
tags: tags:
- docker - docker
- cuda11 - cuda
- cudaComputeCapability6.1
- AVX - AVX
minimal-conda: # -------------------------- Nightly and Pre-Release Tests --------------------------------------------------------------------------------
stage: pretest
extends: .every-commit
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/minimal_conda
script:
- pip install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils
- pip install -e .
- python quicktest.py
tags:
- docker
# Linter for code formatting
flake8-lint:
stage: pretest
extends: .every-commit
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
script:
- flake8 src/lbmpy
tags:
- docker
- cuda11
# -------------------------- Tests ------------------------------------------------------------------------------------- # Test against latest pystencils 2.0 development version
pystencils-2.0dev:
# pipeline with latest python version stage: "Prerelease-Tests"
latest-python: image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:ubuntu24.04-cuda12.6
stage: test allow_failure: true
extends: .every-commit needs: []
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/latest_python
before_script:
- pip install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils
script: script:
- env
- pip list
- export NUM_CORES=$(nproc --all)
- mkdir -p ~/.config/matplotlib - mkdir -p ~/.config/matplotlib
- echo "backend:template" > ~/.config/matplotlib/matplotlibrc - echo "backend:template" > ~/.config/matplotlib/matplotlibrc
- mkdir public - nox -s "testsuite_pystencils2(cupy12)"
- py.test -v -n $NUM_CORES -m "not longrun" --junitxml=report.xml
tags: tags:
- docker - docker
- AVX - AVX
- cuda
- cudaComputeCapability6.1
artifacts: artifacts:
when: always when: always
paths:
- test-report
reports: reports:
junit: report.xml junit: report.xml
# Minimal tests in windows environment
#minimal-windows:
# stage: test
# except:
# variables:
# - $ENABLE_NIGHTLY_BUILDS
# tags:
# - win
# script:
# - export NUM_CORES=$(nproc --all)
# - export MPLBACKEND=Agg
# - source /cygdrive/c/Users/build/Miniconda3/Scripts/activate
# - source activate pystencils
# - pip install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils
# - python -c "import numpy"
# - pip install sympy==1.9
# - py.test -v -m "not (notebook or longrun)"
minimal-sympy-master: minimal-sympy-master:
stage: test stage: "Prerelease-Tests"
extends: .every-commit needs: []
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/minimal_conda image: i10git.cs.fau.de:5005/pycodegen/pycodegen/nox:alpine
before_script:
- pip install -e .
script: script:
- pip install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils - nox -s quicktest -P 3.13 -- --sympy-master
- python -m pip install --upgrade git+https://github.com/sympy/sympy.git
- pip list
- python quicktest.py
allow_failure: true allow_failure: true
tags: tags:
- docker - docker
- cuda
ubuntu: # pycodegen-integration:
stage: test # image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
extends: .every-commit # stage: integration
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/ubuntu # when: manual
before_script: # allow_failure: true
# - apt-get -y remove python3-sympy # script:
- ln -s /usr/include/locale.h /usr/include/xlocale.h # - env
# - pip3 install `grep -Eo 'sympy[>=]+[0-9\.]+' setup.py | sed 's/>/=/g'` # - pip list
- pip3 install git+https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pystencils.git@master#egg=pystencils # - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pycodegen.git
script: # - cd pycodegen
- export NUM_CORES=$(nproc --all) # - git submodule sync --recursive
- mkdir -p ~/.config/matplotlib # - git submodule update --init --recursive
- echo "backend:template" > ~/.config/matplotlib/matplotlibrc # - git submodule foreach git fetch origin # compare the latest master version!
- env # - git submodule foreach git reset --hard origin/master
- pip3 list # - cd lbmpy
- pytest -v -n $NUM_CORES -m "not longrun" --junitxml=report.xml # - git remote add test $CI_REPOSITORY_URL
tags: # - git fetch test
- docker # - git reset --hard $CI_COMMIT_SHA
- cuda11 # - cd ..
artifacts: # - pip install -e pystencils/
when: always # - pip install -e lbmpy/
reports: # - ./install_walberla.sh
junit: report.xml # # build all integration tests
# - cd walberla/build/
# - make -j $NUM_CORES MicroBenchmarkGpuLbm LbCodeGenerationExample
# - cd apps/benchmarks/UniformGridGPU
# - make -j $NUM_CORES
# - cd ../UniformGridCPU
# - make -j $NUM_CORES
# tags:
# - docker
# - cuda
# - cudaComputeCapability6.1
# - AVX
pycodegen-integration:
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
stage: test
when: manual
allow_failure: true
script:
- env
- pip list
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@i10git.cs.fau.de/pycodegen/pycodegen.git
- cd pycodegen
- git submodule sync --recursive
- git submodule update --init --recursive
- git submodule foreach git fetch origin # compare the latest master version!
- git submodule foreach git reset --hard origin/master
- cd lbmpy
- git remote add test $CI_REPOSITORY_URL
- git fetch test
- git reset --hard $CI_COMMIT_SHA
- cd ..
- pip install -e pystencils/
- pip install -e lbmpy/
- ./install_walberla.sh
# build all integration tests
- cd walberla/build/
- make -j $NUM_CORES MicroBenchmarkGpuLbm LbCodeGenerationExample
- cd apps/benchmarks/UniformGridGPU
- make -j $NUM_CORES
- cd ../UniformGridCPU
- make -j $NUM_CORES
tags:
- docker
- cuda11
- AVX
# -------------------- Scheduled Tasks -------------------------------------------------------------------------- # -------------------- Scheduled Tasks --------------------------------------------------------------------------
nightly-sympy: nightly-sympy:
stage: nightly stage: nightly
extends: .scheduled rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/latest_python image: i10git.cs.fau.de:5005/pycodegen/pycodegen/latest_python
before_script: before_script:
- pip install -e . - pip install -e .
...@@ -240,6 +185,7 @@ nightly-sympy: ...@@ -240,6 +185,7 @@ nightly-sympy:
- docker - docker
- AVX - AVX
- cuda - cuda
- cudaComputeCapability6.1
artifacts: artifacts:
when: always when: always
reports: reports:
...@@ -251,7 +197,6 @@ nightly-sympy: ...@@ -251,7 +197,6 @@ nightly-sympy:
build-documentation: build-documentation:
stage: docs stage: docs
needs: [] needs: []
extends: .every-commit
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/documentation image: i10git.cs.fau.de:5005/pycodegen/pycodegen/documentation
before_script: before_script:
- pip install -e . - pip install -e .
...@@ -262,7 +207,8 @@ build-documentation: ...@@ -262,7 +207,8 @@ build-documentation:
- sphinx-build -W -b html doc html_doc - sphinx-build -W -b html doc html_doc
tags: tags:
- docker - docker
- cuda11 - cuda
- cudaComputeCapability6.1
artifacts: artifacts:
paths: paths:
- html_doc - html_doc
...@@ -270,9 +216,10 @@ build-documentation: ...@@ -270,9 +216,10 @@ build-documentation:
pages: pages:
image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full image: i10git.cs.fau.de:5005/pycodegen/pycodegen/full
extends: .every-commit-master rules:
- if: '$CI_PIPELINE_SOURCE != "schedule" && $CI_PROJECT_PATH == "pycodegen/lbmpy" && $CI_COMMIT_BRANCH == "master"'
stage: deploy stage: deploy
needs: ["tests-and-coverage", "build-documentation"] needs: ["testsuite-cuda-py3.10", "build-documentation"]
script: script:
- ls -l - ls -l
- mv coverage_report html_doc - mv coverage_report html_doc
......
...@@ -11,3 +11,4 @@ Contributors: ...@@ -11,3 +11,4 @@ Contributors:
- Rudolf Weeber <weeber@icp.uni-stuttgart.de> - Rudolf Weeber <weeber@icp.uni-stuttgart.de>
- Christian Godenschwager <christian.godenschwager@fau.de> - Christian Godenschwager <christian.godenschwager@fau.de>
- Jan Hönig <jan.hoenig@fau.de> - Jan Hönig <jan.hoenig@fau.de>
- Philipp Suffa <philipp.suffa@fau.de>
------------------------ Important ---------------------------------
lbmpy is under the following GNU AGPLv3 license.
This license holds for the sources of lbmpy itself as well
as for all kernels generated with lbmpy i.e.
the output of lbmpy is also protected by the GNU AGPLv3 license.
----------------------------------------------------------------------
GNU AFFERO GENERAL PUBLIC LICENSE GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007 Version 3, 19 November 2007
......
...@@ -5,13 +5,18 @@ import runpy ...@@ -5,13 +5,18 @@ import runpy
import sys import sys
import warnings import warnings
import platform import platform
import pathlib
import nbformat import nbformat
from nbconvert import PythonExporter import nbconvert
import sympy import sympy
from lbmpy._compat import IS_PYSTENCILS_2
# Trigger config file reading / creation once - to avoid race conditions when multiple instances are creating it # Trigger config file reading / creation once - to avoid race conditions when multiple instances are creating it
# at the same time # at the same time
from pystencils.cpu import cpujit if not IS_PYSTENCILS_2:
from pystencils.cpu import cpujit
# trigger cython imports - there seems to be a problem when multiple processes try to compile the same cython file # trigger cython imports - there seems to be a problem when multiple processes try to compile the same cython file
# at the same time # at the same time
...@@ -19,7 +24,6 @@ try: ...@@ -19,7 +24,6 @@ try:
import pyximport import pyximport
pyximport.install(language_level=3) pyximport.install(language_level=3)
from lbmpy.phasefield.simplex_projection import simplex_projection_2d # NOQA from lbmpy.phasefield.simplex_projection import simplex_projection_2d # NOQA
except ImportError: except ImportError:
pass pass
...@@ -45,6 +49,13 @@ collect_ignore = [os.path.join(SCRIPT_FOLDER, "doc", "conf.py"), ...@@ -45,6 +49,13 @@ collect_ignore = [os.path.join(SCRIPT_FOLDER, "doc", "conf.py"),
os.path.join(SCRIPT_FOLDER, "doc", "img", "mb_discretization", "maxwell_boltzmann_stencil_plot.py")] os.path.join(SCRIPT_FOLDER, "doc", "img", "mb_discretization", "maxwell_boltzmann_stencil_plot.py")]
add_path_to_ignore('_local_tmp') add_path_to_ignore('_local_tmp')
if IS_PYSTENCILS_2:
# TODO: Fix these step-by-step
collect_ignore += [
os.path.join(SCRIPT_FOLDER, "doc", "notebooks", "10_tutorial_conservative_allen_cahn_two_phase.ipynb"),
os.path.join(SCRIPT_FOLDER, "tests", "test_compiled_in_boundaries.ipynb")
]
try: try:
import cupy import cupy
except ImportError: except ImportError:
...@@ -129,7 +140,7 @@ class IPyNbTest(pytest.Item): ...@@ -129,7 +140,7 @@ class IPyNbTest(pytest.Item):
class IPyNbFile(pytest.File): class IPyNbFile(pytest.File):
def collect(self): def collect(self):
exporter = PythonExporter() exporter = nbconvert.PythonExporter()
exporter.exclude_markdown = True exporter.exclude_markdown = True
exporter.exclude_input_prompt = True exporter.exclude_input_prompt = True
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="53.913788mm"
height="53.913788mm"
viewBox="0 0 53.913788 53.913788"
version="1.1"
id="svg834"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="lbmpy-logo.svg"
inkscape:export-filename="/local/bauer/code/lbmpy/lbmpy/doc/img/logo.png"
inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs828">
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1421"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-6"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-7"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-7"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-6-9"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-7-4"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-7-5"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-6"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-5"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-7"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-6-3"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-5-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-7-4"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-6-3-0"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-5-9-6"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#c6c6c6;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-7-4-0"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-8"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-4"
is_visible="true"
lpeversion="0" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606" />
</filter>
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5"
is_visible="true"
lpeversion="0" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188"
is_visible="true"
lpeversion="0" />
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4608-0">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4610-2" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4612-5" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4614-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4616-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4618-9" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4632-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4634-9" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4636-8" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4638-7" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4640-6" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4642-5" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4620-1">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4622-1" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4624-4" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4626-8" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4628-5" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4630-7" />
</filter>
<filter
y="-0.25"
height="1.5"
inkscape:menu-tooltip="Darkens the edge with an inner blur and adds a flexible glow"
inkscape:menu="Shadows and Glows"
inkscape:label="Dark And Glow"
style="color-interpolation-filters:sRGB"
id="filter4596-6">
<feGaussianBlur
stdDeviation="5"
result="result6"
id="feGaussianBlur4598-6" />
<feComposite
result="result8"
in="SourceGraphic"
operator="atop"
in2="result6"
id="feComposite4600-9" />
<feComposite
result="result9"
operator="over"
in2="SourceAlpha"
in="result8"
id="feComposite4602-1" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
result="result10"
id="feColorMatrix4604-4" />
<feBlend
in="result10"
mode="normal"
in2="result6"
id="feBlend4606-3" />
</filter>
<inkscape:path-effect
effect="spiro"
id="path-effect4188-5-6"
is_visible="true"
lpeversion="0" />
<inkscape:path-effect
effect="spiro"
id="path-effect4188-7"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-3"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1421-6"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-75"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-3"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-5"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-6"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-6-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-7-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-7-1"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-27"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-0"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-9"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-6-36"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-5-0"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-7-6"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-6-3-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-5-9-61"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-7-4-8"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-2-2-7"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-2-8-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-3-4-2"
is_visible="true"
lpeversion="0" />
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-6-9-0"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path1421-2-7-4-2"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:#dddddd;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<inkscape:path-effect
effect="spiro"
id="path-effect1404-7-7-5-3"
is_visible="true"
lpeversion="0" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="158.57143"
inkscape:cy="78.571429"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1664"
inkscape:window-height="1113"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid1886"
originx="-9.840785"
originy="-227.28709"
spacingy="1"
spacingx="1"
units="mm" />
</sodipodi:namedview>
<metadata
id="metadata831">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-9.8407853,-15.799119)">
<rect
style="opacity:1;fill:#646ecb;fill-opacity:1;stroke:#d2d2d2;stroke-width:0.509157;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1396"
width="53.404633"
height="53.404633"
x="10.095364"
y="16.053698"
ry="3.0735996"
inkscape:export-xdpi="188.45"
inkscape:export-ydpi="188.45" />
<path
style="font-weight:bold;font-size:16.9333px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';letter-spacing:0px;word-spacing:0px;fill:#ffffff;stroke-width:0.264583px"
d="m 21.505785,62.578241 c 0,-0.626532 -0.474132,-0.643466 -0.795865,-0.643466 h -2.015062 v -8.26345 c 0,-0.609599 -0.118533,-0.812798 -0.795865,-0.812798 h -2.607729 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643465 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 2.015063 v 7.806251 h -1.99813 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643466 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 5.435589 c 0.3048,0 0.795865,-0.01693 0.795865,-0.626532 z m 9.228643,-3.064927 c 0,-2.116663 -1.54093,-3.776126 -3.352793,-3.776126 -0.728132,0 -1.405464,0.237066 -1.964263,0.643465 v -2.709328 c 0,-0.609599 -0.118533,-0.812798 -0.795865,-0.812798 h -1.202265 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643465 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 0.609599 v 8.263451 c 0,0.406399 0.01693,0.812798 0.711198,0.812798 0.524933,0 0.660399,-0.237066 0.677332,-0.575732 0.643466,0.541865 1.303865,0.677332 1.79493,0.677332 1.862663,0 3.53906,-1.625597 3.53906,-3.793059 z m -1.388531,0 c 0,1.49013 -1.083731,2.523061 -2.184395,2.523061 -1.202265,0 -1.727197,-1.371597 -1.727197,-2.116662 v -1.202265 c 0,-0.914398 0.897465,-1.710263 1.862663,-1.710263 1.151464,0 2.048929,1.151465 2.048929,2.506129 z m 10.820373,3.064927 c 0,-0.558799 -0.321733,-0.643466 -0.931331,-0.643466 v -3.860792 c 0,-0.355599 -0.03387,-2.336795 -1.608664,-2.336795 -0.474132,0 -1.117598,0.186266 -1.608663,0.745065 -0.287867,-0.491066 -0.745066,-0.745065 -1.269998,-0.745065 -0.491066,0 -0.948265,0.169333 -1.337731,0.474132 -0.118533,-0.372533 -0.440265,-0.389466 -0.745065,-0.389466 h -0.524932 c -0.3048,0 -0.812799,0.03387 -0.812799,0.626532 0,0.558799 0.321733,0.643466 0.931332,0.643466 v 4.842923 c -0.609599,0 -0.931332,0.08467 -0.931332,0.643466 0,0.609599 0.524933,0.626532 0.812799,0.626532 h 1.43933 c 0.3048,0 0.761999,-0.01693 0.761999,-0.626532 0,-0.558799 -0.270933,-0.643466 -0.880532,-0.643466 v -2.827861 c 0,-1.354664 0.575732,-2.099729 1.219198,-2.099729 0.321733,0 0.474132,0.270933 0.474132,1.219198 v 3.708392 c -0.355599,0.01693 -0.677332,0.1016 -0.677332,0.643466 0,0.609599 0.474133,0.626532 0.761999,0.626532 h 1.236131 c 0.304799,0 0.761998,-0.01693 0.761998,-0.626532 0,-0.558799 -0.287866,-0.643466 -0.897465,-0.643466 v -2.827861 c 0,-1.354664 0.592666,-2.099729 1.219198,-2.099729 0.338666,0 0.474132,0.270933 0.474132,1.219198 v 3.708392 c -0.338666,0.01693 -0.660398,0.1016 -0.660398,0.643466 0,0.609599 0.474132,0.626532 0.745065,0.626532 h 1.236131 c 0.304799,0 0.812798,-0.01693 0.812798,-0.626532 z m 9.829776,-3.064927 c 0,-2.116663 -1.540931,-3.776126 -3.352794,-3.776126 -0.728132,0 -1.422397,0.237066 -1.981196,0.660398 -0.01693,-0.389466 -0.169333,-0.575732 -0.778932,-0.575732 H 42.68086 c -0.321733,0 -0.812798,0.03387 -0.812798,0.643466 0,0.609598 0.507999,0.626532 0.795865,0.626532 h 0.609598 v 8.500516 H 42.68086 c -0.321733,0 -0.812798,0.01693 -0.812798,0.643466 0,0.609598 0.507999,0.626532 0.795865,0.626532 h 2.624661 c 0.287866,0 0.795865,-0.01693 0.795865,-0.626532 0,-0.626532 -0.491065,-0.643466 -0.812798,-0.643466 h -0.592666 v -2.963327 c 0.643466,0.558799 1.286931,0.677332 1.777997,0.677332 1.862663,0 3.53906,-1.625597 3.53906,-3.793059 z m -1.388531,0 c 0,1.49013 -1.083731,2.523061 -2.184396,2.523061 -1.202264,0 -1.727196,-1.371597 -1.727196,-2.116662 v -1.202265 c 0,-0.914398 0.897465,-1.710263 1.862663,-1.710263 1.151464,0 2.048929,1.151465 2.048929,2.506129 z M 59.08922,56.46532 c 0,-0.626533 -0.474133,-0.643466 -0.795865,-0.643466 h -1.930397 c -0.304799,0 -0.795865,0.03387 -0.795865,0.626532 0,0.626532 0.474133,0.643466 0.795865,0.643466 h 0.270933 l -1.456264,4.419591 -1.676396,-4.419591 h 0.220133 c 0.304799,0 0.795865,-0.01693 0.795865,-0.626532 0,-0.626533 -0.474133,-0.643466 -0.795865,-0.643466 h -1.930397 c -0.321732,0 -0.795865,0.01693 -0.795865,0.643466 0,0.609598 0.491066,0.626532 0.795865,0.626532 H 52.2143 l 2.370662,5.977455 c -0.06773,0.186266 -0.423333,1.371597 -0.609599,1.744129 -0.338666,0.643466 -0.863598,1.032932 -1.185331,1.032932 0.01693,-0.06773 0.186266,-0.118533 0.186266,-0.372533 0,-0.491066 -0.355599,-0.846665 -0.846665,-0.846665 -0.524932,0 -0.846665,0.355599 -0.846665,0.846665 0,0.761999 0.609599,1.490131 1.490131,1.490131 1.69333,0 2.523062,-2.252129 2.590795,-2.438396 l 2.523061,-7.433718 h 0.4064 c 0.304799,0 0.795865,-0.01693 0.795865,-0.626532 z"
id="text1392"
aria-label="lbm py" />
<path
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-6-9)"
d="M 36.797679,33.475 H 23.568513"
id="path1402-8-0-4"
inkscape:connector-curvature="0"
inkscape:path-effect="#path-effect1404-7-7-5"
inkscape:original-d="m 36.797679,33.475 c -4.259608,0.03317 -8.970011,-0.03362 -13.229166,0"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="188.45"
inkscape:export-ydpi="188.45" />
<g
id="g9842"
inkscape:export-xdpi="188.45"
inkscape:export-ydpi="188.45">
<path
sodipodi:nodetypes="cc"
inkscape:original-d="m 36.797679,33.475 c 2.23e-4,-4.259735 2.23e-4,-8.969879 0,-13.229167"
inkscape:path-effect="#path-effect1404"
inkscape:connector-curvature="0"
id="path1402"
d="M 36.797679,33.475 V 20.245833"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="m 36.797679,33.475 c 4.259736,2.23e-4 8.969879,2.23e-4 13.229167,0"
inkscape:path-effect="#path-effect1404-7"
inkscape:connector-curvature="0"
id="path1402-8"
d="M 36.797679,33.475 H 50.026846"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="m 36.797679,33.475 c 0.03317,4.259607 -0.03362,8.97001 0,13.229166"
inkscape:path-effect="#path-effect1404-7-7"
inkscape:connector-curvature="0"
id="path1402-8-0"
d="M 36.797679,33.475 V 46.704166"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-6)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="m 36.797679,33.475 c 4.259736,2.23e-4 8.13389,-13.228083 12.393178,-13.228306"
inkscape:path-effect="#path-effect1404-7-3"
inkscape:connector-curvature="0"
id="path1402-8-9"
d="M 36.797679,33.475 49.190857,20.246694"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-2)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="M 36.797679,33.475 C 32.537943,33.475223 27.827801,20.246056 23.568513,20.245833"
inkscape:path-effect="#path-effect1404-7-3-7"
inkscape:connector-curvature="0"
id="path1402-8-9-4"
d="M 36.797679,33.475 23.568513,20.245833"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-2-6)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="M 36.797679,33.475 C 32.537943,33.474776 27.827801,46.703943 23.568513,46.704166"
inkscape:path-effect="#path-effect1404-7-3-7-4"
inkscape:connector-curvature="0"
id="path1402-8-9-4-4"
d="M 36.797679,33.475 23.568513,46.704166"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-2-6-3)" />
<path
sodipodi:nodetypes="cc"
inkscape:original-d="m 36.797679,33.475 c 4.259736,-2.23e-4 7.646962,13.228943 11.90625,13.229166"
inkscape:path-effect="#path-effect1404-7-3-4"
inkscape:connector-curvature="0"
id="path1402-8-9-3"
d="m 36.797679,33.475 11.90625,13.229166"
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.845195;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-2-2)" />
</g>
</g>
</svg>
...@@ -2,23 +2,23 @@ ...@@ -2,23 +2,23 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="53.913788mm" width="53.913788mm"
height="53.913788mm" height="53.913788mm"
viewBox="0 0 53.913788 53.913788" viewBox="0 0 53.913788 53.913788"
version="1.1" version="1.1"
id="svg834" id="svg834"
inkscape:version="0.92.3 (2405546, 2018-03-11)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="logo.svg" sodipodi:docname="logo.svg"
inkscape:export-filename="/local/bauer/code/lbmpy/lbmpy/doc/img/logo.png" inkscape:export-filename="/local/bauer/code/lbmpy/lbmpy/doc/img/logo.png"
inkscape:export-xdpi="70.669998" inkscape:export-xdpi="70.669998"
inkscape:export-ydpi="70.669998"> inkscape:export-ydpi="70.669998"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs <defs
id="defs828"> id="defs828">
<marker <marker
...@@ -641,25 +641,31 @@ ...@@ -641,25 +641,31 @@
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="1.4" inkscape:zoom="1.4"
inkscape:cx="158.26067" inkscape:cx="158.21429"
inkscape:cy="-4.9825309" inkscape:cy="251.78571"
inkscape:document-units="mm" inkscape:document-units="mm"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="false" showgrid="false"
inkscape:window-width="1214" inkscape:window-width="1557"
inkscape:window-height="1052" inkscape:window-height="1122"
inkscape:window-x="1482" inkscape:window-x="0"
inkscape:window-y="524" inkscape:window-y="0"
inkscape:window-maximized="0" inkscape:window-maximized="0"
fit-margin-top="0" fit-margin-top="0"
fit-margin-left="0" fit-margin-left="0"
fit-margin-right="0" fit-margin-right="0"
fit-margin-bottom="0"> fit-margin-bottom="0"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid <inkscape:grid
type="xygrid" type="xygrid"
id="grid1886" id="grid1886"
originx="-9.8407853" originx="-9.8407853"
originy="-227.28709" /> originy="-227.28709"
spacingy="1"
spacingx="1"
units="mm" />
</sodipodi:namedview> </sodipodi:namedview>
<metadata <metadata
id="metadata831"> id="metadata831">
...@@ -688,21 +694,11 @@ ...@@ -688,21 +694,11 @@
ry="3.0735996" ry="3.0735996"
inkscape:export-xdpi="188.45" inkscape:export-xdpi="188.45"
inkscape:export-ydpi="188.45" /> inkscape:export-ydpi="188.45" />
<text <path
xml:space="preserve" style="font-weight:bold;font-size:16.9333px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';letter-spacing:0px;word-spacing:0px;fill:#ffffff;stroke-width:0.264583px"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:125%;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, ';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 21.505785,62.578241 c 0,-0.626532 -0.474132,-0.643466 -0.795865,-0.643466 h -2.015062 v -8.26345 c 0,-0.609599 -0.118533,-0.812798 -0.795865,-0.812798 h -2.607729 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643465 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 2.015063 v 7.806251 h -1.99813 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643466 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 5.435589 c 0.3048,0 0.795865,-0.01693 0.795865,-0.626532 z m 9.228643,-3.064927 c 0,-2.116663 -1.54093,-3.776126 -3.352793,-3.776126 -0.728132,0 -1.405464,0.237066 -1.964263,0.643465 v -2.709328 c 0,-0.609599 -0.118533,-0.812798 -0.795865,-0.812798 h -1.202265 c -0.321732,0 -0.812798,0.01693 -0.812798,0.643465 0,0.609599 0.507999,0.626532 0.795865,0.626532 h 0.609599 v 8.263451 c 0,0.406399 0.01693,0.812798 0.711198,0.812798 0.524933,0 0.660399,-0.237066 0.677332,-0.575732 0.643466,0.541865 1.303865,0.677332 1.79493,0.677332 1.862663,0 3.53906,-1.625597 3.53906,-3.793059 z m -1.388531,0 c 0,1.49013 -1.083731,2.523061 -2.184395,2.523061 -1.202265,0 -1.727197,-1.371597 -1.727197,-2.116662 v -1.202265 c 0,-0.914398 0.897465,-1.710263 1.862663,-1.710263 1.151464,0 2.048929,1.151465 2.048929,2.506129 z m 10.820373,3.064927 c 0,-0.558799 -0.321733,-0.643466 -0.931331,-0.643466 v -3.860792 c 0,-0.355599 -0.03387,-2.336795 -1.608664,-2.336795 -0.474132,0 -1.117598,0.186266 -1.608663,0.745065 -0.287867,-0.491066 -0.745066,-0.745065 -1.269998,-0.745065 -0.491066,0 -0.948265,0.169333 -1.337731,0.474132 -0.118533,-0.372533 -0.440265,-0.389466 -0.745065,-0.389466 h -0.524932 c -0.3048,0 -0.812799,0.03387 -0.812799,0.626532 0,0.558799 0.321733,0.643466 0.931332,0.643466 v 4.842923 c -0.609599,0 -0.931332,0.08467 -0.931332,0.643466 0,0.609599 0.524933,0.626532 0.812799,0.626532 h 1.43933 c 0.3048,0 0.761999,-0.01693 0.761999,-0.626532 0,-0.558799 -0.270933,-0.643466 -0.880532,-0.643466 v -2.827861 c 0,-1.354664 0.575732,-2.099729 1.219198,-2.099729 0.321733,0 0.474132,0.270933 0.474132,1.219198 v 3.708392 c -0.355599,0.01693 -0.677332,0.1016 -0.677332,0.643466 0,0.609599 0.474133,0.626532 0.761999,0.626532 h 1.236131 c 0.304799,0 0.761998,-0.01693 0.761998,-0.626532 0,-0.558799 -0.287866,-0.643466 -0.897465,-0.643466 v -2.827861 c 0,-1.354664 0.592666,-2.099729 1.219198,-2.099729 0.338666,0 0.474132,0.270933 0.474132,1.219198 v 3.708392 c -0.338666,0.01693 -0.660398,0.1016 -0.660398,0.643466 0,0.609599 0.474132,0.626532 0.745065,0.626532 h 1.236131 c 0.304799,0 0.812798,-0.01693 0.812798,-0.626532 z m 9.829776,-3.064927 c 0,-2.116663 -1.540931,-3.776126 -3.352794,-3.776126 -0.728132,0 -1.422397,0.237066 -1.981196,0.660398 -0.01693,-0.389466 -0.169333,-0.575732 -0.778932,-0.575732 H 42.68086 c -0.321733,0 -0.812798,0.03387 -0.812798,0.643466 0,0.609598 0.507999,0.626532 0.795865,0.626532 h 0.609598 v 8.500516 H 42.68086 c -0.321733,0 -0.812798,0.01693 -0.812798,0.643466 0,0.609598 0.507999,0.626532 0.795865,0.626532 h 2.624661 c 0.287866,0 0.795865,-0.01693 0.795865,-0.626532 0,-0.626532 -0.491065,-0.643466 -0.812798,-0.643466 h -0.592666 v -2.963327 c 0.643466,0.558799 1.286931,0.677332 1.777997,0.677332 1.862663,0 3.53906,-1.625597 3.53906,-3.793059 z m -1.388531,0 c 0,1.49013 -1.083731,2.523061 -2.184396,2.523061 -1.202264,0 -1.727196,-1.371597 -1.727196,-2.116662 v -1.202265 c 0,-0.914398 0.897465,-1.710263 1.862663,-1.710263 1.151464,0 2.048929,1.151465 2.048929,2.506129 z M 59.08922,56.46532 c 0,-0.626533 -0.474133,-0.643466 -0.795865,-0.643466 h -1.930397 c -0.304799,0 -0.795865,0.03387 -0.795865,0.626532 0,0.626532 0.474133,0.643466 0.795865,0.643466 h 0.270933 l -1.456264,4.419591 -1.676396,-4.419591 h 0.220133 c 0.304799,0 0.795865,-0.01693 0.795865,-0.626532 0,-0.626533 -0.474133,-0.643466 -0.795865,-0.643466 h -1.930397 c -0.321732,0 -0.795865,0.01693 -0.795865,0.643466 0,0.609598 0.491066,0.626532 0.795865,0.626532 H 52.2143 l 2.370662,5.977455 c -0.06773,0.186266 -0.423333,1.371597 -0.609599,1.744129 -0.338666,0.643466 -0.863598,1.032932 -1.185331,1.032932 0.01693,-0.06773 0.186266,-0.118533 0.186266,-0.372533 0,-0.491066 -0.355599,-0.846665 -0.846665,-0.846665 -0.524932,0 -0.846665,0.355599 -0.846665,0.846665 0,0.761999 0.609599,1.490131 1.490131,1.490131 1.69333,0 2.523062,-2.252129 2.590795,-2.438396 l 2.523061,-7.433718 h 0.4064 c 0.304799,0 0.795865,-0.01693 0.795865,-0.626532 z"
x="13.547134"
y="63.204773"
id="text1392" id="text1392"
inkscape:export-xdpi="188.45" aria-label="lbm py" />
inkscape:export-ydpi="188.45"><tspan
sodipodi:role="line"
id="tspan1390"
x="13.547134"
y="63.204773"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16.93333244px;font-family:'Latin Modern Mono Light';-inkscape-font-specification:'Latin Modern Mono Light, Bold';fill:#ffffff;stroke-width:0.26458332px">lbm<tspan
style="font-size:2.82222223px"
id="tspan1398"> </tspan>py</tspan></text>
<path <path
style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.84519458;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-6-9)" style="fill:none;fill-rule:evenodd;stroke:#dddddd;stroke-width:0.84519458;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-8-6-9)"
d="M 36.797679,33.475 H 23.568513" d="M 36.797679,33.475 H 23.568513"
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
from IPython.display import clear_output from IPython.display import clear_output
from lbmpy.session import * from lbmpy.session import *
from lbmpy.relaxationrates import relaxation_rate_from_lattice_viscosity from lbmpy.relaxationrates import relaxation_rate_from_lattice_viscosity
from pystencils.typing import BasicType, TypedSymbol
``` ```
   
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
   
# Demo: Interpolation Bounce Back Boundaries # Demo: Interpolation Bounce Back Boundaries
In this notebook we present how to use interpolation bounce back boundaries. We will show this on a simple flow around sphere in two dimensions using the linearised bounce back boundary by [Bouzidi et. al.](https://doi.org/10.1063/1.1399290) and the `QuadraticBounceBack` boundary condition by [Geier et. al.](https://www.sciencedirect.com/science/article/pii/S0898122115002126) In this notebook we present how to use interpolation bounce back boundaries. We will show this on a simple flow around sphere in two dimensions using the linearised bounce back boundary by [Bouzidi et. al.](https://doi.org/10.1063/1.1399290) and the `QuadraticBounceBack` boundary condition by [Geier et. al.](https://www.sciencedirect.com/science/article/pii/S0898122115002126)
   
The first part of the demo is similar to other demos / tutorials, so we will not go into detail about these parts The first part of the demo is similar to other demos / tutorials, so we will not go into detail about these parts
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
stencil = LBStencil(Stencil.D2Q9) stencil = LBStencil(Stencil.D2Q9)
reference_length = 30 reference_length = 30
maximal_velocity = 0.05 maximal_velocity = 0.05
reynolds_number = 500 reynolds_number = 500
kinematic_vicosity = (reference_length * maximal_velocity) / reynolds_number kinematic_vicosity = (reference_length * maximal_velocity) / reynolds_number
   
initial_velocity=(maximal_velocity, 0) initial_velocity=(maximal_velocity, 0)
omega = relaxation_rate_from_lattice_viscosity(kinematic_vicosity) omega = relaxation_rate_from_lattice_viscosity(kinematic_vicosity)
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
domain_size = (400, 150) domain_size = (400, 150)
dim = len(domain_size) dim = len(domain_size)
circle_mid = np.array((40, 75)) circle_mid = np.array((40, 75))
circle_rad = 10 circle_rad = 10
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
dh = ps.create_data_handling(domain_size=domain_size) dh = ps.create_data_handling(domain_size=domain_size)
   
src = dh.add_array('pdfs', values_per_cell=len(stencil)) src = dh.add_array('pdfs', values_per_cell=len(stencil))
dh.fill(src.name, 0.0, ghost_layers=True) dh.fill(src.name, 0.0, ghost_layers=True)
dst = dh.add_array('pdfs_tmp', values_per_cell=len(stencil)) dst = dh.add_array('pdfs_tmp', values_per_cell=len(stencil))
dh.fill(dst.name, 0.0, ghost_layers=True) dh.fill(dst.name, 0.0, ghost_layers=True)
   
velField = dh.add_array('velField', values_per_cell=dh.dim) velField = dh.add_array('velField', values_per_cell=dh.dim)
dh.fill('velField', 0.0, ghost_layers=True) dh.fill('velField', 0.0, ghost_layers=True)
   
densityField = dh.add_array('densityField', values_per_cell=1) densityField = dh.add_array('densityField', values_per_cell=1)
dh.fill('densityField', 1.0, ghost_layers=True) dh.fill('densityField', 1.0, ghost_layers=True)
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
lbm_config = LBMConfig(stencil=stencil, method=Method.CUMULANT, relaxation_rate=omega, lbm_config = LBMConfig(stencil=stencil, method=Method.CUMULANT, relaxation_rate=omega,
compressible=True, output={"velocity": velField, "density": densityField}) compressible=True, output={"velocity": velField, "density": densityField})
   
method = create_lb_method(lbm_config=lbm_config) method = create_lb_method(lbm_config=lbm_config)
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
init = pdf_initialization_assignments(method, 1.0, (0.0, 0.0, 0.0), src.center_vector) init = pdf_initialization_assignments(method, 1.0, (0.0, 0.0, 0.0), src.center_vector)
   
ast_init = ps.create_kernel(init, target=dh.default_target) ast_init = ps.create_kernel(init, target=dh.default_target)
kernel_init = ast_init.compile() kernel_init = ast_init.compile()
   
dh.run_kernel(kernel_init) dh.run_kernel(kernel_init)
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
lbm_optimisation = LBMOptimisation(symbolic_field=src, symbolic_temporary_field=dst) lbm_optimisation = LBMOptimisation(symbolic_field=src, symbolic_temporary_field=dst)
update = create_lb_update_rule(lb_method=method, update = create_lb_update_rule(lb_method=method,
lbm_config=lbm_config, lbm_config=lbm_config,
lbm_optimisation=lbm_optimisation) lbm_optimisation=lbm_optimisation)
   
ast_kernel = ps.create_kernel(update, target=dh.default_target) ast_kernel = ps.create_kernel(update, target=dh.default_target)
kernel = ast_kernel.compile() kernel = ast_kernel.compile()
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
def set_sphere(x, y, *_): def set_sphere(x, y, *_):
return (x-circle_mid[0])**2 + (y-circle_mid[1])**2 < circle_rad**2 return (x-circle_mid[0])**2 + (y-circle_mid[1])**2 < circle_rad**2
``` ```
   
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
   
# Interpolation Boundary Conditions implementation details # Interpolation Boundary Conditions implementation details
   
The most important part of the interpolation bounce back boundary is, that we need to define the distance to the wall for each boundary cell. Thus, we need to provide a Python CallBack function to the boundary that calculates the normalised wall distance `q` for each cell and stores the value in `boundary_data`. The normalised wall distance is defined as: The most important part of the interpolation bounce back boundary is, that we need to define the distance to the wall for each boundary cell. Thus, we need to provide a Python CallBack function to the boundary that calculates the normalised wall distance `q` for each cell and stores the value in `boundary_data`. The normalised wall distance is defined as:
   
$$ $$
\begin{align} \begin{align}
q = \frac{|\boldsymbol{x}_{F} - \boldsymbol{x}_{w}|}{|\boldsymbol{x}_{F} - \boldsymbol{x}_{b}|}. q = \frac{|\boldsymbol{x}_{F} - \boldsymbol{x}_{w}|}{|\boldsymbol{x}_{F} - \boldsymbol{x}_{b}|}.
\end{align} \end{align}
$$ $$
   
The variable `boundary_data` is an index vector that every boundary condition holds internally. For simple boundaries it stores the `x`- and `y`- (and `z` in 3D) coordinate to represent a fluid cell that is next to a boundary cell and the lattice direction `dir` to get from the fluid cell to the boundary cell. The variable `boundary_data` is an index vector that every boundary condition holds internally. For simple boundaries it stores the `x`- and `y`- (and `z` in 3D) coordinate to represent a fluid cell that is next to a boundary cell and the lattice direction `dir` to get from the fluid cell to the boundary cell.
   
In the case of the interpolation boundaries we have an additional value `q` that needs to be stored in each cell. This value needs to be between 0 and 1, otherwise the boundary condition would fall back to a simple bounce back boundary without interpolation. In the case of the interpolation boundaries we have an additional value `q` that needs to be stored in each cell. This value needs to be between 0 and 1, otherwise the boundary condition would fall back to a simple bounce back boundary without interpolation.
   
<center> <center>
<img src="../img/Boundary.svg" alt="Boundary.svg" width="400" height="400"> <img src="../img/Boundary.svg" alt="Boundary.svg" width="400" height="400">
</center> </center>
   
Two dimensional representation of the boundary nodes with the normalised wall distance `q`. The figure was inspired by [Directional lattice Boltzmann boundary conditions](https://doi.org/10.13097/archive-ouverte/unige:160770). Two dimensional representation of the boundary nodes with the normalised wall distance `q`. The figure was inspired by [Directional lattice Boltzmann boundary conditions](https://doi.org/10.13097/archive-ouverte/unige:160770).
   
The linear Bouzidi boundary condition is implemented using the following equation The linear Bouzidi boundary condition is implemented using the following equation
$$ $$
\begin{align} \begin{align}
f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b) = f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b) =
\begin{cases} \begin{cases}
\frac{1}{2q} f_{i}(\boldsymbol{x}_F) + \frac{2q-1}{2q} f_{\bar{i}}(\boldsymbol{x}_{F}), & \text{if } q \geq 0.5\\ \frac{1}{2q} f_{i}(\boldsymbol{x}_F) + \frac{2q-1}{2q} f_{\bar{i}}(\boldsymbol{x}_{F}), & \text{if } q \geq 0.5\\
2 q f_{i}(\boldsymbol{x}_F) + (1 - 2q) f_{i}(\boldsymbol{x}_{FF}), & q > 0 \land q < 0.5 \\ 2 q f_{i}(\boldsymbol{x}_F) + (1 - 2q) f_{i}(\boldsymbol{x}_{FF}), & q > 0 \land q < 0.5 \\
f_{i}(\boldsymbol{x}_F), & q = -1 f_{i}(\boldsymbol{x}_F), & q = -1
\end{cases} \end{cases}
\end{align} \end{align}
$$ $$
   
where $f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b)$ is the missing lattice link that will be needed in the next streaming step. Furthermore, $f_{i}(\boldsymbol{x}_F)$ represents the lattice link flowing in wall direction at $\boldsymbol{x}_{F}$, $f_{\bar{i}}(\boldsymbol{x}_{F})$ is the inverse direction at $\boldsymbol{x}_{F}$ and $f_{i}(\boldsymbol{x}_{FF})$ is the lattice link at the next cell. where $f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b)$ is the missing lattice link that will be needed in the next streaming step. Furthermore, $f_{i}(\boldsymbol{x}_F)$ represents the lattice link flowing in wall direction at $\boldsymbol{x}_{F}$, $f_{\bar{i}}(\boldsymbol{x}_{F})$ is the inverse direction at $\boldsymbol{x}_{F}$ and $f_{i}(\boldsymbol{x}_{FF})$ is the lattice link at the next cell.
   
**The linearised bounce back boundary by [Bouzidi et. al.](https://doi.org/10.1063/1.1399290) needs a second fluid node for the interpolation. This fluid node is not guaranteed to exist. In this case, we implemented a fallback scenario to a simple bounce back scheme with interpolation by setting `q` to -1.** **The linearised bounce back boundary by [Bouzidi et. al.](https://doi.org/10.1063/1.1399290) needs a second fluid node for the interpolation. This fluid node is not guaranteed to exist. In this case, we implemented a fallback scenario to a simple bounce back scheme with interpolation by setting `q` to -1.**
   
To overcome this problem, we can use the `QuadraticBounceBack` boundary condition by [Geier et. al.](https://www.sciencedirect.com/science/article/pii/S0898122115002126). It uses the following rule: To overcome this problem, we can use the `QuadraticBounceBack` boundary condition by [Geier et. al.](https://www.sciencedirect.com/science/article/pii/S0898122115002126). It uses the following rule:
   
$$ $$
\begin{align} \begin{align}
f_{\bar{i}}^{\mathrm{p}}(\boldsymbol{x}_F) &= \frac{f_{\bar{i}}(\boldsymbol{x}_F) - f_{i}(\boldsymbol{x}_F)}{2} + \frac{f_{\bar{i}}(\boldsymbol{x}_F) + f_{i}(\boldsymbol{x}_F)- \omega(f_{\bar{i}}^{\mathrm{eq}}(\boldsymbol{x}_F) + f_{i}^{\mathrm{eq}}(\boldsymbol{x}_F))}{2 - 2\omega} \\ f_{\bar{i}}^{\mathrm{p}}(\boldsymbol{x}_F) &= \frac{f_{\bar{i}}(\boldsymbol{x}_F) - f_{i}(\boldsymbol{x}_F)}{2} + \frac{f_{\bar{i}}(\boldsymbol{x}_F) + f_{i}(\boldsymbol{x}_F)- \omega(f_{\bar{i}}^{\mathrm{eq}}(\boldsymbol{x}_F) + f_{i}^{\mathrm{eq}}(\boldsymbol{x}_F))}{2 - 2\omega} \\
f_{\bar{i}}^{\mathrm{wall}}(\boldsymbol{x}_F) &= (1 - q)f_{\bar{i}}^{\mathrm{p}}(\boldsymbol{x}_F) + q f_{\bar{i}}(\boldsymbol{x}_F) \\ f_{\bar{i}}^{\mathrm{wall}}(\boldsymbol{x}_F) &= (1 - q)f_{\bar{i}}^{\mathrm{p}}(\boldsymbol{x}_F) + q f_{\bar{i}}(\boldsymbol{x}_F) \\
f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b) &= \frac{1}{q+1} f_{\bar{i}}^{\mathrm{wall}}(\boldsymbol{x}_F) + \frac{q}{q+1}f_{i}(\boldsymbol{x}_F) f_{\bar{i}}^{t + 1}(\boldsymbol{x}_b) &= \frac{1}{q+1} f_{\bar{i}}^{\mathrm{wall}}(\boldsymbol{x}_F) + \frac{q}{q+1}f_{i}(\boldsymbol{x}_F)
\end{align} \end{align}
$$ $$
   
In this BC the idea is to realise the interpolation with the pre collision PDF value (marked with the subscript p). Since the pre collision PDF value is not available a simple reconstruction needs to be done. This happens via the BGK rule and the relaxation rate for the fluid viscosity. Thus, this boundary condition needs the equilibrium at the wall. However, the equilibrium at the wall can be calculated inplace from the PDFs. Thus, this BC does not need any further information and can be applied in all cases. Furthermore, we have no more branches with the subgrid distance `q` In this BC the idea is to realise the interpolation with the pre collision PDF value (marked with the subscript p). Since the pre collision PDF value is not available a simple reconstruction needs to be done. This happens via the BGK rule and the relaxation rate for the fluid viscosity. Thus, this boundary condition needs the equilibrium at the wall. However, the equilibrium at the wall can be calculated inplace from the PDFs. Thus, this BC does not need any further information and can be applied in all cases. Furthermore, we have no more branches with the subgrid distance `q`
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
def init_wall_distance(boundary_data, **_): def init_wall_distance(boundary_data, **_):
dim = boundary_data.dim dim = boundary_data.dim
coords = [coord for coord, _ in zip(['x', 'y', 'z'], range(dim))] coords = [coord for coord, _ in zip(['x', 'y', 'z'], range(dim))]
   
for cell in boundary_data.index_array: for cell in boundary_data.index_array:
direction = np.array(stencil[cell['dir']]) direction = np.array(stencil[cell['dir']])
fluid_cell = np.array(tuple([cell[coord] for coord in coords])) - np.array([0.5] * dim) fluid_cell = np.array(tuple([cell[coord] for coord in coords])) - np.array([0.5] * dim)
boundary_cell = fluid_cell + direction boundary_cell = fluid_cell + direction
   
f = fluid_cell - circle_mid f = fluid_cell - circle_mid
d = (boundary_cell - circle_mid) - f d = (boundary_cell - circle_mid) - f
   
a = d.dot(d) a = d.dot(d)
b = 2.0 * ( d.dot(f)) b = 2.0 * ( d.dot(f))
c = f.dot(f) - circle_rad**2 c = f.dot(f) - circle_rad**2
   
bb4ac = b * b - ( 4.0 * a * c ) bb4ac = b * b - ( 4.0 * a * c )
assert bb4ac > 0 assert bb4ac > 0
   
sqrtbb4ac = np.sqrt(bb4ac) sqrtbb4ac = np.sqrt(bb4ac)
q = np.min( [( -b + sqrtbb4ac ) / ( 2.0 * a ), ( -b - sqrtbb4ac ) / ( 2.0 * a )] ) q = np.min( [( -b + sqrtbb4ac ) / ( 2.0 * a ), ( -b - sqrtbb4ac ) / ( 2.0 * a )] )
   
assert q > 0 and q < 1 assert q > 0 and q < 1
   
cell['q'] = q cell['q'] = q
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
bh = LatticeBoltzmannBoundaryHandling(method, dh, src.name, name="bh") bh = LatticeBoltzmannBoundaryHandling(method, dh, src.name, name="bh")
   
inflow = UBB(initial_velocity) inflow = UBB(initial_velocity)
outflow = ExtrapolationOutflow(stencil[4], method) outflow = ExtrapolationOutflow(stencil[4], method)
wall = NoSlip("wall") wall = NoSlip("wall")
# obstacle = NoSlip("obstacle") # obstacle = NoSlip("obstacle")
# obstacle = NoSlipLinearBouzidi("obstacle", init_wall_distance=init_wall_distance) # obstacle = NoSlipLinearBouzidi("obstacle", init_wall_distance=init_wall_distance)
obstacle = QuadraticBounceBack(omega, "obstacle", init_wall_distance=init_wall_distance) obstacle = QuadraticBounceBack(omega, "obstacle", init_wall_distance=init_wall_distance)
   
bh.set_boundary(inflow, slice_from_direction('W', dim)) bh.set_boundary(inflow, slice_from_direction('W', dim))
bh.set_boundary(outflow, slice_from_direction('E', dim)) bh.set_boundary(outflow, slice_from_direction('E', dim))
for direction in ('N', 'S'): for direction in ('N', 'S'):
bh.set_boundary(wall, slice_from_direction(direction, dim)) bh.set_boundary(wall, slice_from_direction(direction, dim))
   
bh.set_boundary(obstacle, mask_callback=set_sphere) bh.set_boundary(obstacle, mask_callback=set_sphere)
   
plt.figure(dpi=200) plt.figure(dpi=200)
plt.boundary_handling(bh) plt.boundary_handling(bh)
``` ```
   
%% Output %% Output
   
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
def timeloop(timeSteps): def timeloop(timeSteps):
for i in range(timeSteps): for i in range(timeSteps):
bh() bh()
dh.run_kernel(kernel) dh.run_kernel(kernel)
dh.swap(src.name, dst.name) dh.swap(src.name, dst.name)
``` ```
   
%% Cell type:code id: tags: %% Cell type:code id: tags:
   
``` python ``` python
mask = np.fromfunction(set_sphere, (domain_size[0], domain_size[1], len(domain_size))) mask = np.fromfunction(set_sphere, (domain_size[0], domain_size[1], len(domain_size)))
if 'is_test_run' not in globals(): if 'is_test_run' not in globals():
timeloop(50000) # initial steps timeloop(50000) # initial steps
   
def run(): def run():
timeloop(50) timeloop(50)
return np.ma.array(dh.gather_array('velField'), mask=mask) return np.ma.array(dh.gather_array('velField'), mask=mask)
   
animation = plt.vector_field_magnitude_animation(run, frames=600, rescale=True) animation = plt.vector_field_magnitude_animation(run, frames=600, rescale=True)
set_display_mode('video') set_display_mode('video')
res = display_animation(animation) res = display_animation(animation)
else: else:
timeloop(10) timeloop(10)
res = None res = None
res res
``` ```
   
%% Output %% Output
   
<IPython.core.display.HTML object> <IPython.core.display.HTML object>
Source diff could not be displayed: it is too large. Options to address this: view the blob.
from __future__ import annotations
from typing import Sequence
from argparse import ArgumentParser
import os
import nox
import subprocess
import re
nox.options.sessions = ["lint", "typecheck"]
def get_cuda_version(session: nox.Session) -> None | tuple[int, ...]:
query_args = ["nvcc", "--version"]
try:
query_result = subprocess.run(query_args, capture_output=True)
except FileNotFoundError:
return None
matches = re.findall(r"release \d+\.\d+", str(query_result.stdout))
if matches:
match = matches[0]
version_string = match.split()[-1]
try:
return tuple(int(v) for v in version_string.split("."))
except ValueError:
pass
session.warn("nvcc was found, but I am unable to determine the CUDA version.")
return None
def install_cupy(
session: nox.Session, cupy_version: str, skip_if_no_cuda: bool = False
):
if cupy_version is not None:
cuda_version = get_cuda_version(session)
if cuda_version is None or cuda_version[0] not in (11, 12):
if skip_if_no_cuda:
session.skip(
"No compatible installation of CUDA found - Need either CUDA 11 or 12"
)
else:
session.warn(
"Running without cupy: no compatbile installation of CUDA found. Need either CUDA 11 or 12."
)
return
cuda_major = cuda_version[0]
cupy_package = f"cupy-cuda{cuda_major}x=={cupy_version}"
session.install(cupy_package)
def check_external_doc_dependencies(session: nox.Session):
dot_args = ["dot", "--version"]
try:
_ = subprocess.run(dot_args, capture_output=True)
except FileNotFoundError:
session.error(
"Unable to build documentation: "
"Command `dot` from the `graphviz` package (https://www.graphviz.org/) is not available"
)
def editable_install(session: nox.Session, opts: Sequence[str] = ()):
if opts:
opts_str = "[" + ",".join(opts) + "]"
else:
opts_str = ""
session.install("-e", f".{opts_str}")
def install_pystencils_master(session: nox.Session):
session.install("git+https://i10git.cs.fau.de/pycodegen/pystencils.git@master")
def install_sympy_master(session: nox.Session):
session.install("--upgrade", "git+https://github.com/sympy/sympy.git@master")
@nox.session(python="3.10", tags=["qa", "code-quality"])
def lint(session: nox.Session):
"""Lint code using flake8"""
session.install("flake8")
session.run("flake8", "src/lbmpy")
@nox.session(python="3.10", tags=["qa", "code-quality"])
def typecheck(session: nox.Session):
"""Run MyPy for static type checking"""
editable_install(session)
session.install("mypy")
session.run("mypy", "src/lbmpy")
def run_testsuite(session: nox.Session, coverage: bool = True):
num_cores = os.cpu_count()
args = [
"pytest",
"-v",
"-n",
str(num_cores),
"-m",
"not longrun",
"--html",
"test-report/index.html",
"--junitxml=report.xml",
]
if coverage:
args += [
"--cov-report=term",
"--cov=.",
]
session.run(*args)
if coverage:
session.run("coverage", "html")
session.run("coverage", "xml")
@nox.session(python=["3.10", "3.11", "3.12", "3.13"])
def testsuite_cpu(session: nox.Session):
install_pystencils_master(session)
editable_install(session, ["alltrafos", "use_cython", "interactive", "tests"])
run_testsuite(session, coverage=False)
@nox.session(python=["3.10", "3.11", "3.12", "3.13"])
@nox.parametrize("cupy_version", ["12", "13"], ids=["cupy12", "cupy13"])
def testsuite_gpu(session: nox.Session, cupy_version: str | None):
install_cupy(session, cupy_version, skip_if_no_cuda=True)
install_pystencils_master(session)
editable_install(session, ["alltrafos", "use_cython", "interactive", "tests"])
run_testsuite(session)
@nox.parametrize("cupy_version", [None, "12", "13"], ids=["cpu", "cupy12", "cupy13"])
@nox.session(python="3.10", tags=["test"])
def testsuite_pystencils2(session: nox.Session, cupy_version: str | None):
if cupy_version is not None:
install_cupy(session, cupy_version, skip_if_no_cuda=True)
session.install(
"git+https://i10git.cs.fau.de/pycodegen/pystencils.git@v2.0-dev"
)
editable_install(session, ["alltrafos", "use_cython", "interactive", "tests"])
run_testsuite(session)
@nox.session
def quicktest(session: nox.Session):
parser = ArgumentParser()
parser.add_argument(
"--sympy-master", action="store_true", help="Use latest SymPy master revision"
)
args = parser.parse_args(session.posargs)
install_pystencils_master(session)
editable_install(session)
if args.sympy_master:
install_sympy_master(session)
session.run("python", "quicktest.py")
...@@ -11,7 +11,7 @@ authors = [ ...@@ -11,7 +11,7 @@ authors = [
] ]
license = { file = "COPYING.txt" } license = { file = "COPYING.txt" }
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = ["pystencils>=1.3", "sympy>=1.9,<=1.12.1", "numpy>=1.8.0", "appdirs", "joblib"] dependencies = ["pystencils>=1.3", "sympy>=1.12", "numpy>=1.8.0", "appdirs", "joblib", "packaging"]
classifiers = [ classifiers = [
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",
"Framework :: Jupyter", "Framework :: Jupyter",
......
...@@ -3,7 +3,12 @@ testpaths = src tests doc/notebooks ...@@ -3,7 +3,12 @@ testpaths = src tests doc/notebooks
pythonpath = src pythonpath = src
python_files = test_*.py *_test.py scenario_*.py python_files = test_*.py *_test.py scenario_*.py
norecursedirs = *.egg-info .git .cache .ipynb_checkpoints htmlcov norecursedirs = *.egg-info .git .cache .ipynb_checkpoints htmlcov
addopts = --doctest-modules --durations=20 --cov-config pytest.ini addopts =
--doctest-modules --durations=20
--cov-config pytest.ini
--ignore=src/lbmpy/custom_code_nodes.py
--ignore=src/lbmpy/lookup_tables.py
--ignore=src/lbmpy/phasefield_allen_cahn/contact_angle.py
markers = markers =
longrun: tests only run at night since they have large execution time longrun: tests only run at night since they have large execution time
notebook: mark for notebooks notebook: mark for notebooks
...@@ -24,7 +29,10 @@ omit = doc/* ...@@ -24,7 +29,10 @@ omit = doc/*
setup.py setup.py
conftest.py conftest.py
versioneer.py versioneer.py
quicktest.py
noxfile.py
src/lbmpy/_version.py src/lbmpy/_version.py
src/lbmpy/_compat.py
venv/ venv/
[report] [report]
......
from pystencils import __version__ as ps_version
# Determine if we're running pystencils 1.x or 2.x
version_tokes = ps_version.split(".")
PYSTENCILS_VERSION_MAJOR = int(version_tokes[0])
IS_PYSTENCILS_2 = PYSTENCILS_VERSION_MAJOR == 2
if IS_PYSTENCILS_2:
from pystencils.defaults import DEFAULTS
def get_loop_counter_symbol(coord: int):
return DEFAULTS.spatial_counters[coord]
def get_supported_instruction_sets():
from pystencils import Target
vector_targets = Target.available_vector_cpu_targets()
isas = []
for target in vector_targets:
tokens = target.name.split("_")
isas.append(tokens[-1].lower())
return isas
else:
from pystencils.backends.simd_instruction_sets import (
get_supported_instruction_sets as get_supported_instruction_sets_,
)
get_supported_instruction_sets = get_supported_instruction_sets_
def get_loop_counter_symbol(coord: int):
from pystencils.astnodes import LoopOverCoordinate
return LoopOverCoordinate.get_loop_counter_symbol(coord)
def import_guard_pystencils1(feature):
if IS_PYSTENCILS_2:
raise ImportError(
f"The following feature is not yet available when running pystencils 2.x: {feature}"
)
return True
import itertools import itertools
from pystencils import CreateKernelConfig, Field, Assignment, AssignmentCollection from pystencils import CreateKernelConfig, Field, Assignment, AssignmentCollection, Target
from pystencils.slicing import ( from pystencils.slicing import (
shift_slice, shift_slice,
get_slice_before_ghost_layer, get_slice_before_ghost_layer,
...@@ -14,7 +14,6 @@ from lbmpy.advanced_streaming.utility import ( ...@@ -14,7 +14,6 @@ from lbmpy.advanced_streaming.utility import (
numeric_offsets, numeric_offsets,
) )
from pystencils.datahandling import SerialDataHandling from pystencils.datahandling import SerialDataHandling
from pystencils.enums import Target
from itertools import chain from itertools import chain
......
...@@ -2,10 +2,17 @@ import numpy as np ...@@ -2,10 +2,17 @@ import numpy as np
import sympy as sp import sympy as sp
import pystencils as ps import pystencils as ps
from pystencils.typing import TypedSymbol, create_type from .._compat import IS_PYSTENCILS_2
from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is_inplace, Timestep
from lbmpy.custom_code_nodes import TranslationArraysNode if IS_PYSTENCILS_2:
from pystencils import TypedSymbol, create_type
from pystencils.types.quick import Arr
from lbmpy.lookup_tables import TranslationArraysNode
else:
from pystencils.typing import TypedSymbol, create_type
from ..custom_code_nodes import TranslationArraysNode
from lbmpy.advanced_streaming.utility import get_accessor, inverse_dir_index, is_inplace, Timestep
from itertools import product from itertools import product
...@@ -64,13 +71,21 @@ class BetweenTimestepsIndexing: ...@@ -64,13 +71,21 @@ class BetweenTimestepsIndexing:
assert f_dir in ['in', 'out'] assert f_dir in ['in', 'out']
inv = '_inv' if inverse else '' inv = '_inv' if inverse else ''
name = f"f_{f_dir}{inv}_dir_idx" name = f"f_{f_dir}{inv}_dir_idx"
return TypedSymbol(name, self._index_dtype) if IS_PYSTENCILS_2:
return TypedSymbol(name, Arr(self._index_dtype, self._q))
else:
return TypedSymbol(name, self._index_dtype)
def _offset_array_symbols(self, f_dir, inverse): def _offset_array_symbols(self, f_dir, inverse):
assert f_dir in ['in', 'out'] assert f_dir in ['in', 'out']
inv = '_inv' if inverse else '' inv = '_inv' if inverse else ''
name_base = f"f_{f_dir}{inv}_offsets_" name_base = f"f_{f_dir}{inv}_offsets_"
symbols = [TypedSymbol(name_base + d, self._index_dtype) for d in self._coordinate_names]
if IS_PYSTENCILS_2:
symbols = [TypedSymbol(name_base + d, Arr(self._index_dtype, self._q)) for d in self._coordinate_names]
else:
symbols = [TypedSymbol(name_base + d, self._index_dtype) for d in self._coordinate_names]
return symbols return symbols
def _array_symbols(self, f_dir, inverse, index): def _array_symbols(self, f_dir, inverse, index):
...@@ -169,15 +184,25 @@ class BetweenTimestepsIndexing: ...@@ -169,15 +184,25 @@ class BetweenTimestepsIndexing:
indices, offsets = self._get_translated_indices_and_offsets(f_dir, inv) indices, offsets = self._get_translated_indices_and_offsets(f_dir, inv)
index_array_symbol = self._index_array_symbol(f_dir, inv) index_array_symbol = self._index_array_symbol(f_dir, inv)
symbols_defined.add(index_array_symbol) symbols_defined.add(index_array_symbol)
array_content.append((self._index_dtype, index_array_symbol.name, indices))
if IS_PYSTENCILS_2:
array_content.append((index_array_symbol, indices))
else:
array_content.append((self._index_dtype, index_array_symbol.name, indices))
for f_dir, inv in self._required_offset_arrays: for f_dir, inv in self._required_offset_arrays:
indices, offsets = self._get_translated_indices_and_offsets(f_dir, inv) indices, offsets = self._get_translated_indices_and_offsets(f_dir, inv)
offset_array_symbols = self._offset_array_symbols(f_dir, inv) offset_array_symbols = self._offset_array_symbols(f_dir, inv)
symbols_defined |= set(offset_array_symbols) symbols_defined |= set(offset_array_symbols)
for d, arrsymb in enumerate(offset_array_symbols): for d, arrsymb in enumerate(offset_array_symbols):
array_content.append((self._offsets_dtype, arrsymb.name, offsets[d])) if IS_PYSTENCILS_2:
array_content.append((arrsymb, offsets[d]))
else:
array_content.append((self._offsets_dtype, arrsymb.name, offsets[d]))
return TranslationArraysNode(array_content, symbols_defined) if IS_PYSTENCILS_2:
return TranslationArraysNode(array_content)
else:
return TranslationArraysNode(array_content, symbols_defined)
# end class AdvancedStreamingIndexing # end class AdvancedStreamingIndexing
import sympy as sp import sympy as sp
from .._compat import IS_PYSTENCILS_2
from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing
from lbmpy.advanced_streaming.utility import Timestep, get_accessor from lbmpy.advanced_streaming.utility import Timestep, get_accessor
from lbmpy.custom_code_nodes import LbmWeightInfo
from pystencils.boundaries.boundaryhandling import BoundaryOffsetInfo from pystencils.boundaries.boundaryhandling import BoundaryOffsetInfo
from pystencils.assignment import Assignment from pystencils import Assignment
from pystencils.astnodes import Block, Conditional, LoopOverCoordinate, SympyAssignment from pystencils.simp import AssignmentCollection, sympy_cse_on_assignment_list
from pystencils.simp.assignment_collection import AssignmentCollection
from pystencils.simp.simplifications import sympy_cse_on_assignment_list
from pystencils.stencil import inverse_direction from pystencils.stencil import inverse_direction
from pystencils.sympyextensions import fast_subs from pystencils.sympyextensions import fast_subs
if IS_PYSTENCILS_2:
from lbmpy.lookup_tables import LbmWeightInfo
else:
from lbmpy.custom_code_nodes import LbmWeightInfo
from pystencils.astnodes import Block, Conditional, LoopOverCoordinate, SympyAssignment # TODO replace
def direction_indices_in_direction(direction, stencil): def direction_indices_in_direction(direction, stencil):
for i, offset in enumerate(stencil): for i, offset in enumerate(stencil):
...@@ -58,6 +63,9 @@ def border_conditions(direction, field, ghost_layers=1): ...@@ -58,6 +63,9 @@ def border_conditions(direction, field, ghost_layers=1):
def boundary_conditional(boundary, direction, streaming_pattern, prev_timestep, lb_method, output_field, cse=False): def boundary_conditional(boundary, direction, streaming_pattern, prev_timestep, lb_method, output_field, cse=False):
if IS_PYSTENCILS_2:
raise NotImplementedError("In-Kernel Boundaries are not yet available on pystencils 2.0")
stencil = lb_method.stencil stencil = lb_method.stencil
dir_indices = direction_indices_in_direction(direction, stencil) dir_indices = direction_indices_in_direction(direction, stencil)
......
...@@ -2,21 +2,38 @@ import abc ...@@ -2,21 +2,38 @@ import abc
from enum import Enum, auto from enum import Enum, auto
from warnings import warn from warnings import warn
from pystencils import Assignment, Field from pystencils import Assignment, AssignmentCollection, Field, TypedSymbol
from pystencils.simp.assignment_collection import AssignmentCollection
from pystencils.stencil import offset_to_direction_string, direction_string_to_offset, inverse_direction from pystencils.stencil import offset_to_direction_string, direction_string_to_offset, inverse_direction
from pystencils.sympyextensions import get_symmetric_part, simplify_by_equality, scalar_product from pystencils.sympyextensions import get_symmetric_part, simplify_by_equality, scalar_product
from pystencils.typing import create_type, TypedSymbol
from lbmpy.advanced_streaming.utility import AccessPdfValues, Timestep from lbmpy.advanced_streaming.utility import AccessPdfValues, Timestep
from lbmpy.custom_code_nodes import (NeighbourOffsetArrays, MirroredStencilDirections, LbmWeightInfo,
TranslationArraysNode)
from lbmpy.maxwellian_equilibrium import discrete_equilibrium from lbmpy.maxwellian_equilibrium import discrete_equilibrium
from lbmpy.simplificationfactory import create_simplification_strategy from lbmpy.simplificationfactory import create_simplification_strategy
import sympy as sp import sympy as sp
import numpy as np import numpy as np
from .._compat import IS_PYSTENCILS_2
if IS_PYSTENCILS_2:
from pystencils import create_type
from pystencils.sympyextensions.typed_sympy import CastFunc
from pystencils.types.quick import Arr
from lbmpy.lookup_tables import (
NeighbourOffsetArrays,
MirroredStencilDirections,
LbmWeightInfo,
TranslationArraysNode
)
else:
from pystencils.typing import create_type, CastFunc
from lbmpy.custom_code_nodes import (
NeighbourOffsetArrays,
MirroredStencilDirections,
LbmWeightInfo,
TranslationArraysNode
)
class LbBoundary(abc.ABC): class LbBoundary(abc.ABC):
"""Base class that all boundaries should derive from. """Base class that all boundaries should derive from.
...@@ -130,6 +147,8 @@ class NoSlip(LbBoundary): ...@@ -130,6 +147,8 @@ class NoSlip(LbBoundary):
force = sp.Symbol("f") force = sp.Symbol("f")
subexpressions = [Assignment(force, sp.Float(2.0) * f_out(dir_symbol))] subexpressions = [Assignment(force, sp.Float(2.0) * f_out(dir_symbol))]
offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
if IS_PYSTENCILS_2:
offset = [CastFunc.as_numeric(o) for o in offset]
for i in range(lb_method.stencil.D): for i in range(lb_method.stencil.D):
subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i])) subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i]))
else: else:
...@@ -211,6 +230,8 @@ class NoSlipLinearBouzidi(LbBoundary): ...@@ -211,6 +230,8 @@ class NoSlipLinearBouzidi(LbBoundary):
force = sp.Symbol("f") force = sp.Symbol("f")
subexpressions.append(Assignment(force, f_xf + rhs)) subexpressions.append(Assignment(force, f_xf + rhs))
offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
if IS_PYSTENCILS_2:
offset = [CastFunc.as_numeric(o) for o in offset]
for i in range(lb_method.stencil.D): for i in range(lb_method.stencil.D):
subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i])) subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i]))
...@@ -239,10 +260,15 @@ class QuadraticBounceBack(LbBoundary): ...@@ -239,10 +260,15 @@ class QuadraticBounceBack(LbBoundary):
self.data_type = data_type self.data_type = data_type
self.init_wall_distance = init_wall_distance self.init_wall_distance = init_wall_distance
self.equilibrium_values_name = "f_eq" self.equilibrium_values_name = "f_eq"
self.inv_dir_symbol = TypedSymbol("inv_dir", create_type("int32"))
super(QuadraticBounceBack, self).__init__(name, calculate_force_on_boundary) super(QuadraticBounceBack, self).__init__(name, calculate_force_on_boundary)
def inv_dir_symbol(self, stencil):
if IS_PYSTENCILS_2:
return TypedSymbol("inv_dir", Arr(create_type("int32"), stencil.Q))
else:
return TypedSymbol("inv_dir", create_type("int32"))
@property @property
def additional_data(self): def additional_data(self):
"""Used internally only. For the NoSlipLinearBouzidi boundary the distance to the obstacle of every """Used internally only. For the NoSlipLinearBouzidi boundary the distance to the obstacle of every
...@@ -273,9 +299,15 @@ class QuadraticBounceBack(LbBoundary): ...@@ -273,9 +299,15 @@ class QuadraticBounceBack(LbBoundary):
""" """
stencil = lb_method.stencil stencil = lb_method.stencil
inv_directions = [str(stencil.index(inverse_direction(direction))) for direction in stencil] inv_directions = [str(stencil.index(inverse_direction(direction))) for direction in stencil]
dtype = self.inv_dir_symbol.dtype
name = self.inv_dir_symbol.name if IS_PYSTENCILS_2:
inverse_dir_node = TranslationArraysNode([(dtype, name, inv_directions), ], {self.inv_dir_symbol}) inverse_dir_node = TranslationArraysNode([(self.inv_dir_symbol(stencil), inv_directions), ])
else:
inv_dir_symbol = self.inv_dir_symbol(stencil)
dtype = inv_dir_symbol.dtype
name = inv_dir_symbol.name
inverse_dir_node = TranslationArraysNode([(dtype, name, inv_directions), ], {inv_dir_symbol})
return [LbmWeightInfo(lb_method, self.data_type), inverse_dir_node, NeighbourOffsetArrays(lb_method.stencil)] return [LbmWeightInfo(lb_method, self.data_type), inverse_dir_node, NeighbourOffsetArrays(lb_method.stencil)]
@staticmethod @staticmethod
...@@ -293,7 +325,7 @@ class QuadraticBounceBack(LbBoundary): ...@@ -293,7 +325,7 @@ class QuadraticBounceBack(LbBoundary):
def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector): def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector):
omega = self.relaxation_rate omega = self.relaxation_rate
inv = sp.IndexedBase(self.inv_dir_symbol, shape=(1,))[dir_symbol] inv = sp.IndexedBase(self.inv_dir_symbol(lb_method.stencil), shape=(1,))[dir_symbol]
weight_info = LbmWeightInfo(lb_method, data_type=self.data_type) weight_info = LbmWeightInfo(lb_method, data_type=self.data_type)
weight_of_direction = weight_info.weight_of_direction weight_of_direction = weight_info.weight_of_direction
pdf_field_accesses = [f_out(i) for i in range(len(lb_method.stencil))] pdf_field_accesses = [f_out(i) for i in range(len(lb_method.stencil))]
...@@ -317,13 +349,19 @@ class QuadraticBounceBack(LbBoundary): ...@@ -317,13 +349,19 @@ class QuadraticBounceBack(LbBoundary):
subexpressions.append(Assignment(weight, weight_of_direction(dir_symbol, lb_method))) subexpressions.append(Assignment(weight, weight_of_direction(dir_symbol, lb_method)))
subexpressions.append(Assignment(weight_inv, weight_of_direction(inv, lb_method))) subexpressions.append(Assignment(weight_inv, weight_of_direction(inv, lb_method)))
if IS_PYSTENCILS_2:
cast_offset = CastFunc.as_numeric
else:
def cast_offset(x):
return x
for i in range(lb_method.stencil.D): for i in range(lb_method.stencil.D):
offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
subexpressions.append(Assignment(v[i], offset[i])) subexpressions.append(Assignment(v[i], cast_offset(offset[i])))
for i in range(lb_method.stencil.D): for i in range(lb_method.stencil.D):
offset = NeighbourOffsetArrays.neighbour_offset(inv, lb_method.stencil) offset = NeighbourOffsetArrays.neighbour_offset(inv, lb_method.stencil)
subexpressions.append(Assignment(v_inv[i], offset[i])) subexpressions.append(Assignment(v_inv[i], cast_offset(offset[i])))
cqc = lb_method.conserved_quantity_computation cqc = lb_method.conserved_quantity_computation
rho = cqc.density_symbol rho = cqc.density_symbol
...@@ -348,6 +386,8 @@ class QuadraticBounceBack(LbBoundary): ...@@ -348,6 +386,8 @@ class QuadraticBounceBack(LbBoundary):
force = sp.Symbol("f") force = sp.Symbol("f")
subexpressions.append(Assignment(force, f_xf + result)) subexpressions.append(Assignment(force, f_xf + result))
offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
if IS_PYSTENCILS_2:
offset = [CastFunc.as_numeric(o) for o in offset]
for i in range(lb_method.stencil.D): for i in range(lb_method.stencil.D):
subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i])) subexpressions.append(Assignment(force_vector[0](f'F_{i}'), force * offset[i]))
...@@ -469,7 +509,7 @@ class FreeSlip(LbBoundary): ...@@ -469,7 +509,7 @@ class FreeSlip(LbBoundary):
neighbor_offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) neighbor_offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
if self.normal_direction: if self.normal_direction:
tangential_offset = tuple(offset + normal for offset, normal in zip(neighbor_offset, self.normal_direction)) tangential_offset = tuple(offset + normal for offset, normal in zip(neighbor_offset, self.normal_direction))
mirrored_stencil_symbol = MirroredStencilDirections._mirrored_symbol(self.mirror_axis) mirrored_stencil_symbol = MirroredStencilDirections._mirrored_symbol(self.mirror_axis, self.stencil)
mirrored_direction = inv_dir[sp.IndexedBase(mirrored_stencil_symbol, shape=(1,))[dir_symbol]] mirrored_direction = inv_dir[sp.IndexedBase(mirrored_stencil_symbol, shape=(1,))[dir_symbol]]
else: else:
normal_direction = list() normal_direction = list()
...@@ -610,7 +650,7 @@ class WallFunctionBounce(LbBoundary): ...@@ -610,7 +650,7 @@ class WallFunctionBounce(LbBoundary):
# neighbour offset symbols are basically the stencil directions defined in stencils.py:L130ff. # neighbour offset symbols are basically the stencil directions defined in stencils.py:L130ff.
neighbor_offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil) neighbor_offset = NeighbourOffsetArrays.neighbour_offset(dir_symbol, lb_method.stencil)
tangential_offset = tuple(offset + normal for offset, normal in zip(neighbor_offset, self.normal_direction)) tangential_offset = tuple(offset + normal for offset, normal in zip(neighbor_offset, self.normal_direction))
mirrored_stencil_symbol = MirroredStencilDirections._mirrored_symbol(self.mirror_axis) mirrored_stencil_symbol = MirroredStencilDirections._mirrored_symbol(self.mirror_axis, self.stencil)
mirrored_direction = inv_dir[sp.IndexedBase(mirrored_stencil_symbol, shape=(1,))[dir_symbol]] mirrored_direction = inv_dir[sp.IndexedBase(mirrored_stencil_symbol, shape=(1,))[dir_symbol]]
name_base = "f_in_inv_offsets_" name_base = "f_in_inv_offsets_"
...@@ -696,7 +736,12 @@ class WallFunctionBounce(LbBoundary): ...@@ -696,7 +736,12 @@ class WallFunctionBounce(LbBoundary):
if self.stencil.Q == 19: if self.stencil.Q == 19:
result.append(Assignment(weight, sp.Rational(1, 2))) result.append(Assignment(weight, sp.Rational(1, 2)))
elif self.stencil.Q == 27: elif self.stencil.Q == 27:
result.append(Assignment(inv_weight_sq, sum([neighbor_offset[i]**2 for i in self.tangential_axis]))) result.append(
Assignment(
inv_weight_sq,
sum([CastFunc(neighbor_offset[i], self.data_type)**2 for i in self.tangential_axis])
)
)
a, b = sp.symbols("wfb_a wfb_b") a, b = sp.symbols("wfb_a wfb_b")
if self.weight_method == self.WeightMethod.LATTICE_WEIGHT: if self.weight_method == self.WeightMethod.LATTICE_WEIGHT:
...@@ -712,7 +757,12 @@ class WallFunctionBounce(LbBoundary): ...@@ -712,7 +757,12 @@ class WallFunctionBounce(LbBoundary):
(res_ab[b], True)))) (res_ab[b], True))))
factor = self.dt / self.dy * weight factor = self.dt / self.dy * weight
drag = sum([neighbor_offset[i] * factor * wall_stress[i] for i in self.tangential_axis]) drag = sum(
[
CastFunc(neighbor_offset[i], self.data_type) * factor * wall_stress[i]
for i in self.tangential_axis
]
)
result.append(Assignment(f_in.center(inv_dir[dir_symbol]), f_out[tangential_offset](mirrored_direction) - drag)) result.append(Assignment(f_in.center(inv_dir[dir_symbol]), f_out[tangential_offset](mirrored_direction) - drag))
...@@ -792,6 +842,7 @@ class UBB(LbBoundary): ...@@ -792,6 +842,7 @@ class UBB(LbBoundary):
return callable(self._velocity) return callable(self._velocity)
def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector): def __call__(self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector):
dtype = create_type(self.data_type)
vel_from_idx_field = callable(self._velocity) vel_from_idx_field = callable(self._velocity)
vel = [index_field(f'vel_{i}') for i in range(self.dim)] if vel_from_idx_field else self._velocity vel = [index_field(f'vel_{i}') for i in range(self.dim)] if vel_from_idx_field else self._velocity
...@@ -814,8 +865,11 @@ class UBB(LbBoundary): ...@@ -814,8 +865,11 @@ class UBB(LbBoundary):
c_s_sq = sp.Rational(1, 3) c_s_sq = sp.Rational(1, 3)
weight_info = LbmWeightInfo(lb_method, data_type=self.data_type) weight_info = LbmWeightInfo(lb_method, data_type=self.data_type)
weight_of_direction = weight_info.weight_of_direction weight_of_direction = weight_info.weight_of_direction
vel_term = 2 / c_s_sq * sum([d_i * v_i for d_i, v_i in zip(neighbor_offset, velocity)]) * weight_of_direction( vel_term = (
dir_symbol, lb_method) 2 / c_s_sq
* sum([CastFunc(d_i, dtype) * v_i for d_i, v_i in zip(neighbor_offset, velocity)])
* weight_of_direction(dir_symbol, lb_method)
)
# Better alternative: in conserved value computation # Better alternative: in conserved value computation
# rename what is currently called density to "virtual_density" # rename what is currently called density to "virtual_density"
......
from dataclasses import replace from dataclasses import replace
import numpy as np import numpy as np
from pystencils import Assignment, CreateKernelConfig, create_kernel, Field, Target from pystencils import Assignment, CreateKernelConfig, create_kernel, Field, Target, FieldType
from pystencils.boundaries import BoundaryHandling from pystencils.boundaries import BoundaryHandling
from pystencils.boundaries.createindexlist import numpy_data_type_for_boundary_object from pystencils.boundaries.createindexlist import numpy_data_type_for_boundary_object
from pystencils.field import FieldType
from pystencils.simp import add_subexpressions_for_field_reads from pystencils.simp import add_subexpressions_for_field_reads
from pystencils.stencil import inverse_direction from pystencils.stencil import inverse_direction
from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing
from lbmpy.advanced_streaming.utility import is_inplace, Timestep, AccessPdfValues from lbmpy.advanced_streaming.utility import is_inplace, Timestep, AccessPdfValues
from .._compat import IS_PYSTENCILS_2
if IS_PYSTENCILS_2:
from pystencils.types import PsNumericType
class LatticeBoltzmannBoundaryHandling(BoundaryHandling): class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
""" """
...@@ -20,13 +24,16 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -20,13 +24,16 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
""" """
def __init__(self, lb_method, data_handling, pdf_field_name, streaming_pattern='pull', def __init__(self, lb_method, data_handling, pdf_field_name, streaming_pattern='pull',
name="boundary_handling", flag_interface=None, target=Target.CPU, openmp=False): name="boundary_handling", flag_interface=None, target=Target.CPU, openmp=False, **kwargs):
self._lb_method = lb_method self._lb_method = lb_method
self._streaming_pattern = streaming_pattern self._streaming_pattern = streaming_pattern
self._inplace = is_inplace(streaming_pattern) self._inplace = is_inplace(streaming_pattern)
self._prev_timestep = None self._prev_timestep = None
super(LatticeBoltzmannBoundaryHandling, self).__init__(data_handling, pdf_field_name, lb_method.stencil, super(LatticeBoltzmannBoundaryHandling, self).__init__(
name, flag_interface, target, openmp) data_handling, pdf_field_name, lb_method.stencil,
name, flag_interface, target=target, openmp=openmp,
**kwargs
)
# ------------------------- Overridden methods of pystencils.BoundaryHandling ------------------------- # ------------------------- Overridden methods of pystencils.BoundaryHandling -------------------------
...@@ -52,7 +59,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -52,7 +59,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
def _add_inplace_boundary(self, boundary_obj, flag=None): def _add_inplace_boundary(self, boundary_obj, flag=None):
if boundary_obj not in self._boundary_object_to_boundary_info: if boundary_obj not in self._boundary_object_to_boundary_info:
sym_index_field = Field.create_generic('indexField', spatial_dimensions=1, sym_index_field = Field.create_generic('indexField', spatial_dimensions=1, field_type=FieldType.INDEXED,
dtype=numpy_data_type_for_boundary_object(boundary_obj, self.dim)) dtype=numpy_data_type_for_boundary_object(boundary_obj, self.dim))
ast_even = self._create_boundary_kernel(self._data_handling.fields[self._field_name], sym_index_field, ast_even = self._create_boundary_kernel(self._data_handling.fields[self._field_name], sym_index_field,
...@@ -67,10 +74,15 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -67,10 +74,15 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
return self._boundary_object_to_boundary_info[boundary_obj].flag return self._boundary_object_to_boundary_info[boundary_obj].flag
def _create_boundary_kernel(self, symbolic_field, symbolic_index_field, boundary_obj, prev_timestep=Timestep.BOTH): def _create_boundary_kernel(self, symbolic_field, symbolic_index_field, boundary_obj, prev_timestep=Timestep.BOTH):
if IS_PYSTENCILS_2:
additional_args = {"default_dtype": self._default_dtype}
else:
additional_args = dict()
return create_lattice_boltzmann_boundary_kernel( return create_lattice_boltzmann_boundary_kernel(
symbolic_field, symbolic_index_field, self._lb_method, boundary_obj, symbolic_field, symbolic_index_field, self._lb_method, boundary_obj,
prev_timestep=prev_timestep, streaming_pattern=self._streaming_pattern, prev_timestep=prev_timestep, streaming_pattern=self._streaming_pattern,
target=self._target, cpu_openmp=self._openmp) target=self._target, cpu_openmp=self._openmp, **additional_args)
class InplaceStreamingBoundaryInfo(object): class InplaceStreamingBoundaryInfo(object):
...@@ -159,6 +171,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling): ...@@ -159,6 +171,7 @@ class LatticeBoltzmannBoundaryHandling(BoundaryHandling):
def create_lattice_boltzmann_boundary_kernel(pdf_field, index_field, lb_method, boundary_functor, def create_lattice_boltzmann_boundary_kernel(pdf_field, index_field, lb_method, boundary_functor,
prev_timestep=Timestep.BOTH, streaming_pattern='pull', prev_timestep=Timestep.BOTH, streaming_pattern='pull',
target=Target.CPU, force_vector=None, **kernel_creation_args): target=Target.CPU, force_vector=None, **kernel_creation_args):
from .._compat import IS_PYSTENCILS_2
indexing = BetweenTimestepsIndexing( indexing = BetweenTimestepsIndexing(
pdf_field, lb_method.stencil, prev_timestep, streaming_pattern, np.int32, np.int32) pdf_field, lb_method.stencil, prev_timestep, streaming_pattern, np.int32, np.int32)
...@@ -168,32 +181,69 @@ def create_lattice_boltzmann_boundary_kernel(pdf_field, index_field, lb_method, ...@@ -168,32 +181,69 @@ def create_lattice_boltzmann_boundary_kernel(pdf_field, index_field, lb_method,
dir_symbol = indexing.dir_symbol dir_symbol = indexing.dir_symbol
inv_dir = indexing.inverse_dir_symbol inv_dir = indexing.inverse_dir_symbol
config = CreateKernelConfig(target=target, default_number_int="int32", if IS_PYSTENCILS_2:
skip_independence_check=True, **kernel_creation_args) from pystencils.types.quick import SInt
config = CreateKernelConfig(
index_field=index_field,
target=target,
index_dtype=SInt(32),
skip_independence_check=True,
**kernel_creation_args
)
default_data_type: PsNumericType = config.get_option("default_dtype")
if force_vector is None:
force_vector_type = np.dtype([(f"F_{i}", default_data_type.numpy_dtype) for i in range(dim)], align=True)
force_vector = Field.create_generic('force_vector', spatial_dimensions=1,
dtype=force_vector_type, field_type=FieldType.INDEXED)
boundary_assignments = boundary_functor(f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector)
boundary_assignments = indexing.substitute_proxies(boundary_assignments)
if pdf_field.dtype != default_data_type:
boundary_assignments = add_subexpressions_for_field_reads(boundary_assignments, data_type=default_data_type)
elements: list[Assignment] = []
index_arrs_node = indexing.create_code_node()
elements += index_arrs_node.get_array_declarations()
for node in boundary_functor.get_additional_code_nodes(lb_method)[::-1]:
elements += node.get_array_declarations()
elements += [Assignment(dir_symbol, index_field[0]('dir'))]
elements += boundary_assignments.all_assignments
kernel = create_kernel(elements, config=config)
return kernel
else:
config = CreateKernelConfig(index_fields=[index_field], target=target, default_number_int="int32",
skip_independence_check=True, **kernel_creation_args)
default_data_type = config.data_type.default_factory() default_data_type = config.data_type.default_factory()
if force_vector is None: if force_vector is None:
force_vector_type = np.dtype([(f"F_{i}", default_data_type.c_name) for i in range(dim)], align=True) force_vector_type = np.dtype([(f"F_{i}", default_data_type.c_name) for i in range(dim)], align=True)
force_vector = Field.create_generic('force_vector', spatial_dimensions=1, force_vector = Field.create_generic('force_vector', spatial_dimensions=1,
dtype=force_vector_type, field_type=FieldType.INDEXED) dtype=force_vector_type, field_type=FieldType.INDEXED)
config = replace(config, index_fields=[index_field, force_vector]) config = replace(config, index_fields=[index_field, force_vector])
boundary_assignments = boundary_functor(f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector) boundary_assignments = boundary_functor(f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector)
boundary_assignments = indexing.substitute_proxies(boundary_assignments) boundary_assignments = indexing.substitute_proxies(boundary_assignments)
if pdf_field.dtype != default_data_type: if pdf_field.dtype != default_data_type:
boundary_assignments = add_subexpressions_for_field_reads(boundary_assignments, data_type=default_data_type) boundary_assignments = add_subexpressions_for_field_reads(boundary_assignments, data_type=default_data_type)
elements = [Assignment(dir_symbol, index_field[0]('dir'))] elements = [Assignment(dir_symbol, index_field[0]('dir'))]
elements += boundary_assignments.all_assignments elements += boundary_assignments.all_assignments
kernel = create_kernel(elements, config=config) kernel = create_kernel(elements, config=config)
# Code Elements ahead of the loop # Code Elements ahead of the loop
index_arrs_node = indexing.create_code_node() index_arrs_node = indexing.create_code_node()
for node in boundary_functor.get_additional_code_nodes(lb_method)[::-1]: for node in boundary_functor.get_additional_code_nodes(lb_method)[::-1]:
kernel.body.insert_front(node) kernel.body.insert_front(node)
kernel.body.insert_front(index_arrs_node) kernel.body.insert_front(index_arrs_node)
return kernel return kernel
...@@ -157,7 +157,7 @@ class MuskerLaw(ImplicitWallFunctionModel): ...@@ -157,7 +157,7 @@ class MuskerLaw(ImplicitWallFunctionModel):
def law(u_p, y_p): def law(u_p, y_p):
arctan = sp.Float(5.424) * sp.atan(sp.Float(0.119760479041916168) * y_p - sp.Float(0.488023952095808383)) arctan = sp.Float(5.424) * sp.atan(sp.Float(0.119760479041916168) * y_p - sp.Float(0.488023952095808383))
logarithm = (sp.Float(0.434) * sp.log((y_p + sp.Float(10.6)) ** sp.Float(9.6) logarithm = (sp.Float(0.434) * sp.log((y_p + sp.Float(10.6)) ** sp.Float(9.6)
/ (y_p ** 2 - sp.Float(8.15) * y_p + sp.Float(86)) ** 2, 10)) / (y_p ** 2 - sp.Float(8.15) * y_p + sp.Float(86)) ** 2))
return (arctan + logarithm - sp.Float(3.50727901936264842)) - u_p return (arctan + logarithm - sp.Float(3.50727901936264842)) - u_p
u_plus = velocity_symbol / self.u_tau[0] u_plus = velocity_symbol / self.u_tau[0]
......