Showing preview only (4,094K chars total). Download the full file or copy to clipboard to get everything.
Repository: lettucecfd/lettuce
Branch: master
Commit: 121359d2b7ee
Files: 256
Total size: 3.9 MB
Directory structure:
gitextract_tttiteof/
├── .codeclimate.yml
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── BUG_REPORT.yml
│ │ └── FEATURE_REQUEST.yml
│ ├── pull_request_template.md
│ └── workflows/
│ └── CI.yml
├── .gitignore
├── .readthedocs.yaml
├── AUTHORS.rst
├── LICENSE
├── README.rst
├── docs/
│ ├── README.md
│ ├── authors.rst
│ ├── conf.py
│ ├── contributing.rst
│ ├── history.rst
│ ├── index.rst
│ ├── installation.rst
│ ├── make.bat
│ ├── modules.rst
│ ├── readme.rst
│ └── usage.rst
├── examples/
│ ├── 00_simplest_TGV.py
│ ├── 01a_first_example_TGV.ipynb
│ ├── 01b_first_example_obstacle.py
│ ├── 02_converging_obstacle_flow.py
│ ├── 03_outputs_TGV.py
│ ├── __init__.py
│ ├── advanced_flows/
│ │ ├── FailingTGVandObstacle.py
│ │ ├── LidDrivenCavity.ipynb
│ │ ├── MixingLayer.ipynb
│ │ ├── PartiallySaturatedObstacle.py
│ │ └── PorousMedium.ipynb
│ ├── advanced_projects/
│ │ ├── __init__.py
│ │ └── efficient_bounce_back_obstacle/
│ │ ├── 00_run_parametrized_project.ipynb
│ │ ├── 01_script_cylinder_simulation.py
│ │ ├── __init__.py
│ │ ├── auxiliary_code/
│ │ │ ├── __init__.py
│ │ │ ├── data_processing_and_plotting.py
│ │ │ └── helperCode.py
│ │ ├── boundary/
│ │ │ ├── __init__.py
│ │ │ ├── fullway_bounce_back_boundary.py
│ │ │ ├── halfway_bounce_back_boundary.py
│ │ │ ├── linear_interpolated_bounce_back_boundary.py
│ │ │ └── solid_boundary_data.py
│ │ ├── flow/
│ │ │ ├── __init__.py
│ │ │ └── obstacle_cylinder.py
│ │ ├── profile_reference_data/
│ │ │ ├── Fig09_ux_profile_pos1_DI2018.csv
│ │ │ ├── Fig09_ux_profile_pos1_KM2000.csv
│ │ │ ├── Fig09_ux_profile_pos1_LS1993.csv
│ │ │ ├── Fig09_ux_profile_pos1_WR2008.csv
│ │ │ ├── Fig09_ux_profile_pos2_DI2018.csv
│ │ │ ├── Fig09_ux_profile_pos2_KM2000.csv
│ │ │ ├── Fig09_ux_profile_pos2_LS1993.csv
│ │ │ ├── Fig09_ux_profile_pos2_WR2008.csv
│ │ │ ├── Fig09_ux_profile_pos3_DI2018.csv
│ │ │ ├── Fig09_ux_profile_pos3_KM2000.csv
│ │ │ ├── Fig09_ux_profile_pos3_LS1993.csv
│ │ │ ├── Fig09_ux_profile_pos3_WR2008.csv
│ │ │ ├── Fig10_uy_profile_pos1_DI2018.csv
│ │ │ ├── Fig10_uy_profile_pos1_KM2000.csv
│ │ │ ├── Fig10_uy_profile_pos1_LS1993.csv
│ │ │ ├── Fig10_uy_profile_pos1_WR2008.csv
│ │ │ ├── Fig10_uy_profile_pos2_DI2018.csv
│ │ │ ├── Fig10_uy_profile_pos2_KM2000.csv
│ │ │ ├── Fig10_uy_profile_pos2_LS1993.csv
│ │ │ ├── Fig10_uy_profile_pos2_WR2008.csv
│ │ │ ├── Fig10_uy_profile_pos3_DI2018.csv
│ │ │ ├── Fig10_uy_profile_pos3_KM2000.csv
│ │ │ ├── Fig10_uy_profile_pos3_LS1993.csv
│ │ │ ├── Fig10_uy_profile_pos3_WR2008.csv
│ │ │ ├── Fig11_uxux_profile_pos1_DI2018.csv
│ │ │ ├── Fig11_uxux_profile_pos1_KM2000.csv
│ │ │ ├── Fig11_uxux_profile_pos1_R2016.csv
│ │ │ ├── Fig11_uxux_profile_pos2_BM1994.csv
│ │ │ ├── Fig11_uxux_profile_pos2_DI2018.csv
│ │ │ ├── Fig11_uxux_profile_pos2_KM2000.csv
│ │ │ ├── Fig11_uxux_profile_pos2_LS1993.csv
│ │ │ ├── Fig11_uxux_profile_pos2_R2016.csv
│ │ │ ├── Fig11_uxux_profile_pos3_DI2018.csv
│ │ │ ├── Fig11_uxux_profile_pos3_KM2000.csv
│ │ │ ├── Fig11_uxux_profile_pos3_R2016.csv
│ │ │ ├── Fig12_uyuy_profile_pos1_DI2018.csv
│ │ │ ├── Fig12_uyuy_profile_pos1_R2016.csv
│ │ │ ├── Fig12_uyuy_profile_pos2_BM1994.csv
│ │ │ ├── Fig12_uyuy_profile_pos2_DI2018.csv
│ │ │ ├── Fig12_uyuy_profile_pos2_LS1993.csv
│ │ │ ├── Fig12_uyuy_profile_pos2_R2016.csv
│ │ │ ├── Fig12_uyuy_profile_pos3_DI2018.csv
│ │ │ ├── Fig12_uyuy_profile_pos3_R2016.csv
│ │ │ ├── Fig13_uxuy_profile_pos1_BM1994.csv
│ │ │ ├── Fig13_uxuy_profile_pos1_DI2018.csv
│ │ │ ├── Fig13_uxuy_profile_pos1_R2016.csv
│ │ │ ├── Fig13_uxuy_profile_pos2_BM1994.csv
│ │ │ ├── Fig13_uxuy_profile_pos2_DI2018.csv
│ │ │ ├── Fig13_uxuy_profile_pos2_LS1993.csv
│ │ │ ├── Fig13_uxuy_profile_pos2_R2016.csv
│ │ │ ├── Fig13_uxuy_profile_pos3_BM1994.csv
│ │ │ ├── Fig13_uxuy_profile_pos3_DI2018.csv
│ │ │ └── Fig13_uxuy_profile_pos3_R2016.csv
│ │ ├── reporter/
│ │ │ ├── __init__.py
│ │ │ ├── observables_force_coefficients.py
│ │ │ ├── reporter_ProfileReporter.py
│ │ │ └── reporter_advanced_vtk_reporter.py
│ │ └── simulation/
│ │ ├── __init__.py
│ │ └── ebb_simulation.py
│ ├── development/
│ │ ├── .gitignore
│ │ ├── example_progress_reporter_based_on_simplest_TGV.py
│ │ └── manually_generate_cuda_native.py
│ └── simple_flows/
│ ├── Couette.ipynb
│ ├── DecayingTurbulence.ipynb
│ ├── LambOseenVortex.py
│ ├── Obstacle.ipynb
│ └── Poiseuille.ipynb
├── lettuce/
│ ├── __init__.py
│ ├── _context.py
│ ├── _flow.py
│ ├── _simulation.py
│ ├── _stencil.py
│ ├── _unit.py
│ ├── _version.py
│ ├── base.py
│ ├── cli.py
│ ├── cuda_native/
│ │ ├── __init__.py
│ │ ├── _default_code_gen.py
│ │ ├── _generator.py
│ │ ├── _registry.py
│ │ ├── _template.py
│ │ ├── _transformer.py
│ │ ├── _util.py
│ │ └── ext/
│ │ ├── __init__.py
│ │ ├── _boundary/
│ │ │ ├── __init__.py
│ │ │ ├── bounce_back_boundary.py
│ │ │ ├── equilibrium_pu.py
│ │ │ └── no_boundary.py
│ │ ├── _collision/
│ │ │ ├── __init__.py
│ │ │ ├── bgk_collision.py
│ │ │ └── no_collision.py
│ │ ├── _equilibrium/
│ │ │ ├── __init__.py
│ │ │ └── quadratic_equilibrium.py
│ │ └── _force/
│ │ ├── __init__.py
│ │ └── _force.py
│ ├── ext/
│ │ ├── __init__.py
│ │ ├── _boundary/
│ │ │ ├── __init__.py
│ │ │ ├── anti_bounce_back_outlet.py
│ │ │ ├── bounce_back_boundary.py
│ │ │ ├── equilibrium_boundary_pu.py
│ │ │ ├── equilibrium_outlet_p.py
│ │ │ └── partially_saturated_boundary.py
│ │ ├── _collision/
│ │ │ ├── __init__.py
│ │ │ ├── bgk_collision.py
│ │ │ ├── kbc_collision.py
│ │ │ ├── mrt_collision.py
│ │ │ ├── no_collision.py
│ │ │ ├── regularized_collision.py
│ │ │ ├── smagorinsky_collision.py
│ │ │ └── trt_collision.py
│ │ ├── _equilibrium/
│ │ │ ├── __init__.py
│ │ │ ├── incompressible_quadratic_equilibrium.py
│ │ │ ├── quadratic_equilibrium.py
│ │ │ └── quadratic_equilibrium_less_memory.py
│ │ ├── _flows/
│ │ │ ├── __init__.py
│ │ │ ├── _ext_flow.py
│ │ │ ├── _flow_by_name.py
│ │ │ ├── couette.py
│ │ │ ├── decayingturbulence.py
│ │ │ ├── doublyshear.py
│ │ │ ├── lamboseenvortex.py
│ │ │ ├── liddrivencavity.py
│ │ │ ├── obstacle.py
│ │ │ ├── poiseuille.py
│ │ │ └── taylorgreen.py
│ │ ├── _force/
│ │ │ ├── __init__.py
│ │ │ ├── _force.py
│ │ │ ├── guo.py
│ │ │ └── shan_chen.py
│ │ ├── _reporter/
│ │ │ ├── __init__.py
│ │ │ ├── error_reporter.py
│ │ │ ├── failure_reporter.py
│ │ │ ├── observable_reporter.py
│ │ │ ├── progress_reporter.py
│ │ │ ├── vtk_reporter.py
│ │ │ └── write_image.py
│ │ └── _stencil/
│ │ ├── __init__.py
│ │ ├── d1q3.py
│ │ ├── d2q9.py
│ │ ├── d3q15.py
│ │ ├── d3q19.py
│ │ └── d3q27.py
│ └── util/
│ ├── __init__.py
│ ├── datautils.py
│ ├── moments.py
│ └── utility.py
├── native_cuda_synopsis.md
├── pyproject.toml
├── requirements.txt
├── tests/
│ ├── __init__.py
│ ├── boundary/
│ │ ├── test_antibounceback_outlet_bc.py
│ │ ├── test_bc_masks.py
│ │ ├── test_bounceback_bc.py
│ │ ├── test_equilibrium_bc_outlet_p.py
│ │ ├── test_equilibrium_bc_pu.py
│ │ ├── test_equilibrium_pressure_outlet.py
│ │ └── test_partiallysaturated_bc.py
│ ├── collision/
│ │ ├── test_collision_conserves_mass.py
│ │ ├── test_collision_conserves_momentum.py
│ │ ├── test_collision_fixpoint_2x.py
│ │ ├── test_collision_fixpoint_2x_MRT.py
│ │ ├── test_collision_optimizes_pseudo_entropy.py
│ │ ├── test_collision_relaxes_shear_moments.py
│ │ └── test_force.py
│ ├── conftest.py
│ ├── flow/
│ │ ├── test_divergence.py
│ │ ├── test_einsum.py
│ │ ├── test_flow.py
│ │ ├── test_initialize_fneq.py
│ │ ├── test_initialize_pressure.py
│ │ ├── test_obstacle.py
│ │ └── test_pressure_poisson.py
│ ├── moments/
│ │ ├── test_conserved_moments_d2q9.py
│ │ ├── test_getitem.py
│ │ ├── test_inverse_transform.py
│ │ ├── test_moment_equilibrium_D3Q27Hermite.py
│ │ ├── test_moment_equilibrium_dellar.py
│ │ ├── test_moment_equilibrium_lallemand.py
│ │ ├── test_moments_density.py
│ │ └── test_orthogonality.py
│ ├── native/
│ │ ├── __init__.py
│ │ ├── test_native_bgk_collision.py
│ │ ├── test_native_bounce_back.py
│ │ ├── test_native_equilibrium_pu.py
│ │ ├── test_native_no_streaming_mask.py
│ │ ├── test_native_streaming.py
│ │ └── test_native_streaming_strategy.py
│ ├── reporter/
│ │ ├── test_HDF5Reporter.py
│ │ ├── test_energy_spectrum.py
│ │ ├── test_generic_reporters.py
│ │ ├── test_high_ma_reporter.py
│ │ ├── test_nan_reporter.py
│ │ ├── test_vtk_reporter_mask.py
│ │ ├── test_vtk_reporter_no_mask.py
│ │ ├── test_write_image.py
│ │ └── test_write_vtk.py
│ ├── stencil/
│ │ ├── test_first_zero.py
│ │ ├── test_opposite.py
│ │ ├── test_symmetry.py
│ │ └── test_weights.py
│ ├── test_checkpoint.py
│ ├── test_cli.py
│ ├── test_equilibrium.py
│ ├── unit/
│ │ ├── __init__.py
│ │ ├── test_consistency.py
│ │ ├── test_conversion_reversible.py
│ │ └── test_reynolds_number_consistent.py
│ └── util/
│ ├── test_grid_fine_to_coarse.py
│ └── test_torch_gradient.py
└── versioneer.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .codeclimate.yml
================================================
exclude_patterns:
- "versioneer.py"
- "lettuce/_version.py"
- "config/"
- "db/"
- "dist/"
- "features/"
- "**/node_modules/"
- "script/"
- "**/spec/"
- "**/test/"
- "**/tests/"
- "Tests/"
- "**/vendor/"
- "**/*_test.go"
- "**/*.d.ts"
================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.yml
================================================
name: Bug Report
description: File a bug report.
title: "[Bug]: "
labels: ["bug"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
value: "A bug happened!"
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of our software are you running?
options:
- 0.2.0
- 0.2.1
- 0.2.2
- 0.2.3
default: 0
validations:
required: true
- type: dropdown
id: browsers
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Windows
- MacOs
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml
================================================
name: "Feature Request"
description: Suggest an idea for improving lettuce
title: "[Feature]: "
labels: ["enhancement"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a new and exciting feature!
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: is-related
attributes:
label: Is your proposal related to a problem?
description: Provide a clear and concise description of what the problem is.
placeholder: "I'm always frustrated when..."
value: "This is related to a problem!"
validations:
required: true
- type: textarea
id: solution
attributes:
label: "Describe the solution you'd like"
description: Provide a clear and concise description of what you want to happen.
placeholder: (Describe your proposed solution here.)
value: "This is the suggested solution."
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: "Describe alternatives you've considered"
description: "Let us know about other solutions you've tried or researched."
placeholder: (Write your answer here.)
value: "This is an alternative."
validations:
required: true
- type: textarea
id: context
attributes:
label: "Additional context"
description: "Is there anything else you can add about the proposal? You might want to link to related issues here, if you haven't already."
placeholder: (Write your answer here.)
value: "This is additional context."
validations:
required: true
================================================
FILE: .github/pull_request_template.md
================================================
## Description
<!-- Add a description of the changes -->
## Checklist
- [ ] This pull request is associated to an issue
- [ ] This PR contains a description
- [ ] Did you add a new method? If so, you need to
- [ ] add method description
- [ ] maybe mention class in the corresponding `__init__`
- [ ] add an example using the method in `examples/advanced_flows/` or `examples/simple_flows/`
- [ ] add a test in `tests/`
- [ ] Add someone else as reviewer and wait for approval before merging.
================================================
FILE: .github/workflows/CI.yml
================================================
name: CI
on:
push:
branches:
- "master"
pull_request:
branches:
- "**"
schedule:
- cron: "0 7 * * 1"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
test:
runs-on: ${{ matrix.cfg.os }}
strategy:
fail-fast: false
matrix:
cfg:
- { os: ubuntu-latest, python-version: '3.12', extra: 'cpu' }
- { os: ubuntu-latest, python-version: '3.12', extra: 'cu124' }
- { os: ubuntu-latest, python-version: '3.12', extra: 'cu126' }
- { os: ubuntu-latest, python-version: '3.12', extra: 'cu128' }
- { os: ubuntu-latest, python-version: '3.12', extra: 'cu130' }
- { os: macos-latest, python-version: '3.12', extra: 'cpu' }
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Install dependencies with ${{ matrix.cfg.extra }} extra
shell: bash -el {0}
run: |
uv sync --extra ${{ matrix.cfg.extra }}
- name: Run unit tests
shell: bash -el {0}
run: |
uv run --extra ${{ matrix.cfg.extra }} pytest tests
- name: Run integration tests
shell: bash -el {0}
run: |
source .venv/bin/activate
if [[ "${{ matrix.cfg.extra }}" == "cpu" ]]; then
lettuce --no-cuda convergence --use-no-cuda_native
lettuce --no-cuda benchmark --use-no-cuda_native
else
lettuce --no-cuda convergence --use-no-cuda_native
lettuce --no-cuda benchmark --use-no-cuda_native
fi
================================================
FILE: .gitignore
================================================
Makefile
.idea/
.gitattributes
.editorconfig
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# data folder
data/
================================================
FILE: .readthedocs.yaml
================================================
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
# You can also specify other tool versions:
# nodejs: "19"
# rust: "1.64"
# golang: "1.19"
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub
# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: requirements.txt
================================================
FILE: AUTHORS.rst
================================================
=======
Credits
=======
Development Lead
----------------
* Andreas Kraemer <kraemer.research@gmail.com>
Contributors
------------
* Dominik Wilde
* Mario Bedrunka
* Philipp Spelten
* You?
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019, Andreas Kraemer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.rst
================================================
.. image:: https://raw.githubusercontent.com/lettucecfd/lettuce/master/.source/img/logo_lettuce_typo.png
.. image:: https://github.com/lettucecfd/lettuce/actions/workflows/CI.yml/badge.svg
:target: https://github.com/lettucecfd/lettuce/actions/workflows/CI.yml
:alt: CI Status
.. image:: https://readthedocs.org/projects/lettucecfd/badge/?version=latest
:target: https://lettucecfd.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.3757641.svg
:target: https://doi.org/10.5281/zenodo.3757641
GPU-accelerated Lattice Boltzmann Simulations in Python
-------------------------------------------------------
Lettuce is a Computational Fluid Dynamics framework based on the lattice Boltzmann method (LBM).
- **GPU-Accelerated Computation**: Utilizes PyTorch for high performance and efficient GPU utilization.
- **Rapid Prototyping**: Supports both 2D and 3D simulations for quick and reliable analysis.
- **Advanced Techniques**: Integrates neural networks and automatic differentiation to enhance LBM.
- **Optimized Performance**: Includes custom PyTorch extensions for native CUDA kernels.
Resources
---------
- `Documentation`_
- Presentation at CFDML2021 - `Paper`_ | `Preprint`_ | `Slides`_ | `Video`_ | `Code`_
.. _Paper: https://www.springerprofessional.de/en/lettuce-pytorch-based-lattice-boltzmann-framework/19862378
.. _Documentation: https://lettuceboltzmann.readthedocs.io
.. _Preprint: https://arxiv.org/pdf/2106.12929.pdf
.. _Slides: https://drive.google.com/file/d/1jyJFKgmRBTXhPvTfrwFs292S4MC3Fqh8/view
.. _Video: https://www.youtube.com/watch?v=7nVCuuZDCYA
.. _Code: https://github.com/lettucecfd/lettuce-paper
Getting Started
---------------
To find some very simple examples of how to use lettuce, please have a look at the examples_. These will guide you through lettuce's main features. Please ensure you have Jupyter installed to run the Jupyter notebooks.
.. _examples: https://github.com/lettucecfd/lettuce/tree/master/examples
Installation
------------
* Install the uv package manager from https://docs.astral.sh/uv/
* Clone this repository from github and change to it::
git clone https://github.com/lettucecfd/lettuce
cd lettuce
* Create a new virtual environment and activate it::
uv venv
source .venv/bin/activate
* The `pyproject.toml` file currently requires at least **CUDA 12.4** (we successfully tested CUDA 12.4, 12.6, 12.8 and 13.0). If your GPU does not support this version, you may need to downgrade it. Please note that we cannot guarantee the maintenance for older CUDA versions.
* Run the install command, depending on your needs (run one of the three options below):
1. use lettuce (no development) with GPU support::
uv pip install .
2. use lettuce (no development) with CPU only or specific older CUDA versions (if you do not have access to a GPU or an older GPU) use (cpu, cu124, cu126)::
uv pip install ".[cpu]"
3. use and **develop** lettuce (code changes take effect in program execution): use the changeable-installation-flag (`-e`)::
uv pip install -e .
* Check out the convergence order, running on CPU::
lettuce --no-cuda convergence
* For running a CUDA-driven LBM simulation on one GPU omit the `--no-cuda`. If CUDA is not found, make sure that CUDA-capable GPU drivers are installed and compatible with the installed cudatoolkit (check cuda version number).
* Check out the performance, running on GPU::
lettuce benchmark
* Run the test cases::
pytest tests
Citation
--------
If you use Lettuce in your research, please cite the following paper::
@inproceedings{bedrunka2021lettuce,
title={Lettuce: PyTorch-Based Lattice Boltzmann Framework},
author={Bedrunka, Mario Christopher and Wilde, Dominik and Kliemank, Martin and Reith, Dirk and Foysi, Holger and Kr{\"a}mer, Andreas},
booktitle={High Performance Computing: ISC High Performance Digital 2021 International Workshops, Frankfurt am Main, Germany, June 24--July 2, 2021, Revised Selected Papers},
pages={40},
organization={Springer Nature}
}
Credits
-------
We use the following third-party packages:
* pytorch_
* numpy_
* pytest_
* click_
* matplotlib_
* versioneer_
* pyevtk_
* h5py_
* mmh3_
This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
.. _pytorch: https://github.com/pytorch/pytorch
.. _numpy: https://github.com/numpy/numpy
.. _pytest: https://github.com/pytest-dev/pytest
.. _click: https://github.com/pallets/click
.. _matplotlib: https://github.com/matplotlib/matplotlib
.. _versioneer: https://github.com/python-versioneer/python-versioneer
.. _pyevtk: https://github.com/pyscience-projects/pyevtk
.. _h5py: https://github.com/h5py/h5py
.. _mmh3: https://github.com/hajimes/mmh3
License
-----------
* Free software: MIT license, as found in the LICENSE_ file.
.. _LICENSE: https://github.com/lettucecfd/lettuce/blob/master/LICENSE
================================================
FILE: docs/README.md
================================================
# Building the docs locally
```
conda install -c conda-forge \
sphinx \
sphinxcontrib-napoleon \
numpydoc \
alabaster
cd docs
make html
```
================================================
FILE: docs/authors.rst
================================================
.. include:: ../AUTHORS.rst
================================================
FILE: docs/conf.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# lettuce documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another
# directory, add these directories to sys.path here. If the directory is
# relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
import lettuce
# -- General configuration ---------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'lettuce'
copyright = u"2019, Andreas Kraemer"
author = u"Andreas Kraemer"
# The version info for the project you're documenting, acts as replacement
# for |version| and |release|, also used in various other places throughout
# the built documents.
#
# The short X.Y version.
version = lettuce.__version__
# The full version, including alpha/beta/rc tags.
release = lettuce.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output -------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a
# theme further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Options for HTMLHelp output ---------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'lettucedoc'
# -- Options for LaTeX output ------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto, manual, or own class]).
latex_documents = [
(master_doc, 'lettuce.tex',
u'lettuce Documentation',
u'Andreas Kraemer', 'manual'),
]
# -- Options for manual page output ------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'lettuce',
u'lettuce Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'lettuce',
u'lettuce Documentation',
author,
'lettuce',
'One line description of project.',
'Miscellaneous'),
]
================================================
FILE: docs/contributing.rst
================================================
.. include:: ../CONTRIBUTING.rst
================================================
FILE: docs/history.rst
================================================
.. include:: ../HISTORY.rst
================================================
FILE: docs/index.rst
================================================
Welcome to lettuce's documentation!
======================================
.. toctree::
:maxdepth: 2
:caption: Contents:
readme
installation
usage
modules
contributing
authors
history
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
================================================
FILE: docs/installation.rst
================================================
.. highlight:: shell
============
Installation
============
From sources
------------
The sources for lettuce can be downloaded from the `Github repo`_.
You can either clone the public repository:
.. code-block:: console
$ git clone git://github.com/lettucecfd/lettuce
Or download the `tarball`_:
.. code-block:: console
$ curl -OL https://github.com/lettucecfd/lettuce/tarball/master
Once you have a copy of the source, you can install it with:
.. code-block:: console
$ python setup.py install
.. _Github repo: https://github.com/lettucecfd/lettuce
.. _tarball: https://github.com/lettucecfd/lettuce/tarball/master
================================================
FILE: docs/make.bat
================================================
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=python -msphinx
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=lettuce
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
echo.then set the SPHINXBUILD environment variable to point to the full
echo.path of the 'sphinx-build' executable. Alternatively you may add the
echo.Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
================================================
FILE: docs/modules.rst
================================================
API
===
Simulation
----------
.. automodule:: lettuce.simulation
:noindex:
:members:
:undoc-members:
:show-inheritance:
Lattices
--------
.. automodule:: lettuce.lattices
:noindex:
:members:
:undoc-members:
:show-inheritance:
Stencils
--------
.. automodule:: lettuce.stencils
:noindex:
:members:
:undoc-members:
:show-inheritance:
Streaming
---------
.. automodule:: lettuce.streaming
:noindex:
:members:
:undoc-members:
:show-inheritance:
Collision
---------
.. automodule:: lettuce.collision
:noindex:
:members:
:undoc-members:
:show-inheritance:
Observables
-----------
.. automodule:: lettuce.observables
:noindex:
:members:
:undoc-members:
:show-inheritance:
Reporters
---------
.. automodule:: lettuce.reporters
:noindex:
:members:
:undoc-members:
:show-inheritance:
Force
-----
.. automodule:: lettuce.force
:noindex:
:members:
:undoc-members:
:show-inheritance:
Equilibrium
-----------
.. automodule:: lettuce.equilibrium
:noindex:
:members:
:undoc-members:
:show-inheritance:
Boundary
--------
.. automodule:: lettuce.boundary
:noindex:
:members:
:undoc-members:
:show-inheritance:
Flows
-----
Couette
^^^^^^^
.. automodule:: lettuce.flows.couette
:noindex:
:members:
:undoc-members:
:show-inheritance:
Poiseuille
^^^^^^^^^^
.. automodule:: lettuce.flows.poiseuille
:noindex:
:members:
:undoc-members:
:show-inheritance:
Taylor-Green
^^^^^^^^^^^^
.. automodule:: lettuce.flows.taylorgreen
:noindex:
:members:
:undoc-members:
:show-inheritance:
Decaying-Turbulence
^^^^^^^^^^^^^^^^^^^
.. automodule:: lettuce.flows.decayingturbulence
:noindex:
:members:
:undoc-members:
:show-inheritance:
Obstacle
^^^^^^^^
.. automodule:: lettuce.flows.obstacle
:noindex:
:members:
:undoc-members:
:show-inheritance:
Utility
-------
.. automodule:: lettuce.util
:noindex:
:members:
:undoc-members:
:show-inheritance:
Command-Line Interface
----------------------
.. automodule:: lettuce.cli
:noindex:
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: docs/readme.rst
================================================
.. include:: ../README.rst
================================================
FILE: docs/usage.rst
================================================
=====
Usage
=====
To use lettuce in a project::
import lettuce
================================================
FILE: examples/00_simplest_TGV.py
================================================
"""
This file showcases the simplicity of the lettuce code.
The following code will run a two-dimensional Taylor-Green vortex on GPU.
"""
import torch
import lettuce as lt
flow = lt.TaylorGreenVortex(
lt.Context(dtype=torch.float64), # for running on cpu: device='cpu'
resolution=128,
reynolds_number=100,
mach_number=0.05,
stencil=lt.D2Q9
)
simulation = lt.Simulation(
flow=flow,
collision=lt.BGKCollision(tau=flow.units.relaxation_parameter_lu),
reporter=[])
mlups = simulation(num_steps=1000)
print("Performance in MLUPS:", mlups)
================================================
FILE: examples/01a_first_example_TGV.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# A first example\n",
"This is a first example of how to use lettuce.\n",
"A two dimensional Taylor Green vortex is initialized and simulated for 10000 steps. Afterwards the energy and the velocity field is plotted."
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-04T07:24:40.895024Z",
"start_time": "2024-08-04T07:24:39.958634Z"
}
},
"source": [
"import lettuce as lt\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import torch"
],
"outputs": [],
"execution_count": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup\n",
"* for running on GPU: device = \"cuda\". CUDA drivers are required!\n",
"* dtype=torch.float32 for single precision - float64 for double precision\n",
"* select collision model (here BGKCollision) - try also KBCCollision or RegularizedCollision"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-04T07:24:43.170453Z",
"start_time": "2024-08-04T07:24:43.005785Z"
}
},
"source": [
"context = lt.Context(device=torch.device('cuda:0') if torch.cuda\n",
" .is_available() else torch.device('cpu'),\n",
" dtype=torch.float32)\n",
"flow = lt.TaylorGreenVortex(resolution=256, reynolds_number=100, \n",
" mach_number=0.05, stencil=lt.D2Q9,\n",
" context=context)\n",
"collision = lt.BGKCollision(tau=flow.units.relaxation_parameter_lu)\n",
"energyreporter = lt.ObservableReporter(lt.IncompressibleKineticEnergy(flow), interval=1000, out=None)\n",
"simulation = lt.Simulation(flow=flow, collision=collision, reporter=[energyreporter])"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"steps time IncompressibleKineticEnergy\n"
]
}
],
"execution_count": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Reporters will grab the results in between simulation steps (see reporters.py and simulation.py)\n",
"* Output: Column 1: simulation steps, Column 2: time in LU, Column 3: kinetic energy in PU\n",
"* Output: separate VTK-file with ux,uy,(uz) and p for every 100. time step in ./output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Run simulation"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-04T07:24:50.269735Z",
"start_time": "2024-08-04T07:24:45.023922Z"
}
},
"source": [
"mlups = simulation(10000)\n",
"print(\"Performance in MLUPS:\", mlups)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Performance in MLUPS: 124.98567838266325\n"
]
}
],
"execution_count": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Post process\n",
"### Energy Reporter\n",
"* Grab output of kinetic energy reporter"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-04T07:24:50.400266Z",
"start_time": "2024-08-04T07:24:50.270799Z"
}
},
"source": [
"energy = np.array(simulation.reporter[0].out)\n",
"print(energy.shape)\n",
"plt.plot(energy[:,1],energy[:,2])\n",
"plt.title('Kinetic energy')\n",
"plt.xlabel('Time')\n",
"plt.ylabel('Energy in physical units')\n",
"plt.show()"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(11, 3)\n"
]
},
{
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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onO0aNECFhYW+Omnn6oVouPHjyMlJeWBMgMAkydPxvjx45GbmwsPDw/079//ST8CkVFgmSEyEu+++y5kMhneeecdiKKIdevW1brQvP/++9izZw+io6MxefJkNGzYECUlJbh27Rp+++03LFmyBD4+PrCzs4Ofnx+2bduGjh07wtnZGa6urg/9Ire1tcUXX3yBMWPGoFOnThg7diw8PDyQlJSEhIQELFy4sNZ5VPHdd9+ha9eueO655/Diiy+iTp06uHPnDv7++2/ExcVh48aNj32/s7Mzpk2bhnnz5sHJyQl9+/bF9evXMWfOHHh5eUEme3Dq4tChQzFjxgwcOnQIb7/9NszNzVXKTGRsWGaIjMjbb78NmUyGWbNmQalUYv369bU6n5eXF2JjY/HBBx/gs88+w/Xr12FnZ4eAgAB06dKl2tWR5cuX4/XXX0evXr0gl8sxYsQIrFy58qHnHT16NLy9vfHJJ59gzJgxEEUR/v7+GDFihNry1FT79u1x8uRJfPTRR5g6dSpycnLg4uKCxo0bPzCp91E++ugj2NjYYMmSJVixYgWCg4OxePFizJo1C46Ojg+83srKCj179sSaNWswfvx4lTMTGRtBvDdlnoiItCY5ORnBwcF47733MHPmzGrPlZaWwt/fH23atHng5nxE9CBemSEi0rCEhASsW7cO0dHRsLe3x8WLF/Hpp5/C3t4eo0ePrnxdZmYmLl68iBUrVuD27dt46623JExNpD9YZoiINMzGxgaxsbFYvnw57t69CwcHB7Rr1w4fffRRteXZv/76K0aOHAkvLy8sWrSIy7GJaojDTERERKTXeAdgIiIi0mssM0RERKTXWGaIiIhIrxn8BGClUon09HTY2dmpvGkdERERSUMUReTn58Pb2/uhN5esyuDLTHp6Onx9faWOQURERE8gLS3tP+/cbfBlxs7ODkDFPwx7e3uJ0xAREVFN5OXlwdfXt/J7/HEMvszcG1qyt7dnmSEiItIzNZkiwgnAREREpNdYZoiIiEivscwQERGRXmOZISIiIr0maZk5dOgQevbsCW9vbwiCgK1bt1Z7XhRFzJ49G97e3rCyskK7du1w/vx5acISERGRTpK0zBQWFiIsLAwLFy586POffvop5s+fj4ULF+LUqVPw9PTEs88+i/z8fC0nJSIiIl0l6dLsrl27omvXrg99ThRFfPXV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"
},
"metadata": {},
"output_type": "display_data"
}
],
"execution_count": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Velocity\n",
"We calculate the speed in Lettuce units depending on the last 'f'. Then we convert this velocity into physical units. For further investigations the tensor must be converted into a Numpy-Array. The norm of the fractions in x and y direction is plotted afterwards."
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-04T07:25:00.256202Z",
"start_time": "2024-08-04T07:25:00.174826Z"
}
},
"source": [
"u = flow.u_pu.cpu().numpy()\n",
"u_norm = np.linalg.norm(u,axis=0)\n",
"plt.imshow(u_norm)\n",
"plt.show()"
],
"outputs": [
{
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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brsNXdcVj7lINq19AODjH/944lPf+MY3ku0HuX2eeuop3H333Xjuuedw/vx5tG2LM2fO4K233gp1ltmHZmkfYJd8iBfQfv3Xf50/85nPJGW/8iu/wn/xF3+xR2e0N/bAAw/wjTfeWNxmreXjx4/zZz/72VD2zjvv8NGjR/kf//Efd+kM99YA8GOPPRbWZ2mTn/3sZ7y6usqPPPJIqPO///u/bIzhb37zm7t27rthefswM9955538yU9+cnCfZWofZuZLly4xAH7qqaeYufpQbnn7MO+eDy3ck9fGxgZeeOEFnDlzJik/c+YMnn322T06q72zV155BSdOnMCpU6fwx3/8x/jBD34AAPjhD3+IixcvJu10+PBh/NZv/dZSthMwW5u88MILmEwmSZ0TJ07g9OnTS9NuTz75JI4dO4b3vve9+PSnP41Lly6FbcvWPq+//joA4OqrrwZQfSi3vH3EdsOHFq7z+r//+z90XYdrr702Kb/22mtx8eLFPTqrvbHf+I3fwJe//GV861vfwj/90z/h4sWLuPnmm/Haa6+FtqjtFG2WNrl48SIOHTqEd7/73YN1DrLdeuut+MpXvoLHH38cn/vc5/D888/jlltuwfr6OoDlah9mxn333YcPf/jDOH36NIDqQ9pK7QPsng8t5KzyAOJr0L0xc6/soNutt94alm+44QZ86EMfwi//8i/jn//5n0OAtLZT3zbTJsvSbnfccUdYPn36NN7//vfj5MmT+PrXv47bb799cL+D2D5nz57Fd7/7XTzzzDO9bdWHhttnt3xo4Z68rrnmGjRN0+uhL1261GNDy2ZXXXUVbrjhBrzyyish67C2U7RZ2uT48ePY2NjAT3/608E6y2Rra2s4efIkXnnlFQDL0z733HMPvva1r+GJJ57AddddF8qrDzkbap+S7ZQPLVzndejQIdx00004f/58Un7+/HncfPPNe3RW+8PW19fx3//931hbW8OpU6dw/PjxpJ02Njbw1FNPLW07zdImN910E1ZXV5M6Fy5cwPe+972lbLfXXnsNr776KtbW1gAc/PZhZpw9exaPPvooHn/8cZw6dSrZvuw+NK19SrZjPjRzasc+skceeYRXV1f5i1/8Iv/Xf/0X33vvvXzVVVfxj370o70+tV21+++/n5988kn+wQ9+wM899xzfdtttfOTIkdAOn/3sZ/no0aP86KOP8ksvvcR/8id/wmtra/zGG2/s8ZnvnF2+fJlffPFFfvHFFxkAf/7zn+cXX3yR/+d//oeZZ2uTz3zmM3zdddfxt7/9bf7Od77Dt9xyC994443ctu1e/axts7H2uXz5Mt9///387LPP8g9/+EN+4okn+EMf+hC/5z3vWZr2+bM/+zM+evQoP/nkk3zhwoXw9/Of/zzUWWYfmtY+u+lDC9l5MTP/3d/9HZ88eZIPHTrEv/Zrv5akai6L3XHHHby2tsarq6t84sQJvv322/n73/9+2G6t5QceeICPHz/Ohw8f5o985CP80ksv7eEZ77w98cQTDKD3d+eddzLzbG3y9ttv89mzZ/nqq6/mK6+8km+77Tb+8Y9/vAe/ZvttrH1+/vOf85kzZ/gXf/EXeXV1lX/pl36J77zzzt5vP8jtU2obAPzwww+HOsvsQ9PaZzd9qL4SpVq1atWqLZwtXMyrWrVq1apVq51XtWrVqlVbOKudV7Vq1apVWzirnVe1atWqVVs4q51XtWrVqlVbOKudV7Vq1apVWzirnVe1atWqVVs4q51XtWrVqlVbOKudV7Vq1apVWzirnVe1atWqVVs4q51XtWrVqlVbOKudV7Vq1apVWzj7/2CXTT2lkZXeAAAAAElFTkSuQmCC"
},
"metadata": {},
"output_type": "display_data"
}
],
"execution_count": 6
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": ""
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/01b_first_example_obstacle.py
================================================
import torch
import lettuce as lt
import matplotlib.pyplot as plt
import numpy as np
"""
Context definitions.
The context defines the default device (cpu or cuda) and datatype (e.g.,
float32 for single, float64 for double precision).
Native CUDA is currently not supported for the anti-bounce-back outlet.
"""
context = lt.Context(torch.device("cuda:0"), use_native=False)
"""
Flow definitions.
We need
1. the resolution in x and y direction
2. the Reynolds number (i.e., how fast the flow behaves compared to the
object's length and fluid's viscosity)
3. the Mach number (i.e., how fast the flow is compared to speed of sound;
Ma=0.3 is stable, above is discouraged)
4. the physical domain length in x-direction (this defines how lattice units
scale to physical units)
to initialize the Obstacle flow object.
"""
nx = 200
ny = 100
Re = 300
Ma = 0.01
lx = 1
flow = lt.Obstacle(context, [nx, ny], reynolds_number=Re, mach_number=Ma,
domain_length_x=lx)
"""
Per default, lt.Obstacle has no solid. It is stored in flow.mask as a fully
False numpy array.
To add a solid, we set some mask values to True by getting the domain extends
from flow.grid and creating a boolean array from it.
For a circle, just use a boolean function. Otherwise, you may as well use the
array indices.
"""
x, y = flow.grid
r = .05*y.max() # radius
x_c = 0.3*x.max() # center along x
y_c = 0.5*y.max() # center along y
flow.mask = ((x - x_c) ** 2 + (y - y_c) ** 2) < (r ** 2)
"""
To show 2D images, you need to rotate the outputs. This is because in lettuce,
the first axis is downstream, while for imshow it is vertical.
"""
plt.imshow(context.convert_to_ndarray(flow.mask.t()))
plt.show()
"""
Collision definition.
The collision is usually BGK (low dissipation, but may be unstable) or KBC
(higher dissipation, but generally stable). BGK is preferred for converging
flows, KBC is preferred for driven flows in smaller domains (where energy
conversation plays a smaller role, but gradients may be higher).
"""
collision = lt.KBCCollision(tau=flow.units.relaxation_parameter_lu)
"""
Simulation object setup.
"""
simulation = lt.Simulation(flow=flow, collision=collision, reporter=[])
"""
Reporters.
- Reporter objects are used to extract information later on or during the
simulation.
- They can be created as separate objects when required later
(see 01_example4convergence.py).
"""
energyreporter = lt.ObservableReporter(lt.IncompressibleKineticEnergy(flow),
interval=50)
simulation.reporter.append(energyreporter)
"""
Run num_steps iterations of the simulation.
This can be done repeatedly (see 02_converging_flows.py).
"""
mlups = simulation(num_steps=4000)
print("Performance in MLUPS:", mlups)
"""
Before or after simulation call, physical values can be extracted from the
flow.
Alternatively, the reporters can be drawn from the simulation.reporters list
(see 01_example4convergence.py)
"""
u = context.convert_to_ndarray(flow.u_pu)
u_norm = np.linalg.norm(u, axis=0).transpose()
plt.imshow(u_norm)
plt.title('Velocity after simulation')
plt.colorbar()
plt.tight_layout()
plt.show()
================================================
FILE: examples/02_converging_obstacle_flow.py
================================================
import lettuce as lt
import matplotlib.pyplot as plt
import numpy as np
import torch
"""
For descriptions of the initialization, refer to
'01b_first_example_obstacle.py'.
Here, we use a lower Reynolds number for faster convergence.
"""
context = lt.Context(device=torch.device('cuda:0' if torch.cuda.is_available()
else 'cpu'), dtype=torch.float32, use_native=False)
nx = 300
ny = 100
Re = 10
Ma = 0.1
lx = 1
flow = lt.Obstacle(context, [nx, ny], reynolds_number=Re, mach_number=Ma,
domain_length_x=lx)
x, y = flow.grid
r = .05*y.max() # radius
x_c = 0.3*x.max() # center along x
y_c = 0.5*y.max() # center along y
flow.mask = ((x - x_c) ** 2 + (y - y_c) ** 2) < (r ** 2)
collision = lt.BGKCollision(tau=flow.units.relaxation_parameter_lu)
simulation = lt.Simulation(flow=flow, collision=collision, reporter=[])
simulation.reporter.append(lt.VTKReporter(
interval=1000,
filename_base="./data/converging_obstacle"
))
"""
We now add a reporter which we access later. The output can be written to files
specified by out="reporter.txt"
"""
energy = lt.IncompressibleKineticEnergy(flow)
simulation.reporter.append(lt.ObservableReporter(energy, interval=1000,
out=None))
"""
Now, we do not just run the whole simulation for 30,000 steps, but check the
energy convergence every 2000 steps.
The populations are kept on the GPU until evaluated by [...].cpu()
"""
nmax = 30000
ntest = 1000
it = 0
i = 0
mlups = 0
energy_old = 1
energy_new = 1
while it <= nmax:
i += 1
it += ntest
mlups += simulation(num_steps=ntest)
energy_new = flow.incompressible_energy().cpu().mean().item()
print(f"avg MLUPS: {mlups / i:.3f}, avg energy: {energy_new:.8f}, "
f"rel. diff: {abs(energy_new - energy_old)/energy_old:.8f}")
if not energy_new == energy_new:
print("CRASHED!")
break
if abs(energy_new - energy_old)/energy_old < 0.0075:
print(f"CONVERGED! To {abs(energy_new - energy_old)/energy_old:.2%} "
f"after {it} iterations.")
break
energy_old = energy_new
u = context.convert_to_ndarray(flow.u_pu)
u_norm = np.linalg.norm(u, axis=0).transpose()
plt.imshow(u_norm)
plt.colorbar()
plt.title(f'Velocities at it={it}')
plt.show()
================================================
FILE: examples/03_outputs_TGV.py
================================================
import lettuce as lt
import torch
import numpy as np
import matplotlib.pyplot as plt
print("start")
# ---------- Set up simulation -------------
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
context = lt.Context(device=device, dtype=torch.float32) # single precision
# - torch.float64 for double precision
resolution = 80 # resolution of the lattice, low resolution leads to
# unstable speeds somewhen after 10 (PU)
flow = lt.TaylorGreenVortex(context, resolution, 1600, 0.1, lt.D3Q27)
# select collision model - try also KBCCollision or RegularizedCollision
collision = lt.BGKCollision(tau=flow.units.relaxation_parameter_lu)
simulation = lt.Simulation(flow, collision, [])
# reporters will grab the results in between simulation steps
# (see io.py and simulation.py)
# Output: Column 1: time in LU, Column 2: kinetic energy in PU
energy = lt.IncompressibleKineticEnergy(flow)
kinE_reporter = lt.ObservableReporter(energy, interval=1, out=None)
simulation.reporter.append(kinE_reporter)
# Output: separate VTK-file with ux,uy,uz and p for every time step in ../data
VTKreport = lt.VTKReporter(interval=25, filename_base='./data/tgv')
simulation.reporter.append(VTKreport)
# ---------- Simulate until time = tend (PU) -------------
tend = 10 # [PU]
nend = int(simulation.flow.units.convert_time_to_lu(10)) # [LU]
print(f"Simulating {nend} steps! Maybe drink some water in the meantime.")
# runs simulation, but also returns overall performance in MLUPS (million
# lattice units per second)
print("MLUPS: ", simulation(nend))
# ---------- Plot kinetic energy over time (PU) -------------
# grab output of kinetic energy reporter
E = np.asarray(kinE_reporter.out)
# normalize to size of grid, not always necessary
E[:, 1] = E[:, 1] / (2 * np.pi) ** 3
# save kinetic energy values for later use
np.save("data/TGV3DoutRes" + str(resolution) + "E", E)
fig = plt.figure()
ax1 = plt.subplot(1, 2, 1)
plt.xlabel('Time in physical units')
plt.ylabel('Kinetic energy in physical units')
ax1.plot(simulation.flow.units.convert_time_to_pu(range(0, E.shape[0])),
E[:, 1])
# ---------- Plot magnitude of speed in slice of 3D volume -------------
# grab u in PU
u = flow.u_pu
# [direction of u: Y, X, Z] (due to ij indexing)
uMagnitude = torch.pow(torch.pow(u[0, :, :, :], 2)
+ torch.pow(u[1, :, :, :], 2)
+ torch.pow(u[2, :, :, :], 2), 0.5)
# select slice to plot
uMagnitude = uMagnitude[:, :, round(0.1 * resolution)]
# send selected slice to CPU und numpy, to be able to plot it via matplotlib
uMagnitude = uMagnitude.cpu().numpy()
ax2 = plt.subplot(1, 2, 2)
ax2.matshow(uMagnitude)
plt.tight_layout()
plt.show()
plt.savefig('data/tgv3d-output.pdf')
================================================
FILE: examples/__init__.py
================================================
================================================
FILE: examples/advanced_flows/FailingTGVandObstacle.py
================================================
"""
This file showcases:
a) interrupting a TGV simulation using a reporter that detects NaN in f
b) interrupting an obstacle simulation using a reporter that detects Ma > 0.3
"""
import torch
import lettuce as lt
import os
if not os.path.exists("./data"):
os.mkdir("./data")
### SIMULATION 1: TGV with NaN Reporter###
# a) unstable TGV, that causes NaN values in f, which are detected by the NaN
# ... reporter, who interrupts the simulation.
flow = lt.TaylorGreenVortex(
lt.Context(dtype=torch.float64),
resolution=32,
reynolds_number=30000,
mach_number=0.3,
stencil=lt.D2Q9
)
nan_reporter = lt.NaNReporter(100, outdir="./data/nan_reporter",
vtk_out=True)
simulation = lt.BreakableSimulation(
flow=flow,
collision=lt.BGKCollision(tau=flow.units.relaxation_parameter_lu),
reporter=[nan_reporter])
simulation(10000)
print(f"Failed after {nan_reporter.failed_iteration} iterations")
### SIMULATION 2: obstacle with High Ma Reporter ###
# b) unstable obstacle flow, that causes high Ma values (Ma > 0.3), which are
# ... detected by the HighMa reporter, who interrupts the simulation.
flow = lt.Obstacle(
lt.Context(dtype=torch.float64,use_native=False),
resolution=[32, 32],
reynolds_number=100,
mach_number=0.01,
stencil=lt.D2Q9(),
domain_length_x=32
)
flow.mask = ((2 < flow.grid[0]) & (flow.grid[0] < 10)
& (2 < flow.grid[1]) & (flow.grid[1] < 10))
high_ma_reporter = lt.HighMaReporter(100, outdir="./data/highma_reporter",
vtk_out=True)
simulation = lt.BreakableSimulation(
flow=flow,
collision=lt.BGKCollision(tau=flow.units.relaxation_parameter_lu),
reporter=[high_ma_reporter])
simulation(10000)
print(f"Failed after {high_ma_reporter.failed_iteration} iterations")
================================================
FILE: examples/advanced_flows/LidDrivenCavity.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Lid-driven cavity flow example\n",
"This is an example of using the cavity flow\n",
"A two dimensional flow is initialized and simulated. Afterwards, the energy and the velocity field are plotted."
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-14T14:45:11.491029Z",
"start_time": "2024-08-14T14:45:10.421365Z"
}
},
"source": [
"import lettuce as lt\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import os"
],
"outputs": [],
"execution_count": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup\n",
"* for running on GPU: device = \"cuda\". CUDA drivers are required!\n",
"* dtype=torch.float32 for single precision - float64 for double precision\n",
"* select collision model (here BGKCollision) - try also KBCCollision or RegularizedCollision\n",
"\n",
"### Code:\n",
"* Reporter will grab the results in between simulation steps\n",
"* Output: Column 1: simulation steps, Column 2: time in LU, Column 3: kinetic energy in PU\n",
"* Output: separate VTK-file with ux,uy,(uz) and p for every 100. time step in ./output"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-14T14:45:11.922912Z",
"start_time": "2024-08-14T14:45:11.491874Z"
}
},
"source": [
"nmax = 100000\n",
"nconsole = 1000\n",
"nreport = 100\n",
"epsilon = 0.0001 # convergence condition: .1 % relative change\n",
"Re = 100\n",
"\n",
"context = lt.Context(use_native=False)\n",
"flow = lt.Cavity2D(context=context, resolution=64, reynolds_number=Re, mach_number=0.05)\n",
"simulation = lt.Simulation(flow=flow, collision=lt.KBCCollision(), reporter=[])\n",
"\n",
"Energy = lt.IncompressibleKineticEnergy(flow)\n",
"energy_reporter_internal = lt.ObservableReporter(Energy, interval=nreport, out=None)\n",
"simulation.reporter.append(energy_reporter_internal)\n",
"simulation.reporter.append(lt.ObservableReporter(Energy, interval=nconsole)) # print energy\n",
"if not os.path.isdir(\"data\"):\n",
" os.mkdir(\"data\")\n",
"simulation.reporter.append(lt.VTKReporter(interval=nreport, filename_base=f\"./data/cavity2d_Re{Re}/out\"))"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"steps time IncompressibleKineticEnergy\n",
"steps time IncompressibleKineticEnergy\n"
]
}
],
"execution_count": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Run simulations"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-14T14:46:07.843211Z",
"start_time": "2024-08-14T14:45:11.923485Z"
}
},
"source": [
"energy_new = 0\n",
"mlups = 0\n",
"iterations = int(nmax//nconsole)\n",
"for _ in range(iterations):\n",
" energy_old = energy_new\n",
" energy_new = Energy(flow.f).mean()\n",
" mlups += simulation(nconsole)\n",
" if abs((energy_new - energy_old)/energy_new) < epsilon:\n",
" print(\"CONVERGENCE! Less than \", epsilon*100, \" % relative change\")\n",
" break\n",
" if not energy_new == energy_new:\n",
" print(\"CRASH\")\n",
" break\n",
"print(\"avg MLUPS: \", mlups/iterations)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0.0 0.0\n",
"1000 0.45105489780439517 0.019674744457006454\n",
"2000 0.9021097956087903 0.02419084496796131\n",
"3000 1.3531646934131856 0.0268400888890028\n",
"4000 1.8042195912175807 0.028614206239581108\n",
"5000 2.255274489021976 0.029889840632677078\n",
"6000 2.706329386826371 0.030847690999507904\n",
"7000 3.157384284630766 0.031584933400154114\n",
"8000 3.6084391824351614 0.0321597158908844\n",
"9000 4.059494080239556 0.03261049836874008\n",
"10000 4.510548978043952 0.03296438604593277\n",
"11000 4.961603875848347 0.03324209898710251\n",
"12000 5.412658773652742 0.033459488302469254\n",
"13000 5.863713671457138 0.033629387617111206\n",
"14000 6.314768569261532 0.03376169875264168\n",
"15000 6.765823467065927 0.03386494889855385\n",
"16000 7.216878364870323 0.03394544497132301\n",
"17000 7.667933262674718 0.03400781750679016\n",
"18000 8.118988160479113 0.034056372940540314\n",
"19000 8.570043058283508 0.034093745052814484\n",
"20000 9.021097956087903 0.034122712910175323\n",
"21000 9.472152853892299 0.034145306795835495\n",
"22000 9.923207751696694 0.034162867814302444\n",
"23000 10.37426264950109 0.03417631983757019\n",
"24000 10.825317547305485 0.034186627715826035\n",
"25000 11.27637244510988 0.034194447100162506\n",
"26000 11.727427342914275 0.03420044109225273\n",
"27000 12.17848224071867 0.03420506417751312\n",
"28000 12.629537138523064 0.03420861065387726\n",
"29000 13.08059203632746 0.03421135991811752\n",
"30000 13.531646934131855 0.034213364124298096\n",
"CONVERGENCE! Less than 0.01 % relative change\n",
"avg MLUPS: 0.6618240655510539\n"
]
}
],
"execution_count": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Post process\n",
"### Energy Reporter\n",
"* Grab output of kinetic energy reporter"
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-14T14:46:07.920150Z",
"start_time": "2024-08-14T14:46:07.844066Z"
}
},
"source": [
"energy = np.array(simulation.reporter[0].out)\n",
"print(energy.shape)\n",
"plt.plot(energy[:,1],energy[:,2])\n",
"plt.title('Kinetic energy')\n",
"plt.xlabel('Time')\n",
"plt.ylabel('Energy in physical units')\n",
"plt.show()"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(301, 3)\n"
]
},
{
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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"
},
"metadata": {},
"output_type": "display_data"
}
],
"execution_count": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Velocity\n",
"We calculate the speed in Lettuce units depending on the last 'f'. Then we convert this velocity into physical units. For further investigations the tensor must be converted into a Numpy-Array. The norm of the fractions in x and y direction is plotted afterwards."
]
},
{
"cell_type": "code",
"metadata": {
"ExecuteTime": {
"end_time": "2024-08-14T14:46:08.012981Z",
"start_time": "2024-08-14T14:46:07.920728Z"
}
},
"source": [
"u_x, u_y = context.convert_to_ndarray(flow.u_pu)\n",
"x, y = [context.convert_to_ndarray(_) for _ in flow.grid]\n",
"plt.quiver(x.T, y.T, u_x.T, u_y.T)"
],
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.quiver.Quiver at 0x7f3c654bf260>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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
gitextract_tttiteof/ ├── .codeclimate.yml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── BUG_REPORT.yml │ │ └── FEATURE_REQUEST.yml │ ├── pull_request_template.md │ └── workflows/ │ └── CI.yml ├── .gitignore ├── .readthedocs.yaml ├── AUTHORS.rst ├── LICENSE ├── README.rst ├── docs/ │ ├── README.md │ ├── authors.rst │ ├── conf.py │ ├── contributing.rst │ ├── history.rst │ ├── index.rst │ ├── installation.rst │ ├── make.bat │ ├── modules.rst │ ├── readme.rst │ └── usage.rst ├── examples/ │ ├── 00_simplest_TGV.py │ ├── 01a_first_example_TGV.ipynb │ ├── 01b_first_example_obstacle.py │ ├── 02_converging_obstacle_flow.py │ ├── 03_outputs_TGV.py │ ├── __init__.py │ ├── advanced_flows/ │ │ ├── FailingTGVandObstacle.py │ │ ├── LidDrivenCavity.ipynb │ │ ├── MixingLayer.ipynb │ │ ├── PartiallySaturatedObstacle.py │ │ └── PorousMedium.ipynb │ ├── advanced_projects/ │ │ ├── __init__.py │ │ └── efficient_bounce_back_obstacle/ │ │ ├── 00_run_parametrized_project.ipynb │ │ ├── 01_script_cylinder_simulation.py │ │ ├── __init__.py │ │ ├── auxiliary_code/ │ │ │ ├── __init__.py │ │ │ ├── data_processing_and_plotting.py │ │ │ └── helperCode.py │ │ ├── boundary/ │ │ │ ├── __init__.py │ │ │ ├── fullway_bounce_back_boundary.py │ │ │ ├── halfway_bounce_back_boundary.py │ │ │ ├── linear_interpolated_bounce_back_boundary.py │ │ │ └── solid_boundary_data.py │ │ ├── flow/ │ │ │ ├── __init__.py │ │ │ └── obstacle_cylinder.py │ │ ├── profile_reference_data/ │ │ │ ├── Fig09_ux_profile_pos1_DI2018.csv │ │ │ ├── Fig09_ux_profile_pos1_KM2000.csv │ │ │ ├── Fig09_ux_profile_pos1_LS1993.csv │ │ │ ├── Fig09_ux_profile_pos1_WR2008.csv │ │ │ ├── Fig09_ux_profile_pos2_DI2018.csv │ │ │ ├── Fig09_ux_profile_pos2_KM2000.csv │ │ │ ├── Fig09_ux_profile_pos2_LS1993.csv │ │ │ ├── Fig09_ux_profile_pos2_WR2008.csv │ │ │ ├── Fig09_ux_profile_pos3_DI2018.csv │ │ │ ├── Fig09_ux_profile_pos3_KM2000.csv │ │ │ ├── Fig09_ux_profile_pos3_LS1993.csv │ │ │ ├── Fig09_ux_profile_pos3_WR2008.csv │ │ │ ├── Fig10_uy_profile_pos1_DI2018.csv │ │ │ ├── Fig10_uy_profile_pos1_KM2000.csv │ │ │ ├── Fig10_uy_profile_pos1_LS1993.csv │ │ │ ├── Fig10_uy_profile_pos1_WR2008.csv │ │ │ ├── Fig10_uy_profile_pos2_DI2018.csv │ │ │ ├── Fig10_uy_profile_pos2_KM2000.csv │ │ │ ├── Fig10_uy_profile_pos2_LS1993.csv │ │ │ ├── Fig10_uy_profile_pos2_WR2008.csv │ │ │ ├── Fig10_uy_profile_pos3_DI2018.csv │ │ │ ├── Fig10_uy_profile_pos3_KM2000.csv │ │ │ ├── Fig10_uy_profile_pos3_LS1993.csv │ │ │ ├── Fig10_uy_profile_pos3_WR2008.csv │ │ │ ├── Fig11_uxux_profile_pos1_DI2018.csv │ │ │ ├── Fig11_uxux_profile_pos1_KM2000.csv │ │ │ ├── Fig11_uxux_profile_pos1_R2016.csv │ │ │ ├── Fig11_uxux_profile_pos2_BM1994.csv │ │ │ ├── Fig11_uxux_profile_pos2_DI2018.csv │ │ │ ├── Fig11_uxux_profile_pos2_KM2000.csv │ │ │ ├── Fig11_uxux_profile_pos2_LS1993.csv │ │ │ ├── Fig11_uxux_profile_pos2_R2016.csv │ │ │ ├── Fig11_uxux_profile_pos3_DI2018.csv │ │ │ ├── Fig11_uxux_profile_pos3_KM2000.csv │ │ │ ├── Fig11_uxux_profile_pos3_R2016.csv │ │ │ ├── Fig12_uyuy_profile_pos1_DI2018.csv │ │ │ ├── Fig12_uyuy_profile_pos1_R2016.csv │ │ │ ├── Fig12_uyuy_profile_pos2_BM1994.csv │ │ │ ├── Fig12_uyuy_profile_pos2_DI2018.csv │ │ │ ├── Fig12_uyuy_profile_pos2_LS1993.csv │ │ │ ├── Fig12_uyuy_profile_pos2_R2016.csv │ │ │ ├── Fig12_uyuy_profile_pos3_DI2018.csv │ │ │ ├── Fig12_uyuy_profile_pos3_R2016.csv │ │ │ ├── Fig13_uxuy_profile_pos1_BM1994.csv │ │ │ ├── Fig13_uxuy_profile_pos1_DI2018.csv │ │ │ ├── Fig13_uxuy_profile_pos1_R2016.csv │ │ │ ├── Fig13_uxuy_profile_pos2_BM1994.csv │ │ │ ├── Fig13_uxuy_profile_pos2_DI2018.csv │ │ │ ├── Fig13_uxuy_profile_pos2_LS1993.csv │ │ │ ├── Fig13_uxuy_profile_pos2_R2016.csv │ │ │ ├── Fig13_uxuy_profile_pos3_BM1994.csv │ │ │ ├── Fig13_uxuy_profile_pos3_DI2018.csv │ │ │ └── Fig13_uxuy_profile_pos3_R2016.csv │ │ ├── reporter/ │ │ │ ├── __init__.py │ │ │ ├── observables_force_coefficients.py │ │ │ ├── reporter_ProfileReporter.py │ │ │ └── reporter_advanced_vtk_reporter.py │ │ └── simulation/ │ │ ├── __init__.py │ │ └── ebb_simulation.py │ ├── development/ │ │ ├── .gitignore │ │ ├── example_progress_reporter_based_on_simplest_TGV.py │ │ └── manually_generate_cuda_native.py │ └── simple_flows/ │ ├── Couette.ipynb │ ├── DecayingTurbulence.ipynb │ ├── LambOseenVortex.py │ ├── Obstacle.ipynb │ └── Poiseuille.ipynb ├── lettuce/ │ ├── __init__.py │ ├── _context.py │ ├── _flow.py │ ├── _simulation.py │ ├── _stencil.py │ ├── _unit.py │ ├── _version.py │ ├── base.py │ ├── cli.py │ ├── cuda_native/ │ │ ├── __init__.py │ │ ├── _default_code_gen.py │ │ ├── _generator.py │ │ ├── _registry.py │ │ ├── _template.py │ │ ├── _transformer.py │ │ ├── _util.py │ │ └── ext/ │ │ ├── __init__.py │ │ ├── _boundary/ │ │ │ ├── __init__.py │ │ │ ├── bounce_back_boundary.py │ │ │ ├── equilibrium_pu.py │ │ │ └── no_boundary.py │ │ ├── _collision/ │ │ │ ├── __init__.py │ │ │ ├── bgk_collision.py │ │ │ └── no_collision.py │ │ ├── _equilibrium/ │ │ │ ├── __init__.py │ │ │ └── quadratic_equilibrium.py │ │ └── _force/ │ │ ├── __init__.py │ │ └── _force.py │ ├── ext/ │ │ ├── __init__.py │ │ ├── _boundary/ │ │ │ ├── __init__.py │ │ │ ├── anti_bounce_back_outlet.py │ │ │ ├── bounce_back_boundary.py │ │ │ ├── equilibrium_boundary_pu.py │ │ │ ├── equilibrium_outlet_p.py │ │ │ └── partially_saturated_boundary.py │ │ ├── _collision/ │ │ │ ├── __init__.py │ │ │ ├── bgk_collision.py │ │ │ ├── kbc_collision.py │ │ │ ├── mrt_collision.py │ │ │ ├── no_collision.py │ │ │ ├── regularized_collision.py │ │ │ ├── smagorinsky_collision.py │ │ │ └── trt_collision.py │ │ ├── _equilibrium/ │ │ │ ├── __init__.py │ │ │ ├── incompressible_quadratic_equilibrium.py │ │ │ ├── quadratic_equilibrium.py │ │ │ └── quadratic_equilibrium_less_memory.py │ │ ├── _flows/ │ │ │ ├── __init__.py │ │ │ ├── _ext_flow.py │ │ │ ├── _flow_by_name.py │ │ │ ├── couette.py │ │ │ ├── decayingturbulence.py │ │ │ ├── doublyshear.py │ │ │ ├── lamboseenvortex.py │ │ │ ├── liddrivencavity.py │ │ │ ├── obstacle.py │ │ │ ├── poiseuille.py │ │ │ └── taylorgreen.py │ │ ├── _force/ │ │ │ ├── __init__.py │ │ │ ├── _force.py │ │ │ ├── guo.py │ │ │ └── shan_chen.py │ │ ├── _reporter/ │ │ │ ├── __init__.py │ │ │ ├── error_reporter.py │ │ │ ├── failure_reporter.py │ │ │ ├── observable_reporter.py │ │ │ ├── progress_reporter.py │ │ │ ├── vtk_reporter.py │ │ │ └── write_image.py │ │ └── _stencil/ │ │ ├── __init__.py │ │ ├── d1q3.py │ │ ├── d2q9.py │ │ ├── d3q15.py │ │ ├── d3q19.py │ │ └── d3q27.py │ └── util/ │ ├── __init__.py │ ├── datautils.py │ ├── moments.py │ └── utility.py ├── native_cuda_synopsis.md ├── pyproject.toml ├── requirements.txt ├── tests/ │ ├── __init__.py │ ├── boundary/ │ │ ├── test_antibounceback_outlet_bc.py │ │ ├── test_bc_masks.py │ │ ├── test_bounceback_bc.py │ │ ├── test_equilibrium_bc_outlet_p.py │ │ ├── test_equilibrium_bc_pu.py │ │ ├── test_equilibrium_pressure_outlet.py │ │ └── test_partiallysaturated_bc.py │ ├── collision/ │ │ ├── test_collision_conserves_mass.py │ │ ├── test_collision_conserves_momentum.py │ │ ├── test_collision_fixpoint_2x.py │ │ ├── test_collision_fixpoint_2x_MRT.py │ │ ├── test_collision_optimizes_pseudo_entropy.py │ │ ├── test_collision_relaxes_shear_moments.py │ │ └── test_force.py │ ├── conftest.py │ ├── flow/ │ │ ├── test_divergence.py │ │ ├── test_einsum.py │ │ ├── test_flow.py │ │ ├── test_initialize_fneq.py │ │ ├── test_initialize_pressure.py │ │ ├── test_obstacle.py │ │ └── test_pressure_poisson.py │ ├── moments/ │ │ ├── test_conserved_moments_d2q9.py │ │ ├── test_getitem.py │ │ ├── test_inverse_transform.py │ │ ├── test_moment_equilibrium_D3Q27Hermite.py │ │ ├── test_moment_equilibrium_dellar.py │ │ ├── test_moment_equilibrium_lallemand.py │ │ ├── test_moments_density.py │ │ └── test_orthogonality.py │ ├── native/ │ │ ├── __init__.py │ │ ├── test_native_bgk_collision.py │ │ ├── test_native_bounce_back.py │ │ ├── test_native_equilibrium_pu.py │ │ ├── test_native_no_streaming_mask.py │ │ ├── test_native_streaming.py │ │ └── test_native_streaming_strategy.py │ ├── reporter/ │ │ ├── test_HDF5Reporter.py │ │ ├── test_energy_spectrum.py │ │ ├── test_generic_reporters.py │ │ ├── test_high_ma_reporter.py │ │ ├── test_nan_reporter.py │ │ ├── test_vtk_reporter_mask.py │ │ ├── test_vtk_reporter_no_mask.py │ │ ├── test_write_image.py │ │ └── test_write_vtk.py │ ├── stencil/ │ │ ├── test_first_zero.py │ │ ├── test_opposite.py │ │ ├── test_symmetry.py │ │ └── test_weights.py │ ├── test_checkpoint.py │ ├── test_cli.py │ ├── test_equilibrium.py │ ├── unit/ │ │ ├── __init__.py │ │ ├── test_consistency.py │ │ ├── test_conversion_reversible.py │ │ └── test_reynolds_number_consistent.py │ └── util/ │ ├── test_grid_fine_to_coarse.py │ └── test_torch_gradient.py └── versioneer.py
SYMBOL INDEX (827 symbols across 133 files)
FILE: examples/advanced_flows/PartiallySaturatedObstacle.py
class ObstaclePartially (line 22) | class ObstaclePartially(lt.Obstacle):
method __init__ (line 23) | def __init__(self, resolution, domain_length_x):
method post_boundaries (line 29) | def post_boundaries(self):
method initial_solution (line 48) | def initial_solution(self, x):
class Show2D (line 60) | class Show2D:
method __init__ (line 61) | def __init__(self, mask, outdir: str, **kwargs):
method __call__ (line 75) | def __call__(self, data, title: str, name: str, vlim=None):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/auxiliary_code/data_processing_and_plotting.py
function plot_force_coefficient (line 23) | def plot_force_coefficient(data_array: np.ndarray, ylabel: str, ylim: tu...
function analyze_periodic_timeseries (line 105) | def analyze_periodic_timeseries(data_array: np.ndarray, periodic_start_r...
function draw_circular_mask (line 262) | def draw_circular_mask(flow: 'Flow', gridpoints_per_diameter: int, outpu...
class ProfilePlotter (line 430) | class ProfilePlotter:
method __init__ (line 439) | def __init__(self, flow: 'Flow', output_path: str, reference_data_path...
method import_profile_reference_data (line 453) | def import_profile_reference_data(self, data_path: str):
method process_data (line 579) | def process_data(self, save: bool = False):
method save_timeseries_to_files (line 666) | def save_timeseries_to_files(self, basepath: str):
method plot_velocity_profiles (line 679) | def plot_velocity_profiles(self, show_reference: bool = False,
method plot_reynolds_stress_profiles (line 802) | def plot_reynolds_stress_profiles(self, show_reference: bool = False,
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/auxiliary_code/helperCode.py
class Logger (line 5) | class Logger(object):
method __init__ (line 7) | def __init__(self, outdir):
method write (line 11) | def write(self, message):
method flush (line 17) | def flush(self):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/boundary/fullway_bounce_back_boundary.py
class FullwayBounceBackBoundary (line 9) | class FullwayBounceBackBoundary(Boundary):
method __init__ (line 20) | def __init__(self, context: 'Context', flow: 'Flow', mask: np.ndarray ...
method __call__ (line 135) | def __call__(self, flow: 'Flow'):
method calc_force_on_boundary (line 161) | def calc_force_on_boundary(self, f: torch.Tensor):
method make_no_collision_mask (line 174) | def make_no_collision_mask(self, f_shape: List[int], context: 'Context...
method make_no_streaming_mask (line 177) | def make_no_streaming_mask(self, shape: List[int], context: 'Context')...
method native_available (line 181) | def native_available(self) -> bool:
method native_generator (line 184) | def native_generator(self, index: int):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/boundary/halfway_bounce_back_boundary.py
class HalfwayBounceBackBoundary (line 10) | class HalfwayBounceBackBoundary(Boundary):
method __init__ (line 19) | def __init__(self, context: 'Context', flow: 'Flow', solid_boundary_da...
method __call__ (line 170) | def __call__(self, flow: 'Flow'):
method make_no_collision_mask (line 192) | def make_no_collision_mask(self, f_shape: List[int], context: 'Context'
method make_no_streaming_mask (line 203) | def make_no_streaming_mask(self, f_shape: List[int], context: 'Context'
method calc_force_on_boundary (line 211) | def calc_force_on_boundary(self):
method store_f_collided (line 220) | def store_f_collided(self, f_collided: torch.Tensor):
method initialize_f_collided (line 244) | def initialize_f_collided(self):
method native_available (line 250) | def native_available(self) -> bool:
method native_generator (line 253) | def native_generator(self, index: int):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/boundary/linear_interpolated_bounce_back_boundary.py
class LinearInterpolatedBounceBackBoundary (line 9) | class LinearInterpolatedBounceBackBoundary(Boundary):
method __init__ (line 20) | def __init__(self, context: 'Context', flow: 'Flow', solid_boundary_da...
method __call__ (line 56) | def __call__(self, flow: 'Flow'):
method make_no_streaming_mask (line 104) | def make_no_streaming_mask(self, f_shape: List[int], context: Context):
method make_no_collision_mask (line 111) | def make_no_collision_mask(self, f_shape: List[int], context: Context):
method calc_force_on_boundary (line 118) | def calc_force_on_boundary(self, f_bounced: torch.Tensor):
method store_f_collided (line 151) | def store_f_collided(self, f_collided: torch.Tensor):
method initialize_f_collided (line 193) | def initialize_f_collided(self):
method native_available (line 207) | def native_available(self) -> bool:
method native_generator (line 210) | def native_generator(self, index: int):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/boundary/solid_boundary_data.py
class SolidBoundaryData (line 8) | class SolidBoundaryData(dict):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/flow/obstacle_cylinder.py
class ObstacleCylinder (line 15) | class ObstacleCylinder(ExtFlow):
method __init__ (line 38) | def __init__(self, context: Context, resolution: Union[int, List[int]],
method make_units (line 185) | def make_units(self, reynolds_number: float, mach_number: float, resol...
method make_resolution (line 194) | def make_resolution(self, resolution: Union[int, List[int]],
method obstacle_mask (line 202) | def obstacle_mask(self):
method obstacle_mask (line 206) | def obstacle_mask(self, m: np.ndarray | torch.Tensor):
method initial_pu (line 210) | def initial_pu(self):
method make_solid_boundary_data (line 287) | def make_solid_boundary_data(self, x_center: float, y_center: float, r...
method make_ibb_index_lists (line 293) | def make_ibb_index_lists(self, x_center: float, y_center: float, radiu...
method grid (line 489) | def grid(self):
method post_boundaries (line 495) | def post_boundaries(self):
method post_streaming_boundaries (line 515) | def post_streaming_boundaries(self):
method _unit_vector (line 590) | def _unit_vector(self, i=0):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/reporter/observables_force_coefficients.py
class DragCoefficient (line 15) | class DragCoefficient(Observable):
method __init__ (line 22) | def __init__(self, flow: 'Flow', obstacle_boundary:
method __call__ (line 37) | def __call__(self, f: torch.Tensor = None):
class LiftCoefficient (line 51) | class LiftCoefficient(Observable):
method __init__ (line 58) | def __init__(self, flow: 'Flow', obstacle_boundary:
method __call__ (line 73) | def __call__(self, f: torch.Tensor = None):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/reporter/reporter_ProfileReporter.py
class ProfileReporter (line 10) | class ProfileReporter(Reporter):
method __init__ (line 16) | def __init__(self, interval: int, flow: 'Flow', position_lu: float, i_...
method __call__ (line 39) | def __call__(self, simulation: 'Simulation'):
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/reporter/reporter_advanced_vtk_reporter.py
function write_vtk (line 15) | def write_vtk(point_dict, id=0, filename_base="./data/output",
class VTKReporterAdvanced (line 26) | class VTKReporterAdvanced(Reporter):
method __init__ (line 33) | def __init__(self, flow: 'Flow', interval: int = 50, filename_base: st...
method __call__ (line 59) | def __call__(self, simulation: Simulation):
method output_mask (line 100) | def output_mask(self, mask: np.ndarray | torch.Tensor, outdir: Optiona...
class VTKsliceReporter (line 145) | class VTKsliceReporter(Reporter):
method __init__ (line 149) | def __init__(self, flow: 'Flow', interval: int = 50, filename_base: st...
method __call__ (line 195) | def __call__(self, simulation: Simulation):
method output_mask (line 242) | def output_mask(self, mask: np.ndarray | torch.Tensor, outdir: Optiona...
FILE: examples/advanced_projects/efficient_bounce_back_obstacle/simulation/ebb_simulation.py
class EbbSimulation (line 11) | class EbbSimulation(Simulation):
method __init__ (line 17) | def __init__(self, flow: 'Flow', collision: 'Collision',
method _post_streaming_boundaries (line 81) | def _post_streaming_boundaries(self):
method _pass_f_collided (line 87) | def _pass_f_collided(self):
method __call__ (line 93) | def __call__(self, num_steps: int) -> float:
FILE: examples/development/manually_generate_cuda_native.py
function ensure_empty_dir (line 8) | def ensure_empty_dir(path):
function main (line 26) | def main(verbose=False, install=False):
FILE: lettuce/_context.py
class Context (line 9) | class Context:
method __init__ (line 10) | def __init__(self, device: Optional[torch.device | str] = None,
method synchronize (line 64) | def synchronize(self):
method empty_tensor (line 72) | def empty_tensor(self, size: Union[List[int], torch.Size], *args,
method zero_tensor (line 77) | def zero_tensor(self, size: Union[List[int], torch.Size], *args,
method full_tensor (line 82) | def full_tensor(self, size: Union[List[int], torch.Size], value, *args,
method one_tensor (line 87) | def one_tensor(self, size: Union[List[int], torch.Size], *args, dtype=...
method convert_to_tensor (line 92) | def convert_to_tensor(self, array, *args,
method convert_to_ndarray (line 118) | def convert_to_ndarray(tensor: Union[torch.Tensor, List]) -> np.ndarray:
FILE: lettuce/_flow.py
class Equilibrium (line 17) | class Equilibrium(ABC):
method __call__ (line 19) | def __call__(self, flow: 'Flow', rho=None, u=None) -> torch.Tensor:
method native_available (line 23) | def native_available(self) -> bool:
method native_generator (line 27) | def native_generator(self) -> 'NativeEquilibrium':
class Boundary (line 31) | class Boundary(ABC):
method __call__ (line 33) | def __call__(self, flow: 'Flow'):
method make_no_collision_mask (line 37) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
method make_no_streaming_mask (line 42) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
method native_available (line 47) | def native_available(self) -> bool:
method native_generator (line 51) | def native_generator(self, index: int) -> 'NativeBoundary':
class Flow (line 55) | class Flow(ABC):
method __init__ (line 81) | def __init__(self, context: 'Context', resolution: List[int],
method pre_boundaries (line 99) | def pre_boundaries(self) -> List['Boundary']:
method post_boundaries (line 105) | def post_boundaries(self) -> List['Boundary']:
method boundaries (line 118) | def boundaries(self) -> List['Boundary']:
method initial_pu (line 123) | def initial_pu(self) -> (float, Union[np.array, torch.Tensor]):
method initialize (line 127) | def initialize(self):
method f_next (line 146) | def f_next(self) -> torch.Tensor:
method f_next (line 154) | def f_next(self, f_next_: torch.Tensor):
method rho (line 157) | def rho(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method rho_pu (line 162) | def rho_pu(self) -> torch.Tensor:
method p_pu (line 166) | def p_pu(self) -> torch.Tensor:
method u_pu (line 170) | def u_pu(self):
method j (line 173) | def j(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method u (line 178) | def u(self, f: Optional[torch.Tensor] = None, rho=None, acceleration=None
method velocity (line 196) | def velocity(self, f: Optional[torch.Tensor] = None):
method incompressible_energy (line 200) | def incompressible_energy(self, f: Optional[torch.Tensor] = None
method entropy (line 206) | def entropy(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method pseudo_entropy_global (line 213) | def pseudo_entropy_global(self, f: Optional[torch.Tensor] = None
method pseudo_entropy_local (line 220) | def pseudo_entropy_local(self, f: Optional[torch.Tensor] = None
method shear_tensor (line 228) | def shear_tensor(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method einsum (line 236) | def einsum(self, equation, fields, *args) -> torch.Tensor:
method dump (line 258) | def dump(self, filename):
method load (line 262) | def load(self, filename):
function pressure_poisson (line 271) | def pressure_poisson(units: 'UnitConversion', u, rho0, tol_abs=1e-10,
function initialize_pressure_poisson (line 323) | def initialize_pressure_poisson(flow: 'Flow',
function initialize_f_neq (line 341) | def initialize_f_neq(flow: 'Flow'):
FILE: lettuce/_simulation.py
class Collision (line 17) | class Collision(ABC):
method __call__ (line 19) | def __call__(self, flow: 'Flow'):
method native_available (line 23) | def native_available(self) -> bool:
method native_generator (line 27) | def native_generator(self, index: int) -> 'NativeCollision':
class Reporter (line 31) | class Reporter(ABC):
method __init__ (line 34) | def __init__(self, interval: int):
method __call__ (line 38) | def __call__(self, simulation: 'Simulation'):
class Simulation (line 42) | class Simulation:
method __init__ (line 53) | def __init__(self, flow: 'Flow', collision: 'Collision',
method step (line 231) | def step(self, num_steps: int):
method units (line 238) | def units(self):
method __stream (line 242) | def __stream(f, i, e, d):
method _stream (line 245) | def _stream(self):
method _collide (line 258) | def _collide(self):
method _report (line 307) | def _report(self):
method __call__ (line 311) | def __call__(self, num_steps):
class BreakableSimulation (line 325) | class BreakableSimulation(Simulation):
method __init__ (line 326) | def __init__(self, flow: 'Flow', collision: 'Collision',
method __call__ (line 330) | def __call__(self, num_steps: int) -> float:
FILE: lettuce/_stencil.py
class Stencil (line 14) | class Stencil(ABC):
method d (line 22) | def d(self) -> int:
method q (line 27) | def q(self) -> int:
class TorchStencil (line 31) | class TorchStencil:
method __init__ (line 37) | def __init__(self, stencil: 'Stencil', context: 'Context'):
method d (line 44) | def d(self) -> Literal[1, 2, 3]:
method q (line 49) | def q(self) -> int:
FILE: lettuce/_unit.py
class UnitConversion (line 13) | class UnitConversion:
method __init__ (line 21) | def __init__(self, reynolds_number, mach_number=0.05,
method characteristic_velocity_lu (line 35) | def characteristic_velocity_lu(self):
method characteristic_pressure_pu (line 39) | def characteristic_pressure_pu(self):
method characteristic_pressure_lu (line 44) | def characteristic_pressure_lu(self):
method viscosity_lu (line 49) | def viscosity_lu(self):
method viscosity_pu (line 54) | def viscosity_pu(self):
method relaxation_parameter_lu (line 59) | def relaxation_parameter_lu(self):
method convert_velocity_to_pu (line 62) | def convert_velocity_to_pu(self, velocity_in_lu):
method convert_velocity_to_lu (line 66) | def convert_velocity_to_lu(self, velocity_in_pu):
method convert_acceleration_to_pu (line 70) | def convert_acceleration_to_pu(self, acceleration_in_lu):
method convert_acceleration_to_lu (line 77) | def convert_acceleration_to_lu(self, acceleration_in_pu):
method convert_time_to_pu (line 84) | def convert_time_to_pu(self, time_in_lu):
method convert_time_to_lu (line 89) | def convert_time_to_lu(self, time_in_pu):
method convert_density_lu_to_pressure_pu (line 94) | def convert_density_lu_to_pressure_pu(self, density_lu):
method convert_pressure_pu_to_density_lu (line 99) | def convert_pressure_pu_to_density_lu(self, pressure_pu):
method convert_density_to_pu (line 103) | def convert_density_to_pu(self, density_lu):
method convert_density_to_lu (line 107) | def convert_density_to_lu(self, density_pu):
method convert_pressure_to_pu (line 111) | def convert_pressure_to_pu(self, pressure_lu):
method convert_pressure_to_lu (line 115) | def convert_pressure_to_lu(self, pressure_pu):
method convert_length_to_pu (line 119) | def convert_length_to_pu(self, length_lu):
method convert_length_to_lu (line 123) | def convert_length_to_lu(self, length_pu):
method convert_energy_to_pu (line 127) | def convert_energy_to_pu(self, energy_lu):
method convert_energy_to_lu (line 132) | def convert_energy_to_lu(self, energy_pu):
method convert_incompressible_energy_to_pu (line 137) | def convert_incompressible_energy_to_pu(self, energy_lu):
method convert_incompressible_energy_to_lu (line 142) | def convert_incompressible_energy_to_lu(self, energy_pu):
FILE: lettuce/_version.py
function get_keywords (line 20) | def get_keywords():
class VersioneerConfig (line 33) | class VersioneerConfig:
function get_config (line 37) | def get_config():
class NotThisMethod (line 51) | class NotThisMethod(Exception):
function register_vcs_handler (line 59) | def register_vcs_handler(vcs, method): # decorator
function run_command (line 72) | def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
function versions_from_parentdir (line 107) | def versions_from_parentdir(parentdir_prefix, root, verbose):
function git_get_keywords (line 132) | def git_get_keywords(versionfile_abs):
function git_versions_from_keywords (line 160) | def git_versions_from_keywords(keywords, tag_prefix, verbose):
function git_pieces_from_vcs (line 224) | def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
function plus_or_dot (line 352) | def plus_or_dot(pieces):
function render_pep440 (line 359) | def render_pep440(pieces):
function render_pep440_branch (line 384) | def render_pep440_branch(pieces):
function pep440_split_post (line 414) | def pep440_split_post(ver):
function render_pep440_pre (line 424) | def render_pep440_pre(pieces):
function render_pep440_post (line 448) | def render_pep440_post(pieces):
function render_pep440_post_branch (line 475) | def render_pep440_post_branch(pieces):
function render_pep440_old (line 504) | def render_pep440_old(pieces):
function render_git_describe (line 526) | def render_git_describe(pieces):
function render_git_describe_long (line 546) | def render_git_describe_long(pieces):
function render (line 566) | def render(pieces, style):
function get_versions (line 602) | def get_versions():
FILE: lettuce/base.py
class LatticeBase (line 4) | class LatticeBase:
method __init__ (line 18) | def __init__(self, lattice):
method native_available (line 30) | def native_available(self) -> bool:
method create_native (line 40) | def create_native(self) -> Optional['NativeLatticeBase']:
FILE: lettuce/cli.py
function main (line 39) | def main(ctx, cuda, gpu_id, precision):
function benchmark (line 87) | def benchmark(ctx, steps, resolution, profile_out, flow, vtk_out,
function convergence (line 139) | def convergence(ctx, use_cuda_native):
FILE: lettuce/cuda_native/_default_code_gen.py
class StreamingStrategy (line 13) | class StreamingStrategy(Enum):
method pre_streaming (line 20) | def pre_streaming(self) -> bool:
method post_streaming (line 24) | def post_streaming(self) -> bool:
class DefaultCodeGeneration (line 28) | class DefaultCodeGeneration(Registry):
method __init__ (line 38) | def __init__(self, stencil: 'Stencil',
method d (line 60) | def d(self) -> str:
method q (line 64) | def q(self) -> str:
method e (line 68) | def e(self, q: int, d: int) -> str:
method w (line 74) | def w(self, q: int) -> str:
method opposite (line 79) | def opposite(self, q: int) -> str:
method support_no_collision_mask (line 84) | def support_no_collision_mask(self) -> str:
method support_no_streaming_mask (line 88) | def support_no_streaming_mask(self) -> str:
method thread_count (line 92) | def thread_count(self, d: Optional[int] = None) -> str:
method cuda_block_count (line 102) | def cuda_block_count(self, d: Optional[int] = None) -> str:
method kernel_block_count (line 111) | def kernel_block_count(self, d: int) -> str:
method cuda_size (line 117) | def cuda_size(self, d: int) -> str:
method kernel_size (line 124) | def kernel_size(self, d: int) -> str:
method kernel_index (line 130) | def kernel_index(self, d: int) -> str:
method cuda_stride (line 138) | def cuda_stride(self, d: int) -> str:
method kernel_stride (line 143) | def kernel_stride(self, d: int) -> str:
method kernel_offset (line 147) | def kernel_offset(self, d: int, v: int = 0) -> str:
method kernel_base_index (line 170) | def kernel_base_index(self) -> str:
method assert_ncm (line 174) | def assert_ncm(self):
method assert_nsm (line 179) | def assert_nsm(self):
method cuda_no_collision_mask (line 185) | def cuda_no_collision_mask(self) -> str:
method cuda_ncm (line 189) | def cuda_ncm(self) -> str:
method kernel_no_collision_mask (line 193) | def kernel_no_collision_mask(self) -> str:
method kernel_ncm (line 197) | def kernel_ncm(self) -> str:
method cuda_no_streaming_mask (line 201) | def cuda_no_streaming_mask(self) -> str:
method cuda_nsm (line 205) | def cuda_nsm(self) -> str:
method kernel_no_streaming_mask (line 209) | def kernel_no_streaming_mask(self) -> str:
method kernel_nsm (line 214) | def kernel_nsm(self) -> str:
method cuda_f (line 218) | def cuda_f(self) -> str:
method kernel_f (line 222) | def kernel_f(self) -> str:
method kernel_stream_offset (line 227) | def kernel_stream_offset(self, q: int) -> str:
method f_reg (line 233) | def f_reg(self, q: int) -> str:
method kernel_rho (line 257) | def kernel_rho(self) -> str:
method kernel_rho_inv (line 261) | def kernel_rho_inv(self) -> str:
method kernel_u (line 265) | def kernel_u(self, d: int) -> str:
method cuda_f_next (line 277) | def cuda_f_next(self) -> str:
method kernel_f_next (line 281) | def kernel_f_next(self) -> str:
method generate (line 285) | def generate(self):
FILE: lettuce/cuda_native/_generator.py
class Generator (line 18) | class Generator(DefaultCodeGeneration):
method __init__ (line 21) | def __init__(self,
method version (line 33) | def version(self):
method name (line 37) | def name(self):
method generate (line 46) | def generate(self) -> Dict[str, str]:
method format (line 54) | def format(self, generate_dir: Optional[str] = None) -> str:
method _resolve (line 86) | def _resolve(self):
method resolve (line 99) | def resolve(self, install: bool = True):
method install (line 112) | def install(directory: str):
FILE: lettuce/cuda_native/_registry.py
class Parameter (line 9) | class Parameter:
method __str__ (line 13) | def __str__(self):
class RegistryList (line 17) | class RegistryList(list):
method __init__ (line 21) | def __init__(self, dimensions: int):
method registered (line 26) | def registered(self, guard: Optional[Hashable] = None, cond: bool = Tr...
method register (line 37) | def register(self, guard: Optional[Hashable] = None, cond: bool = True...
method append (line 49) | def append(self, item: Any, guard: Optional[Hashable] = None, cond: bo...
method extend (line 53) | def extend(self, other, guard: Optional[Hashable] = None, cond: bool =...
method __str__ (line 57) | def __str__(self):
class CodeRegistryList (line 61) | class CodeRegistryList(RegistryList):
method mutable (line 62) | def mutable(self, variable_type: str, variable: str, value: str) -> str:
method variable (line 66) | def variable(self, variable_type: str, variable: str, value: str) -> str:
method __str__ (line 70) | def __str__(self):
class ParameterRegistryList (line 74) | class ParameterRegistryList(RegistryList):
method __str__ (line 75) | def __str__(self):
class Registry (line 79) | class Registry:
method __init__ (line 82) | def __init__(self, d: int):
method cuda_hook (line 95) | def cuda_hook(self, py_value: str, cuda_param: Parameter, cond: bool =...
method kernel_hook (line 100) | def kernel_hook(self, cuda_value: str, kernel_param: Parameter, cond: ...
method python_pre (line 106) | def python_pre(self) -> CodeRegistryList:
method python_post (line 110) | def python_post(self) -> CodeRegistryList:
method cuda (line 114) | def cuda(self) -> CodeRegistryList:
method pipes (line 118) | def pipes(self) -> CodeRegistryList:
method pipe (line 122) | def pipe(self) -> CodeRegistryList:
method joined_buffer (line 125) | def joined_buffer(self) -> Dict[str, str]:
FILE: lettuce/cuda_native/_transformer.py
class NativeTransformer (line 14) | class NativeTransformer(ABC):
method __init__ (line 17) | def __init__(self, index: int):
method create (line 22) | def create(index: int):
method generate (line 26) | def generate(self, reg: 'Registry'):
class NativeBoundary (line 30) | class NativeBoundary(NativeTransformer, ABC):
class NativeEquilibrium (line 34) | class NativeEquilibrium(ABC):
method f_eq (line 36) | def f_eq(self, reg: 'Registry', q: int, rho: Optional[str] = None, u: ...
class NativeCollision (line 40) | class NativeCollision(NativeTransformer, ABC):
FILE: lettuce/cuda_native/_util.py
function lettuce_hash (line 6) | def lettuce_hash(value: Union[str, List[str]]) -> str:
FILE: lettuce/cuda_native/ext/_boundary/bounce_back_boundary.py
class NativeBounceBackBoundary (line 6) | class NativeBounceBackBoundary(NativeBoundary):
method __init__ (line 8) | def __init__(self, index):
method create (line 12) | def create(index):
method generate (line 15) | def generate(self, reg: 'DefaultCodeGeneration'):
FILE: lettuce/cuda_native/ext/_boundary/equilibrium_pu.py
class NativeEquilibriumBoundaryPu (line 6) | class NativeEquilibriumBoundaryPu(NativeBoundary):
method __init__ (line 8) | def __init__(self, index):
method create (line 12) | def create(index):
method cuda_velocity (line 15) | def cuda_velocity(self, reg: 'DefaultCodeGeneration'):
method cuda_velocity_size (line 20) | def cuda_velocity_size(self, reg: 'DefaultCodeGeneration', d: int):
method kernel_velocity_size (line 26) | def kernel_velocity_size(self, reg: 'DefaultCodeGeneration', d: int):
method kernel_velocity (line 31) | def kernel_velocity(self, reg: 'DefaultCodeGeneration', d: int):
method cuda_density (line 55) | def cuda_density(self, reg: 'DefaultCodeGeneration'):
method cuda_density_size (line 60) | def cuda_density_size(self, reg: 'DefaultCodeGeneration', d: int):
method kernel_density_size (line 66) | def kernel_density_size(self, reg: 'DefaultCodeGeneration', d: int):
method kernel_density (line 71) | def kernel_density(self, reg: 'DefaultCodeGeneration'):
method generate (line 89) | def generate(self, reg: 'DefaultCodeGeneration'):
FILE: lettuce/cuda_native/ext/_boundary/no_boundary.py
class NativeNoBoundary (line 6) | class NativeNoBoundary(NativeBoundary):
method __init__ (line 7) | def __init__(self, index):
method create (line 11) | def create(index):
method generate (line 14) | def generate(self, generator: 'Generator'):
FILE: lettuce/cuda_native/ext/_collision/bgk_collision.py
class NativeBGKCollision (line 9) | class NativeBGKCollision(NativeCollision):
method __init__ (line 11) | def __init__(self, index: int, force: Optional['NativeForce'] = None):
method create (line 16) | def create(index: int, force: Optional['NativeForce'] = None):
method cuda_tau_inv (line 21) | def cuda_tau_inv(self, reg: 'DefaultCodeGeneration'):
method kernel_tau_inv (line 25) | def kernel_tau_inv(self, reg: 'DefaultCodeGeneration'):
method generate (line 29) | def generate(self, reg: 'DefaultCodeGeneration'):
FILE: lettuce/cuda_native/ext/_collision/no_collision.py
class NativeNoCollision (line 8) | class NativeNoCollision(NativeCollision):
method create (line 11) | def create(index: int, force: None = None):
method generate (line 15) | def generate(self, _):
FILE: lettuce/cuda_native/ext/_equilibrium/quadratic_equilibrium.py
class NativeQuadraticEquilibrium (line 8) | class NativeQuadraticEquilibrium(NativeEquilibrium):
method uxu (line 11) | def uxu(self, reg: 'DefaultCodeGeneration', u: [str] = None) -> str:
method exu (line 19) | def exu(self, reg: 'DefaultCodeGeneration', q: int, u: [str] = None) -...
method cs_pow_two (line 27) | def cs_pow_two(self, _) -> str:
method two_cs_pow_two (line 31) | def two_cs_pow_two(self, _) -> str:
method f_eq (line 34) | def f_eq(self, reg: 'DefaultCodeGeneration', q: int, rho: str = None, ...
FILE: lettuce/cuda_native/ext/_force/_force.py
class NativeForce (line 1) | class NativeForce:
FILE: lettuce/ext/_boundary/anti_bounce_back_outlet.py
class AntiBounceBackOutlet (line 13) | class AntiBounceBackOutlet(Boundary):
method __init__ (line 22) | def __init__(self, direction: [List[int]], flow: 'Flow',
method __call__ (line 71) | def __call__(self, flow: 'Flow'):
method make_no_streaming_mask (line 93) | def make_no_streaming_mask(self, f_shape, context: 'Context'):
method make_no_collision_mask (line 100) | def make_no_collision_mask(self, shape: List[int], context: 'Context'):
method native_available (line 105) | def native_available(self) -> bool:
method native_generator (line 108) | def native_generator(self, index: int) -> 'NativeBoundary':
FILE: lettuce/ext/_boundary/bounce_back_boundary.py
class BounceBackBoundary (line 10) | class BounceBackBoundary(Boundary):
method __init__ (line 13) | def __init__(self, mask: torch.Tensor):
method __call__ (line 17) | def __call__(self, flow: 'Flow'):
method make_no_streaming_mask (line 20) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
method make_no_collision_mask (line 24) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
method native_available (line 28) | def native_available(self) -> bool:
method native_generator (line 31) | def native_generator(self, index: int) -> 'NativeBoundary':
FILE: lettuce/ext/_boundary/equilibrium_boundary_pu.py
class EquilibriumBoundaryPU (line 15) | class EquilibriumBoundaryPU(Boundary):
method checked_tensor (line 24) | def checked_tensor(t: Union[torch.Tensor, np.ndarray, list, tuple, num...
method __init__ (line 71) | def __init__(self, context: 'Context', flow: 'Flow', mask, velocity, p...
method __call__ (line 79) | def __call__(self, flow: 'Flow'):
method make_no_collision_mask (line 86) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
method make_no_streaming_mask (line 90) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
method native_available (line 94) | def native_available(self) -> bool:
method native_generator (line 97) | def native_generator(self, index: int) -> 'NativeBoundary':
FILE: lettuce/ext/_boundary/equilibrium_outlet_p.py
class EquilibriumOutletP (line 12) | class EquilibriumOutletP(AntiBounceBackOutlet):
method __init__ (line 16) | def __init__(self, direction: List[int], flow: 'Flow',
method __call__ (line 63) | def __call__(self, flow: 'Flow'):
method make_no_streaming_mask (line 75) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
method make_no_collision_mask (line 82) | def make_no_collision_mask(self, shape: List[int], context: 'Context'):
method native_available (line 87) | def native_available(self) -> bool:
method native_generator (line 90) | def native_generator(self, index: int):
FILE: lettuce/ext/_boundary/partially_saturated_boundary.py
class PartiallySaturatedBC (line 6) | class PartiallySaturatedBC(Boundary):
method __init__ (line 15) | def __init__(self, mask: torch.Tensor, tau: float, saturation: float):
method __call__ (line 22) | def __call__(self, flow: 'Flow'):
method make_no_collision_mask (line 39) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
method make_no_streaming_mask (line 43) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
method native_available (line 47) | def native_available(self) -> bool:
method native_generator (line 50) | def native_generator(self, index: int) -> 'NativeBoundary':
FILE: lettuce/ext/_collision/bgk_collision.py
class BGKCollision (line 12) | class BGKCollision(Collision):
method __init__ (line 13) | def __init__(self, tau, force: Optional['Force'] = None):
method __call__ (line 17) | def __call__(self, flow: 'Flow') -> torch.Tensor:
method name (line 24) | def name(self) -> str:
method native_available (line 29) | def native_available(self) -> bool:
method native_generator (line 32) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_collision/kbc_collision.py
class KBCCollision (line 11) | class KBCCollision(Collision):
method __init__ (line 17) | def __init__(self, tau: float = None):
method kbc_moment_transform (line 22) | def kbc_moment_transform(self, f):
method kbc_moment_transform_3d (line 25) | def kbc_moment_transform_3d(self, f):
method kbc_moment_transform_2d (line 33) | def kbc_moment_transform_2d(self, f):
method compute_s_seq_from_m (line 41) | def compute_s_seq_from_m(self, f, m):
method compute_s_seq_from_m_3d (line 44) | def compute_s_seq_from_m_3d(self, f, m):
method compute_s_seq_from_m_2d (line 76) | def compute_s_seq_from_m_2d(self, f, m):
method __call__ (line 96) | def __call__(self, flow: 'Flow') -> torch.Tensor:
method native_available (line 162) | def native_available(self) -> bool:
method native_generator (line 165) | def native_generator(self, index: int) -> 'NativeCollision':
class KBCCollision2D (line 169) | class KBCCollision2D(KBCCollision):
method __init__ (line 170) | def __init__(self, tau: float = None):
class KBCCollision3D (line 176) | class KBCCollision3D(KBCCollision):
method __init__ (line 177) | def __init__(self, tau: float = None):
FILE: lettuce/ext/_collision/mrt_collision.py
class MRTCollision (line 8) | class MRTCollision(Collision):
method __init__ (line 17) | def __init__(self, transform: 'Transform', relaxation_parameters: list,
method __call__ (line 23) | def __call__(self, flow: 'Flow'):
method native_available (line 31) | def native_available(self) -> bool:
method native_generator (line 34) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_collision/no_collision.py
class NoCollision (line 9) | class NoCollision(Collision):
method __call__ (line 10) | def __call__(self, flow: 'Flow') -> torch.Tensor:
method native_available (line 13) | def native_available(self) -> bool:
method native_generator (line 16) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_collision/regularized_collision.py
class RegularizedCollision (line 8) | class RegularizedCollision(Collision):
method __init__ (line 13) | def __init__(self, tau: float = None):
method __call__ (line 17) | def __call__(self, flow: 'Flow'):
method native_available (line 46) | def native_available(self) -> bool:
method native_generator (line 49) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_collision/smagorinsky_collision.py
class SmagorinskyCollision (line 9) | class SmagorinskyCollision(Collision):
method __init__ (line 14) | def __init__(self, tau, smagorinsky_constant=0.17, force: 'Force' = No...
method __call__ (line 21) | def __call__(self, flow: 'Flow'):
method native_available (line 40) | def native_available(self) -> bool:
method native_generator (line 43) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_collision/trt_collision.py
class TRTCollision (line 6) | class TRTCollision(Collision):
method __init__ (line 12) | def __init__(self, tau, tau_minus=1.0):
method __call__ (line 16) | def __call__(self, flow: 'Flow'):
method native_available (line 29) | def native_available(self) -> bool:
method native_generator (line 32) | def native_generator(self, index: int) -> 'NativeCollision':
FILE: lettuce/ext/_equilibrium/incompressible_quadratic_equilibrium.py
class IncompressibleQuadraticEquilibrium (line 8) | class IncompressibleQuadraticEquilibrium(Equilibrium):
method __init__ (line 9) | def __init__(self, rho0=1.0):
method __call__ (line 12) | def __call__(self, flow: 'Flow', rho=None, u=None):
FILE: lettuce/ext/_equilibrium/quadratic_equilibrium.py
class QuadraticEquilibrium (line 10) | class QuadraticEquilibrium(Equilibrium):
method __call__ (line 11) | def __call__(self, flow: 'Flow', rho=None, u=None):
method native_available (line 26) | def native_available(self) -> bool:
method native_generator (line 29) | def native_generator(self) -> 'NativeEquilibrium':
FILE: lettuce/ext/_equilibrium/quadratic_equilibrium_less_memory.py
class QuadraticEquilibriumLessMemory (line 8) | class QuadraticEquilibriumLessMemory(Equilibrium):
method __call__ (line 14) | def __call__(self, flow: 'Flow', rho=None, u=None):
method native_available (line 31) | def native_available(self) -> bool:
method native_generator (line 34) | def native_generator(self) -> 'NativeEquilibrium':
FILE: lettuce/ext/_flows/_ext_flow.py
class ExtFlow (line 8) | class ExtFlow(Flow, ABC):
method __init__ (line 16) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 35) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 40) | def make_units(self, reynolds_number, mach_number, resolution: List[int]
FILE: lettuce/ext/_flows/couette.py
class CouetteFlow2D (line 16) | class CouetteFlow2D(ExtFlow):
method __init__ (line 18) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 26) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 33) | def make_units(self, reynolds_number, mach_number, resolution: List[int]
method analytic_solution (line 43) | def analytic_solution(self):
method initial_pu (line 49) | def initial_pu(self):
method grid (line 56) | def grid(self):
method post_boundaries (line 64) | def post_boundaries(self):
FILE: lettuce/ext/_flows/decayingturbulence.py
class DecayingTurbulence (line 23) | class DecayingTurbulence(ExtFlow):
method __init__ (line 25) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 47) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 54) | def make_units(self, reynolds_number, mach_number, resolution
method analytic_solution (line 64) | def analytic_solution(self, x, t=0):
method _generate_wavenumbers (line 67) | def _generate_wavenumbers(self):
method _generate_spectrum (line 78) | def _generate_spectrum(self):
method _generate_initial_velocity (line 88) | def _generate_initial_velocity(self, ek, wavenumber):
method _compute_initial_pressure (line 157) | def _compute_initial_pressure(self):
method initial_pu (line 162) | def initial_pu(self):
method energy_spectrum (line 173) | def energy_spectrum(self):
method grid (line 177) | def grid(self) -> (torch.Tensor, ...):
method post_boundaries (line 188) | def post_boundaries(self) -> List['Boundary']:
FILE: lettuce/ext/_flows/doublyshear.py
class DoublyPeriodicShear2D (line 19) | class DoublyPeriodicShear2D(ExtFlow):
method __init__ (line 21) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 35) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 43) | def make_units(self, reynolds_number, mach_number,
method analytic_solution (line 51) | def analytic_solution(self, t=0):
method initial_pu (line 54) | def initial_pu(self) -> (float, Union[np.array, torch.Tensor]):
method grid (line 68) | def grid(self) -> (torch.Tensor, torch.Tensor):
method post_boundaries (line 79) | def post_boundaries(self):
FILE: lettuce/ext/_flows/lamboseenvortex.py
class LambOseenVortex2D (line 19) | class LambOseenVortex2D(ExtFlow):
method __init__ (line 20) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 50) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 58) | def make_units(self, reynolds_number, mach_number,
method grid (line 67) | def grid(self):
method initial_pu (line 75) | def initial_pu(self) -> (torch.Tensor, torch.Tensor):
method initial_lamboseenvortex (line 79) | def initial_lamboseenvortex(self) -> (torch.Tensor, torch.Tensor):
method post_boundaries (line 133) | def post_boundaries(self) -> List['Boundary']:
FILE: lettuce/ext/_flows/liddrivencavity.py
class Cavity2D (line 14) | class Cavity2D(ExtFlow):
method __init__ (line 16) | def __init__(self, context: 'Context', resolution, reynolds_number,
method make_resolution (line 20) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 28) | def make_units(self, reynolds_number, mach_number,
method initial_pu (line 36) | def initial_pu(self):
method grid (line 41) | def grid(self) -> (torch.Tensor, torch.Tensor):
method post_boundaries (line 52) | def post_boundaries(self):
FILE: lettuce/ext/_flows/obstacle.py
class Obstacle (line 16) | class Obstacle(ExtFlow):
method __init__ (line 54) | def __init__(self, context: Context, resolution: Union[int, List[int]],
method make_units (line 67) | def make_units(self, reynolds_number, mach_number, resolution: List[int]
method make_resolution (line 76) | def make_resolution(self, resolution: Union[int, List[int]],
method mask (line 84) | def mask(self):
method mask (line 88) | def mask(self, m):
method initial_pu (line 94) | def initial_pu(self) -> (float, Union[np.array, torch.Tensor]):
method grid (line 102) | def grid(self):
method post_boundaries (line 108) | def post_boundaries(self):
method _unit_vector (line 124) | def _unit_vector(self, i=0):
function Obstacle2D (line 128) | def Obstacle2D(context: 'Context', resolution: Union[int, List[int]],
function Obstacle3D (line 141) | def Obstacle3D(context: 'Context', resolution: Union[int, List[int]],
FILE: lettuce/ext/_flows/poiseuille.py
class PoiseuilleFlow2D (line 18) | class PoiseuilleFlow2D(ExtFlow):
method __init__ (line 20) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method analytic_solution (line 30) | def analytic_solution(self, t=0) -> (torch.Tensor, torch.Tensor):
method initial_pu (line 42) | def initial_pu(self):
method make_units (line 51) | def make_units(self, reynolds_number, mach_number,
method make_resolution (line 60) | def make_resolution(self, resolution: Union[int, List[int]],
method grid (line 69) | def grid(self):
method post_boundaries (line 78) | def post_boundaries(self):
method acceleration (line 85) | def acceleration(self):
FILE: lettuce/ext/_flows/taylorgreen.py
class TaylorGreenVortex (line 16) | class TaylorGreenVortex(ExtFlow):
method __init__ (line 17) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 33) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 43) | def make_units(self, reynolds_number, mach_number,
method grid (line 53) | def grid(self):
method initial_pu (line 63) | def initial_pu(self) -> (torch.Tensor, torch.Tensor):
method analytic_solution (line 66) | def analytic_solution(self, t: float) -> (torch.Tensor, torch.Tensor):
method post_boundaries (line 97) | def post_boundaries(self) -> List['Boundary']:
function TaylorGreenVortex3D (line 101) | def TaylorGreenVortex3D(context: 'Context', resolution: Union[int, List[...
function TaylorGreenVortex2D (line 113) | def TaylorGreenVortex2D(context: 'Context', resolution: Union[int, List[...
FILE: lettuce/ext/_force/_force.py
class Force (line 6) | class Force(ABC):
method __init__ (line 8) | def __init__(self, flow: 'Flow', tau, acceleration):
method source_term (line 12) | def source_term(self, u):
method u_eq (line 16) | def u_eq(self, flow: 'Flow'):
method ueq_scaling_factor (line 21) | def ueq_scaling_factor(self):
method native_available (line 25) | def native_available(self) -> bool:
method native_generator (line 29) | def native_generator(self) -> 'NativeForce':
FILE: lettuce/ext/_force/guo.py
class Guo (line 9) | class Guo(Force):
method __init__ (line 11) | def __init__(self, flow, tau, acceleration):
method source_term (line 16) | def source_term(self, u):
method u_eq (line 29) | def u_eq(self, flow: 'Flow' = None):
method ueq_scaling_factor (line 36) | def ueq_scaling_factor(self):
method native_available (line 39) | def native_available(self) -> bool:
method native_generator (line 42) | def native_generator(self) -> 'NativeForce':
FILE: lettuce/ext/_force/shan_chen.py
class ShanChen (line 7) | class ShanChen(Force):
method __init__ (line 9) | def __init__(self, flow, tau, acceleration):
method source_term (line 13) | def source_term(self, u):
method u_eq (line 16) | def u_eq(self, flow: 'Flow'):
method ueq_scaling_factor (line 22) | def ueq_scaling_factor(self):
method native_available (line 25) | def native_available(self) -> bool:
method native_generator (line 28) | def native_generator(self) -> 'NativeForce':
FILE: lettuce/ext/_reporter/error_reporter.py
class ErrorReporter (line 9) | class ErrorReporter(Reporter):
method __init__ (line 12) | def __init__(self, analytical_solution, interval=1, out=sys.stdout):
method __call__ (line 19) | def __call__(self, simulation: 'Simulation'):
FILE: lettuce/ext/_reporter/failure_reporter.py
class FailureReporterBase (line 12) | class FailureReporterBase(Reporter, ABC):
method __init__ (line 25) | def __init__(self, interval: int, k: int = 100, outdir: Optional[str]=...
method __call__ (line 34) | def __call__(self, simulation: 'BreakableSimulation'):
method _get_top_failures (line 57) | def _get_top_failures(self, mask: torch.Tensor, values: torch.Tensor) ...
method _write_log (line 78) | def _write_log(self, simulation: 'BreakableSimulation', results: List[...
method save_vtk (line 99) | def save_vtk(self, simulation: 'BreakableSimulation'):
method locations_string (line 116) | def locations_string(self, simulation: 'BreakableSimulation') -> List[...
method is_failed (line 120) | def is_failed(self, simulation: 'BreakableSimulation') -> torch.Tensor:
method get_results (line 125) | def get_results(self, simulation: 'BreakableSimulation') -> List[Tuple]:
class NaNReporter (line 131) | class NaNReporter(FailureReporterBase):
method __init__ (line 133) | def __init__(self, interval: int, k: int =100, outdir: Optional[str]=N...
method is_failed (line 138) | def is_failed(self, simulation: 'BreakableSimulation') -> torch.Tensor:
method get_results (line 141) | def get_results(self, simulation: 'BreakableSimulation') -> List[Tuple]:
method locations_string (line 145) | def locations_string(self, simulation: 'BreakableSimulation') -> List[...
class HighMaReporter (line 156) | class HighMaReporter(FailureReporterBase):
method __init__ (line 157) | def __init__(self, interval: int, threshold: float =0.3, k: int =100,
method is_failed (line 164) | def is_failed(self, simulation: 'BreakableSimulation') -> torch.Tensor:
method get_results (line 169) | def get_results(self, simulation: 'BreakableSimulation') -> List[Tuple]:
method locations_string (line 175) | def locations_string(self, simulation: 'BreakableSimulation') -> List[...
FILE: lettuce/ext/_reporter/observable_reporter.py
class Observable (line 17) | class Observable(ABC):
method __init__ (line 18) | def __init__(self, flow: 'Flow'):
method __call__ (line 23) | def __call__(self, f: Optional[torch.Tensor] = None):
class MaximumVelocity (line 27) | class MaximumVelocity(Observable):
method __call__ (line 30) | def __call__(self, f: Optional[torch.Tensor] = None):
class IncompressibleKineticEnergy (line 34) | class IncompressibleKineticEnergy(Observable):
method __call__ (line 37) | def __call__(self, f: Optional[torch.Tensor] = None):
class Enstrophy (line 45) | class Enstrophy(Observable):
method __call__ (line 53) | def __call__(self, f: Optional[torch.Tensor] = None):
class EnergySpectrum (line 71) | class EnergySpectrum(Observable):
method __init__ (line 74) | def __init__(self, flow: Flow):
method __call__ (line 99) | def __call__(self, f: Optional[torch.Tensor] = None):
method spectrum_from_u (line 103) | def spectrum_from_u(self, u):
method _ekin_spectrum (line 110) | def _ekin_spectrum(self, u):
method _ekin_spectrum_torch_lt_18 (line 119) | def _ekin_spectrum_torch_lt_18(self, u):
method _ekin_spectrum_torch_ge_18 (line 131) | def _ekin_spectrum_torch_ge_18(self, u):
class Mass (line 140) | class Mass(Observable):
method __init__ (line 150) | def __init__(self, flow: Flow, no_mass_mask=None):
method __call__ (line 154) | def __call__(self, f: Optional[torch.Tensor] = None):
class ObservableReporter (line 161) | class ObservableReporter(Reporter):
method __init__ (line 177) | def __init__(self, observable, interval=1, out=sys.stdout):
method __call__ (line 185) | def __call__(self, simulation: 'Simulation'):
FILE: lettuce/ext/_reporter/progress_reporter.py
function append_txt_file (line 6) | def append_txt_file(filename, line: str):
class ProgressReporter (line 12) | class ProgressReporter(Reporter):
method __init__ (line 30) | def __init__(self, interval=1000, t_max=0, i_target=0, i_start=0,
method __call__ (line 55) | def __call__(self, simulation: 'Simulation'):
method start_timer (line 110) | def start_timer(self):
FILE: lettuce/ext/_reporter/vtk_reporter.py
function write_vtk (line 10) | def write_vtk(point_dict, id=0, filename_base="./data/output"):
class VTKReporter (line 18) | class VTKReporter(Reporter):
method __init__ (line 21) | def __init__(self, interval=50, filename_base="./data/output"):
method __call__ (line 29) | def __call__(self, simulation: 'Simulation'):
method output_mask (line 49) | def output_mask(self, simulation: 'Simulation'):
FILE: lettuce/ext/_reporter/write_image.py
function write_image (line 4) | def write_image(filename, array2d):
FILE: lettuce/ext/_stencil/d1q3.py
class D1Q3 (line 6) | class D1Q3(Stencil):
method __init__ (line 7) | def __init__(self):
FILE: lettuce/ext/_stencil/d2q9.py
class D2Q9 (line 6) | class D2Q9(Stencil):
method __init__ (line 7) | def __init__(self):
FILE: lettuce/ext/_stencil/d3q15.py
class D3Q15 (line 6) | class D3Q15(Stencil):
method __init__ (line 7) | def __init__(self):
FILE: lettuce/ext/_stencil/d3q19.py
class D3Q19 (line 6) | class D3Q19(Stencil):
method __init__ (line 7) | def __init__(self):
FILE: lettuce/ext/_stencil/d3q27.py
class D3Q27 (line 6) | class D3Q27(Stencil):
method __init__ (line 7) | def __init__(self):
FILE: lettuce/util/datautils.py
class HDF5Reporter (line 17) | class HDF5Reporter(Reporter):
method __init__ (line 49) | def __init__(self, flow, collision, interval, filebase='./output', met...
method __call__ (line 66) | def __call__(self, simulation: 'Simulation'): # i, t, f):
method _pickle_to_h5 (line 76) | def _pickle_to_h5(instance):
class LettuceDataset (line 83) | class LettuceDataset(data.Dataset):
method __init__ (line 112) | def __init__(self, filebase, transform=None, target=False, skip_idx_to...
method __str__ (line 123) | def __str__(self):
method __len__ (line 131) | def __len__(self):
method __getitem__ (line 134) | def __getitem__(self, idx):
method __del__ (line 145) | def __del__(self):
method get_data (line 148) | def get_data(self, idx):
method get_attr (line 151) | def get_attr(self, attr):
method _unpickle_from_h5 (line 155) | def _unpickle_from_h5(byte_str):
FILE: lettuce/util/moments.py
function moment_tensor (line 34) | def moment_tensor(e: List[List[int]], multiindex):
function get_default_moment_transform (line 41) | def get_default_moment_transform(stencil: 'Stencil', context: 'Context'):
class Moments (line 51) | class Moments:
method __init__ (line 52) | def __init__(self, lattice):
class Transform (line 60) | class Transform:
method __init__ (line 65) | def __init__(self, stencil: 'Stencil', context: 'Context', names=None):
method __getitem__ (line 71) | def __getitem__(self, moment_names):
method transform (line 76) | def transform(self, f):
method inverse_transform (line 79) | def inverse_transform(self, m):
method equilibrium (line 82) | def equilibrium(self, m: torch.Tensor, flow: 'Flow'):
method einsum (line 96) | def einsum(self, equation, fields, *args) -> torch.Tensor:
method mv (line 112) | def mv(self, m, v) -> torch.Tensor:
class D1Q3Transform (line 117) | class D1Q3Transform(Transform):
method __init__ (line 131) | def __init__(self, stencil: 'Stencil', context: 'Context'):
method transform (line 136) | def transform(self, f):
method inverse_transform (line 139) | def inverse_transform(self, m):
class D2Q9Dellar (line 147) | class D2Q9Dellar(Transform):
method __init__ (line 177) | def __init__(self, stencil: 'Stencil', context: 'Context'):
method transform (line 182) | def transform(self, f):
method inverse_transform (line 185) | def inverse_transform(self, m):
method equilibrium (line 188) | def equilibrium(self, m, flow: 'Flow'):
class D2Q9Lallemand (line 207) | class D2Q9Lallemand(Transform):
method __init__ (line 233) | def __init__(self, stencil: 'Stencil', context: 'Context'):
method transform (line 238) | def transform(self, f):
method inverse_transform (line 241) | def inverse_transform(self, m):
method equilibrium (line 244) | def equilibrium(self, m, flow: 'Flow'):
class D3Q27Hermite (line 369) | class D3Q27Hermite(Transform):
method __init__ (line 535) | def __init__(self, stencil: 'Stencil', context: 'Context'):
method transform (line 540) | def transform(self, f):
method inverse_transform (line 543) | def inverse_transform(self, m):
method equilibrium (line 546) | def equilibrium(self, m, flow: 'Flow'):
FILE: lettuce/util/utility.py
function get_subclasses (line 15) | def get_subclasses(cls, module):
class LettuceException (line 21) | class LettuceException(Exception):
class LettuceWarning (line 25) | class LettuceWarning(UserWarning):
class InefficientCodeWarning (line 29) | class InefficientCodeWarning(LettuceWarning):
class ExperimentalWarning (line 33) | class ExperimentalWarning(LettuceWarning):
function torch_gradient (line 37) | def torch_gradient(f, dx=1, order=2):
function grid_fine_to_coarse (line 102) | def grid_fine_to_coarse(flow: 'Flow', f_fine, tau_fine, tau_coarse):
function torch_jacobi (line 119) | def torch_jacobi(f, p, dx, dim, tol_abs=1e-10, max_num_steps=100000):
function append_axes (line 159) | def append_axes(array, n):
FILE: tests/boundary/test_antibounceback_outlet_bc.py
function test_anti_bounce_back_outlet (line 6) | def test_anti_bounce_back_outlet(fix_configuration, fix_stencil):
FILE: tests/boundary/test_bc_masks.py
function test_masks (line 4) | def test_masks(fix_configuration):
FILE: tests/boundary/test_bounceback_bc.py
function test_bounce_back_boundary (line 6) | def test_bounce_back_boundary(fix_stencil, fix_configuration):
function test_bounce_back_boundary_not_applied_if_mask_empty (line 22) | def test_bounce_back_boundary_not_applied_if_mask_empty(fix_stencil,
FILE: tests/boundary/test_equilibrium_bc_outlet_p.py
function test_equilibrium_outlet_p_algorithm (line 6) | def test_equilibrium_outlet_p_algorithm(fix_stencil, fix_configuration):
FILE: tests/boundary/test_equilibrium_bc_pu.py
function moment_dims_params (line 4) | def moment_dims_params():
function moment_dims_ids (line 11) | def moment_dims_ids():
function fix_stencil_x_moment_dims (line 20) | def fix_stencil_x_moment_dims(request):
class DummyEquilibriumBoundary (line 24) | class DummyEquilibriumBoundary(EquilibriumBoundaryPU):
method make_no_streaming_mask (line 32) | def make_no_streaming_mask(self, shape: List[int], context: 'Context')...
function test_equilibrium_boundary_pu_algorithm (line 37) | def test_equilibrium_boundary_pu_algorithm(fix_stencil, fix_configuration):
function test_equilibrium_boundary_pu_tgv (line 84) | def test_equilibrium_boundary_pu_tgv(fix_stencil, fix_configuration):
function test_equilibrium_boundary_pu_native (line 125) | def test_equilibrium_boundary_pu_native(fix_stencil_x_moment_dims, fix_d...
FILE: tests/boundary/test_equilibrium_pressure_outlet.py
function test_equilibrium_pressure_outlet (line 4) | def test_equilibrium_pressure_outlet(fix_configuration, fix_stencil):
FILE: tests/boundary/test_partiallysaturated_bc.py
function test_partiallysaturated_boundary (line 6) | def test_partiallysaturated_boundary(fix_stencil, fix_configuration):
function test_fullysaturated_like_neq_bounceback (line 24) | def test_fullysaturated_like_neq_bounceback(fix_stencil, fix_configurati...
function test_partiallysaturated_boundary_not_applied_if_mask_empty (line 55) | def test_partiallysaturated_boundary_not_applied_if_mask_empty(fix_stencil,
FILE: tests/collision/test_collision_conserves_mass.py
function test_collision_conserves_mass (line 4) | def test_collision_conserves_mass(fix_conserving_collision,
FILE: tests/collision/test_collision_conserves_momentum.py
function test_collision_conserves_momentum (line 4) | def test_collision_conserves_momentum(fix_conserving_collision,
FILE: tests/collision/test_collision_fixpoint_2x.py
function test_collision_fixpoint_2x (line 5) | def test_collision_fixpoint_2x(Collision,
FILE: tests/collision/test_collision_fixpoint_2x_MRT.py
function test_collision_fixpoint_2x_MRT (line 6) | def test_collision_fixpoint_2x_MRT(Transform, fix_configuration):
FILE: tests/collision/test_collision_optimizes_pseudo_entropy.py
function test_collision_optimizes_pseudo_entropy (line 4) | def test_collision_optimizes_pseudo_entropy(fix_configuration,
FILE: tests/collision/test_collision_relaxes_shear_moments.py
function test_collision_relaxes_shear_moments (line 7) | def test_collision_relaxes_shear_moments(Collision,
FILE: tests/collision/test_force.py
function test_force (line 6) | def test_force(ForceType, fix_device):
FILE: tests/conftest.py
function dtype_params (line 10) | def dtype_params():
function dtype_ids (line 14) | def dtype_ids():
function stencil1d_params (line 18) | def stencil1d_params():
function stencil2d_params (line 22) | def stencil2d_params():
function stencil3d_params (line 26) | def stencil3d_params():
function stencil_params (line 30) | def stencil_params():
function stencil1d_ids (line 34) | def stencil1d_ids():
function stencil2d_ids (line 38) | def stencil2d_ids():
function stencil3d_ids (line 42) | def stencil3d_ids():
function stencil_ids (line 46) | def stencil_ids():
function device_params (line 50) | def device_params():
function device_ids (line 54) | def device_ids():
function native_params (line 58) | def native_params():
function native_ids (line 62) | def native_ids():
function configuration_params (line 66) | def configuration_params():
function configuration_ids (line 74) | def configuration_ids():
function transform_params (line 87) | def transform_params():
function transform_ids (line 103) | def transform_ids():
function fix_transform (line 108) | def fix_transform(request):
function fix_collision (line 116) | def fix_collision(request):
function conserving_collision_params (line 120) | def conserving_collision_params():
function conserving_collision_ids (line 130) | def conserving_collision_ids():
function fix_dtype (line 141) | def fix_dtype(request):
function fix_stencil1d (line 146) | def fix_stencil1d(request):
function fix_stencil2d (line 151) | def fix_stencil2d(request):
function fix_stencil3d (line 156) | def fix_stencil3d(request):
function fix_stencil (line 161) | def fix_stencil(request):
function fix_device (line 166) | def fix_device(request):
function fix_native (line 174) | def fix_native(request):
function fix_configuration (line 182) | def fix_configuration(request):
function fix_conserving_collision (line 191) | def fix_conserving_collision(request):
class TestFlow (line 195) | class TestFlow(ExtFlow):
method __init__ (line 198) | def __init__(self, context: 'Context', resolution: Union[int, List[int]],
method make_resolution (line 206) | def make_resolution(self, resolution: List[int],
method make_units (line 216) | def make_units(self, reynolds_number, mach_number,
method initial_pu (line 221) | def initial_pu(self) -> (float, Union[np.array, torch.Tensor]):
method boundaries (line 227) | def boundaries(self) -> List['Boundary']:
method boundaries (line 231) | def boundaries(self, boundaries: List['Boundary']):
function DummyTGV (line 235) | def DummyTGV(context: 'Context', resolution: Union[int, List[int]],
class DummyFlow (line 243) | class DummyFlow(ExtFlow):
method __init__ (line 245) | def __init__(self, context: Context, resolution: int = 16):
method make_resolution (line 248) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 253) | def make_units(self, reynolds_number, mach_number, _: List[int]
method initial_pu (line 258) | def initial_pu(self) -> (float, List[float]):
method initialize (line 261) | def initialize(self):
method boundaries (line 265) | def boundaries(self) -> List['Boundary']:
FILE: tests/flow/test_divergence.py
function test_divergence (line 5) | def test_divergence(stencil2d3d, fix_configuration):
FILE: tests/flow/test_einsum.py
class EinsumFlow (line 5) | class EinsumFlow(TestFlow):
method __init__ (line 6) | def __init__(self, context, res):
method j (line 11) | def j(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method incompressible_energy (line 16) | def incompressible_energy(self, f: Optional[torch.Tensor] = None
method entropy (line 22) | def entropy(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method pseudo_entropy_global (line 29) | def pseudo_entropy_global(self, f: Optional[torch.Tensor] = None
method pseudo_entropy_local (line 36) | def pseudo_entropy_local(self, f: Optional[torch.Tensor] = None
method shear_tensor (line 44) | def shear_tensor(self, f: Optional[torch.Tensor] = None) -> torch.Tensor:
method einsum (line 52) | def einsum(self, equation, fields, *args) -> torch.Tensor:
function initialize_f_neq_floweinsum (line 68) | def initialize_f_neq_floweinsum(flow: 'EinsumFlow'):
function initialize_f_neq_torcheinsum (line 97) | def initialize_f_neq_torcheinsum(flow: 'Flow'):
class RegularizedEinsum (line 126) | class RegularizedEinsum(RegularizedCollision):
method __call__ (line 127) | def __call__(self, flow: 'Flow'):
class GuoEinsum (line 156) | class GuoEinsum(Guo):
method source_term (line 157) | def source_term(self, u):
function test_einsum (line 172) | def test_einsum(fix_dim):
FILE: tests/flow/test_flow.py
function test_flow (line 5) | def test_flow(flowname, fix_configuration):
FILE: tests/flow/test_initialize_fneq.py
function test_initialize_fneq (line 10) | def test_initialize_fneq(fix_configuration, fix_stencil, Case):
FILE: tests/flow/test_initialize_pressure.py
function test_initialize_pressure (line 5) | def test_initialize_pressure(fix_dtype):
FILE: tests/flow/test_obstacle.py
function test_obstacle (line 5) | def test_obstacle(stencil2d3d, fix_configuration):
FILE: tests/flow/test_pressure_poisson.py
function test_pressure_poisson (line 6) | def test_pressure_poisson(fix_configuration, Stencil):
FILE: tests/moments/test_conserved_moments_d2q9.py
function test_conserved_moments_d2q9 (line 6) | def test_conserved_moments_d2q9(MomentSet):
FILE: tests/moments/test_getitem.py
function test_getitem (line 4) | def test_getitem(fix_device, fix_dtype):
FILE: tests/moments/test_inverse_transform.py
function test_inverse_transform (line 4) | def test_inverse_transform(fix_transform):
FILE: tests/moments/test_moment_equilibrium_D3Q27Hermite.py
function test_moment_equilibrium_D3Q27Hermite (line 4) | def test_moment_equilibrium_D3Q27Hermite(fix_device, fix_dtype):
FILE: tests/moments/test_moment_equilibrium_dellar.py
function test_moment_equilibrium_dellar (line 4) | def test_moment_equilibrium_dellar(fix_device, fix_dtype):
FILE: tests/moments/test_moment_equilibrium_lallemand.py
function test_moment_equilibrium_lallemand (line 4) | def test_moment_equilibrium_lallemand(fix_device, fix_dtype):
FILE: tests/moments/test_moments_density.py
function test_moments_density_array (line 5) | def test_moments_density_array(fix_stencil):
function test_more_moments_density_array (line 10) | def test_more_moments_density_array(fix_stencil):
function test_moments_density_tensor (line 15) | def test_moments_density_tensor(fix_stencil, fix_device):
function test_more_moments_density_tensor (line 25) | def test_more_moments_density_tensor(fix_stencil, fix_device):
FILE: tests/moments/test_orthogonality.py
function test_orthogonality (line 4) | def test_orthogonality(fix_device, fix_dtype, fix_transform):
FILE: tests/native/test_native_bgk_collision.py
class DummyBGK (line 9) | class DummyBGK(ExtFlow):
method __init__ (line 10) | def __init__(self, context: Context):
method make_resolution (line 13) | def make_resolution(self, resolution: Union[int, List[int]],
method make_units (line 18) | def make_units(self, reynolds_number, mach_number, _: List[int]
method initial_pu (line 23) | def initial_pu(self) -> (float, List[float]):
method initialize (line 26) | def initialize(self):
method boundaries (line 31) | def boundaries(self) -> List['Boundary']:
function test_native_bgk_collision (line 35) | def test_native_bgk_collision():
FILE: tests/native/test_native_bounce_back.py
class MyBounceBackBoundary (line 11) | class MyBounceBackBoundary(BounceBackBoundary):
method make_no_collision_mask (line 12) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
class DummyBBBC (line 22) | class DummyBBBC(DummyFlow):
method initialize (line 24) | def initialize(self):
method boundaries (line 29) | def boundaries(self) -> List['Boundary']:
function test_native_bounce_back (line 33) | def test_native_bounce_back():
FILE: tests/native/test_native_equilibrium_pu.py
class my_equilibrium_boundary_mask (line 12) | class my_equilibrium_boundary_mask(EquilibriumBoundaryPU):
method make_no_collision_mask (line 14) | def make_no_collision_mask(self, shape: List[int], context: 'Context'
method make_no_streaming_mask (line 21) | def make_no_streaming_mask(self, shape: List[int], context: 'Context'
function test_equilibrium_boundary_pu_native (line 27) | def test_equilibrium_boundary_pu_native():
FILE: tests/native/test_native_no_streaming_mask.py
function test_native_no_streaming_mask (line 4) | def test_native_no_streaming_mask():
FILE: tests/native/test_native_streaming.py
class DummyStreaming (line 9) | class DummyStreaming(DummyFlow):
method initialize (line 11) | def initialize(self):
function test_native_streaming (line 24) | def test_native_streaming():
FILE: tests/native/test_native_streaming_strategy.py
function test_native_streaming_strategy (line 11) | def test_native_streaming_strategy(streaming_strategy):
FILE: tests/reporter/test_HDF5Reporter.py
function test_HDF5Reporter (line 5) | def test_HDF5Reporter(tmpdir):
FILE: tests/reporter/test_energy_spectrum.py
function test_energy_spectrum (line 5) | def test_energy_spectrum(tmpdir, flowname):
FILE: tests/reporter/test_generic_reporters.py
function test_generic_reporters (line 10) | def test_generic_reporters(Observable, Case, fix_configuration):
FILE: tests/reporter/test_high_ma_reporter.py
function test_high_ma_reporter (line 5) | def test_high_ma_reporter(tmpdir):
FILE: tests/reporter/test_nan_reporter.py
function test_nan_reporter (line 5) | def test_nan_reporter(tmpdir):
FILE: tests/reporter/test_vtk_reporter_mask.py
function test_vtk_reporter_mask (line 6) | def test_vtk_reporter_mask(tmpdir):
FILE: tests/reporter/test_vtk_reporter_no_mask.py
function test_vtk_reporter_no_mask (line 5) | def test_vtk_reporter_no_mask(tmpdir):
FILE: tests/reporter/test_write_image.py
function test_write_image (line 5) | def test_write_image(tmpdir):
FILE: tests/reporter/test_write_vtk.py
function test_write_vtk (line 6) | def test_write_vtk(tmpdir):
FILE: tests/stencil/test_first_zero.py
function test_first_zero (line 4) | def test_first_zero(fix_stencil):
FILE: tests/stencil/test_opposite.py
function test_opposite (line 3) | def test_opposite(fix_stencil):
FILE: tests/stencil/test_symmetry.py
function test_symmetry (line 4) | def test_symmetry(fix_stencil):
FILE: tests/stencil/test_weights.py
function test_weights (line 4) | def test_weights(fix_stencil):
FILE: tests/test_checkpoint.py
function test_checkpoint (line 5) | def test_checkpoint(tmpdir):
FILE: tests/test_cli.py
function response (line 14) | def response():
function test_content (line 23) | def test_content(response):
function test_command_line_interface (line 29) | def test_command_line_interface():
FILE: tests/test_equilibrium.py
function test_equilibrium_conserves_mass (line 5) | def test_equilibrium_conserves_mass(fix_equilibrium,
function test_equilibrium_conserves_momentum (line 24) | def test_equilibrium_conserves_momentum(fix_equilibrium,
FILE: tests/unit/__init__.py
function create_default_unit_conversion (line 4) | def create_default_unit_conversion():
FILE: tests/unit/test_consistency.py
function test_consistency (line 5) | def test_consistency():
FILE: tests/unit/test_conversion_reversible.py
function test_conversion_reversible (line 5) | def test_conversion_reversible():
FILE: tests/unit/test_reynolds_number_consistent.py
function test_reynolds_number_consistent (line 5) | def test_reynolds_number_consistent():
FILE: tests/util/test_grid_fine_to_coarse.py
function test_grid_fine_to_coarse (line 5) | def test_grid_fine_to_coarse(dims):
FILE: tests/util/test_torch_gradient.py
function test_torch_gradient (line 6) | def test_torch_gradient(dims, order):
FILE: versioneer.py
class VersioneerConfig (line 293) | class VersioneerConfig:
function get_root (line 297) | def get_root():
function get_config_from_root (line 336) | def get_config_from_root(root):
class NotThisMethod (line 364) | class NotThisMethod(Exception):
function register_vcs_handler (line 373) | def register_vcs_handler(vcs, method): # decorator
function run_command (line 382) | def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
function git_get_keywords (line 1065) | def git_get_keywords(versionfile_abs):
function git_versions_from_keywords (line 1093) | def git_versions_from_keywords(keywords, tag_prefix, verbose):
function git_pieces_from_vcs (line 1157) | def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command):
function do_vcs_install (line 1285) | def do_vcs_install(manifest_in, versionfile_source, ipy):
function versions_from_parentdir (line 1322) | def versions_from_parentdir(parentdir_prefix, root, verbose):
function versions_from_file (line 1364) | def versions_from_file(filename):
function write_to_version_file (line 1381) | def write_to_version_file(filename, versions):
function plus_or_dot (line 1392) | def plus_or_dot(pieces):
function render_pep440 (line 1399) | def render_pep440(pieces):
function render_pep440_branch (line 1424) | def render_pep440_branch(pieces):
function pep440_split_post (line 1454) | def pep440_split_post(ver):
function render_pep440_pre (line 1464) | def render_pep440_pre(pieces):
function render_pep440_post (line 1488) | def render_pep440_post(pieces):
function render_pep440_post_branch (line 1515) | def render_pep440_post_branch(pieces):
function render_pep440_old (line 1544) | def render_pep440_old(pieces):
function render_git_describe (line 1566) | def render_git_describe(pieces):
function render_git_describe_long (line 1586) | def render_git_describe_long(pieces):
function render (line 1606) | def render(pieces, style):
class VersioneerBadRootError (line 1642) | class VersioneerBadRootError(Exception):
function get_versions (line 1646) | def get_versions(verbose=False):
function get_version (line 1722) | def get_version():
function get_cmdclass (line 1727) | def get_cmdclass(cmdclass=None):
function do_setup (line 1978) | def do_setup():
function scan_setup_py (line 2066) | def scan_setup_py():
Condensed preview — 256 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,098K chars).
[
{
"path": ".codeclimate.yml",
"chars": 294,
"preview": "exclude_patterns:\n - \"versioneer.py\"\n - \"lettuce/_version.py\"\n - \"config/\"\n - \"db/\"\n - \"dist/\"\n - \"fea"
},
{
"path": ".github/ISSUE_TEMPLATE/BUG_REPORT.yml",
"chars": 1422,
"preview": "name: Bug Report\ndescription: File a bug report.\ntitle: \"[Bug]: \"\nlabels: [\"bug\"]\nassignees: []\nbody:\n - type: markdown"
},
{
"path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml",
"chars": 1814,
"preview": "name: \"Feature Request\"\ndescription: Suggest an idea for improving lettuce\ntitle: \"[Feature]: \"\nlabels: [\"enhancement\"]\n"
},
{
"path": ".github/pull_request_template.md",
"chars": 512,
"preview": "## Description\n\n<!-- Add a description of the changes -->\n\n## Checklist\n\n - [ ] This pull request is associated to an is"
},
{
"path": ".github/workflows/CI.yml",
"chars": 1632,
"preview": "name: CI\n\non:\n push:\n branches:\n - \"master\"\n pull_request:\n branches:\n - \"**\"\n schedule:\n\n - cron:"
},
{
"path": ".gitignore",
"chars": 1239,
"preview": "Makefile\n.idea/\n.gitattributes\n.editorconfig\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n"
},
{
"path": ".readthedocs.yaml",
"chars": 813,
"preview": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html f"
},
{
"path": "AUTHORS.rst",
"chars": 193,
"preview": "=======\nCredits\n=======\n\nDevelopment Lead\n----------------\n\n* Andreas Kraemer <kraemer.research@gmail.com>\n\nContributors"
},
{
"path": "LICENSE",
"chars": 1074,
"preview": "MIT License\n\nCopyright (c) 2019, Andreas Kraemer\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.rst",
"chars": 5258,
"preview": ".. image:: https://raw.githubusercontent.com/lettucecfd/lettuce/master/.source/img/logo_lettuce_typo.png\n\n.. image:: htt"
},
{
"path": "docs/README.md",
"chars": 160,
"preview": "# Building the docs locally\n\n```\nconda install -c conda-forge \\\n sphinx \\\n sphinxcontrib-napoleon \\\n numpydoc \\"
},
{
"path": "docs/authors.rst",
"chars": 28,
"preview": ".. include:: ../AUTHORS.rst\n"
},
{
"path": "docs/conf.py",
"chars": 4834,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# lettuce documentation build configuration file, created by\n# sphinx-qu"
},
{
"path": "docs/contributing.rst",
"chars": 33,
"preview": ".. include:: ../CONTRIBUTING.rst\n"
},
{
"path": "docs/history.rst",
"chars": 28,
"preview": ".. include:: ../HISTORY.rst\n"
},
{
"path": "docs/index.rst",
"chars": 304,
"preview": "Welcome to lettuce's documentation!\n======================================\n\n.. toctree::\n :maxdepth: 2\n :caption: Co"
},
{
"path": "docs/installation.rst",
"chars": 645,
"preview": ".. highlight:: shell\n\n============\nInstallation\n============\n\n\nFrom sources\n------------\n\nThe sources for lettuce can be"
},
{
"path": "docs/make.bat",
"chars": 769,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=python -m"
},
{
"path": "docs/modules.rst",
"chars": 2240,
"preview": "API\n===\n\nSimulation\n----------\n.. automodule:: lettuce.simulation\n :noindex:\n :members:\n :undoc-members:\n :s"
},
{
"path": "docs/readme.rst",
"chars": 27,
"preview": ".. include:: ../README.rst\n"
},
{
"path": "docs/usage.rst",
"chars": 69,
"preview": "=====\nUsage\n=====\n\nTo use lettuce in a project::\n\n import lettuce\n"
},
{
"path": "examples/00_simplest_TGV.py",
"chars": 569,
"preview": "\"\"\"\nThis file showcases the simplicity of the lettuce code.\nThe following code will run a two-dimensional Taylor-Green v"
},
{
"path": "examples/01a_first_example_TGV.ipynb",
"chars": 119800,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# A first example\\n\",\n \"This is "
},
{
"path": "examples/01b_first_example_obstacle.py",
"chars": 3166,
"preview": "import torch\nimport lettuce as lt\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\"\"\"\nContext definitions.\n\nThe cont"
},
{
"path": "examples/02_converging_obstacle_flow.py",
"chars": 2331,
"preview": "import lettuce as lt\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport torch\n\n\"\"\"\nFor descriptions of the initia"
},
{
"path": "examples/03_outputs_TGV.py",
"chars": 2730,
"preview": "import lettuce as lt\nimport torch\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nprint(\"start\")\n\n# ---------- Set u"
},
{
"path": "examples/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_flows/FailingTGVandObstacle.py",
"chars": 1829,
"preview": "\"\"\"\nThis file showcases:\n a) interrupting a TGV simulation using a reporter that detects NaN in f\n b) interrupting an ob"
},
{
"path": "examples/advanced_flows/LidDrivenCavity.ipynb",
"chars": 241812,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Lid-driven cavity flow example\\n\""
},
{
"path": "examples/advanced_flows/MixingLayer.ipynb",
"chars": 77877,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Example: Mixing Layer\\n\",\n \"\\n"
},
{
"path": "examples/advanced_flows/PartiallySaturatedObstacle.py",
"chars": 5347,
"preview": "import torch\nimport os\nfrom matplotlib import pyplot as plt\nfrom matplotlib.colors import colorConverter, LinearSegmente"
},
{
"path": "examples/advanced_flows/PorousMedium.ipynb",
"chars": 87260,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"33addcd4\",\n \"metadata\": {},\n \"source\": [\n \"# Implementati"
},
{
"path": "examples/advanced_projects/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/00_run_parametrized_project.ipynb",
"chars": 1584879,
"preview": "{\n \"cells\": [\n {\n \"metadata\": {},\n \"cell_type\": \"markdown\",\n \"source\": [\n \"## ADVANCED PROJECT: CYLINDER FLOW\\"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/01_script_cylinder_simulation.py",
"chars": 47357,
"preview": "\n\"\"\"\n This script contains the code to run the efficient bounce back project with\n the circular cylinder obstacle."
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/__init__.py",
"chars": 691,
"preview": "from examples.advanced_projects.efficient_bounce_back_obstacle.boundary.solid_boundary_data import SolidBoundaryData\nfro"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/auxiliary_code/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/auxiliary_code/data_processing_and_plotting.py",
"chars": 45843,
"preview": "\"\"\"\n THIS FILE CONTAINS THE UTILITIES TO PROCESS AND PLOT THE REPORTED DATA FROM\n THE CYLINDER OBSTACLE SIMULATIO"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/auxiliary_code/helperCode.py",
"chars": 609,
"preview": "import os\nimport sys\n\n\nclass Logger(object):\n \"\"\"logging functionality proposed by P.Spelten to log stdout to file\"\"\""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/boundary/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/boundary/fullway_bounce_back_boundary.py",
"chars": 10462,
"preview": "import torch\nimport numpy as np\n\nfrom typing import List, Optional\nfrom lettuce import Boundary, Flow, Context\n\n__all__ "
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/boundary/halfway_bounce_back_boundary.py",
"chars": 14050,
"preview": "import torch\nimport numpy as np\n\nfrom typing import List, Optional\nfrom lettuce import Boundary, Flow, Context\nfrom soli"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/boundary/linear_interpolated_bounce_back_boundary.py",
"chars": 12075,
"preview": "import torch\n\nfrom typing import List, Optional\nfrom lettuce import Boundary, Flow, Context\nfrom solid_boundary_data imp"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/boundary/solid_boundary_data.py",
"chars": 464,
"preview": "import numpy as np\n\n__all__ = ['SolidBoundaryData']\n\n# index lists for Bounce Back Boundaries: populations for FWBB, HWB"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/flow/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/flow/obstacle_cylinder.py",
"chars": 31683,
"preview": "from typing import Union, List, Optional\n\nimport numpy as np\nimport torch\n\nfrom lettuce.ext._flows import ExtFlow\nfrom l"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos1_DI2018.csv",
"chars": 2570,
"preview": "-2.984375000000001; 1.0574712643678161\n-2.890625000000001; 1.0651340996168583\n-2.718750000000001; 1.0689655172413794\n-2."
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos1_KM2000.csv",
"chars": 4919,
"preview": "-2.984375000000001; 1.0613026819923372\n-2.9179687500000013; 1.0613026819923372\n-2.8515625000000013; 1.0613026819923372\n-"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos1_LS1993.csv",
"chars": 1586,
"preview": "-1.5976562500000009; 1.1226053639846745\n-1.5156250000000009; 1.1302681992337165\n-1.4375000000000004; 1.1379310344827587\n"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos1_WR2008.csv",
"chars": 3872,
"preview": "-2.960937500000001; 1.0727969348659006\n-2.882812500000001; 1.0727969348659006\n-2.800781250000001; 1.0766283524904217\n-2."
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos2_DI2018.csv",
"chars": 1976,
"preview": "-3.000000000000001; 0.05363984674329503\n-2.828125000000001; 0.06130268199233724\n-2.625000000000001; 0.06896551724137945\n"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos2_KM2000.csv",
"chars": 4735,
"preview": "-2.984375000000001; 0.05363984674329503\n-2.917968750000001; 0.05747126436781613\n-2.855468750000001; 0.06130268199233724\n"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos2_LS1993.csv",
"chars": 1622,
"preview": "-1.5937500000000004; 0.09961685823754785\n-1.5156250000000004; 0.11111111111111116\n-1.4375000000000004; 0.111111111111111"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos2_WR2008.csv",
"chars": 3677,
"preview": "-2.964843750000001; 0.06513409961685834\n-2.886718750000001; 0.06896551724137945\n-2.808593750000001; 0.06513409961685834\n"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos3_DI2018.csv",
"chars": 1891,
"preview": "-2.992187500000001; -0.9540229885057472\n-2.742187500000001; -0.946360153256705\n-2.445312500000001; -0.9425287356321839\n-"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos3_KM2000.csv",
"chars": 4154,
"preview": "-2.976562500000001; -0.9501915708812261\n-2.910156250000001; -0.946360153256705\n-2.839843750000001; -0.946360153256705\n-2"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos3_LS1993.csv",
"chars": 1606,
"preview": "-1.5937500000000004; -0.9501915708812261\n-1.5234375000000004; -0.9348659003831421\n-1.4414062500000009; -0.93486590038314"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig09_ux_profile_pos3_WR2008.csv",
"chars": 3198,
"preview": "-2.960937500000001; -0.946360153256705\n-2.875000000000001; -0.9501915708812261\n-2.792968750000001; -0.9501915708812261\n-"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos1_DI2018.csv",
"chars": 2095,
"preview": "-2.9924242424242395; -3.3306690738754696e-16\n-2.6666666666666643; 0\n-2.3636363636363615; 0.006016847172081841\n-1.9772727"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos1_KM2000.csv",
"chars": 3966,
"preview": "-2.9772727272727244; 0.0030084235860406983\n-2.9128787878787854; 0.009025270758122761\n-2.848484848484846; 0.0120336943441"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos1_LS1993.csv",
"chars": 1669,
"preview": "-1.5946969696969684; -0.11432009626955486\n-1.5189393939393936; -0.1203369434416367\n-1.4393939393939386; -0.1083032490974"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos1_WR2008.csv",
"chars": 3314,
"preview": "-2.950757575757573; 0.01504211793020449\n-2.86742424242424; 0.0180505415162453\n-2.7840909090909065; 0.02105896510228622\n-"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos2_DI2018.csv",
"chars": 1730,
"preview": "-2.9999999999999973; -0.9867629362214198\n-2.7348484848484826; -0.9837545126353789\n-2.340909090909089; -0.974729241877256"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos2_KM2000.csv",
"chars": 3790,
"preview": "-2.9469696969696946; -0.9807460890493381\n-2.848484848484846; -0.9807460890493381\n-2.780303030303028; -0.9807460890493381"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos2_LS1993.csv",
"chars": 1657,
"preview": "-1.5946969696969684; -1.0469314079422385\n-1.5189393939393927; -1.0288808664259927\n-1.4431818181818175; -1.01383874849578"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos2_WR2008.csv",
"chars": 3137,
"preview": "-2.9431818181818157; -0.9807460890493381\n-2.848484848484846; -0.9807460890493381\n-2.765151515151513; -0.9747292418772563"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos3_DI2018.csv",
"chars": 1387,
"preview": "-2.9999999999999973; -1.9825511432009622\n-2.651515151515149; -1.9735258724428397\n-2.21212121212121; -1.9584837545126357\n"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos3_KM2000.csv",
"chars": 3766,
"preview": "-2.969696969696967; -1.9885679903730442\n-2.9015151515151487; -1.985559566787003\n-2.8371212121212093; -1.9825511432009626"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos3_LS1993.csv",
"chars": 1653,
"preview": "-1.5984848484848473; -2.0758122743682312\n-1.5189393939393927; -2.0758122743682303\n-1.4356060606060597; -2.06979542719614"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig10_uy_profile_pos3_WR2008.csv",
"chars": 3055,
"preview": "-2.9431818181818157; -1.9825511432009626\n-2.859848484848482; -1.9735258724428397\n-2.776515151515149; -1.9735258724428397"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos1_DI2018.csv",
"chars": 1816,
"preview": "-2.996129032258067; 0\n-1.0374193548387107; 0.001626016260162566\n-0.8361290322580657; 0.004878048780487809\n-0.75096774193"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos1_KM2000.csv",
"chars": 3820,
"preview": "-2.9767741935483896; -1.1102230246251565e-16\n-2.9148387096774218; 0\n-2.845161290322583; -1.1102230246251565e-16\n-2.77935"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos1_R2016.csv",
"chars": 2153,
"preview": "-2.9109677419354862; 0.001626016260162566\n-2.7832258064516155; -1.1102230246251565e-16\n-2.6477419354838734; -1.110223024"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos2_BM1994.csv",
"chars": 2596,
"preview": "-1.9509677419354858; -0.49918699186991866\n-1.858064516129034; -0.49918699186991866\n-1.7767741935483885; -0.4975609756097"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos2_DI2018.csv",
"chars": 1620,
"preview": "-3.0000000000000027; -0.5008130081300813\n-1.6412903225806468; -0.49918699186991866\n-1.3238709677419367; -0.4975609756097"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos2_KM2000.csv",
"chars": 3984,
"preview": "-2.9767741935483896; -0.5008130081300813\n-2.9109677419354862; -0.5008130081300813\n-2.845161290322583; -0.500813008130081"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos2_LS1993.csv",
"chars": 1653,
"preview": "-1.6064516129032271; -0.4829268292682928\n-1.5212903225806467; -0.48943089430894327\n-1.4400000000000013; -0.4878048780487"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos2_R2016.csv",
"chars": 2275,
"preview": "-2.945806451612906; -0.5008130081300813\n-2.8103225806451637; -0.49918699186991866\n-2.678709677419361; -0.500813008130081"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos3_DI2018.csv",
"chars": 1526,
"preview": "-3.0000000000000027; -1\n-1.7032258064516141; -1\n-1.5329032258064528; -0.9967479674796748\n-1.3238709677419367; -0.9934959"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos3_KM2000.csv",
"chars": 3495,
"preview": "-2.972903225806454; -1.0016260162601625\n-2.9070967741935507; -1.0032520325203254\n-2.841290322580648; -1.0032520325203254"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig11_uxux_profile_pos3_R2016.csv",
"chars": 2158,
"preview": "-2.9419354838709704; -1\n-2.810322580645164; -1\n-2.674838709677421; -1\n-2.53935483870968; -1\n-2.407741935483873; -1\n-2.26"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos1_DI2018.csv",
"chars": 1117,
"preview": "-2.9990238388820396; -0.00014687100894006377\n-1.1558775174681464; 0.0014495530012770264\n-0.9546513220989175; 0.003844189"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos1_R2016.csv",
"chars": 2818,
"preview": "-2.9540690505548715; 0.0014495530012769153\n-2.819204685573367; 0.0006513409961684813\n-2.6843403205918626; 0.001449553001"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos2_BM1994.csv",
"chars": 2215,
"preview": "-1.8708727222907249; -0.5006257982120053\n-1.802370187696945; -0.5006257982120053\n-1.7146013152486645; -0.499029374201788"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos2_DI2018.csv",
"chars": 1477,
"preview": "-2.9990238388820396; -0.4990293742017884\n-1.9479380737087275; -0.4990293742017884\n-1.2800383614193724; -0.49743295019157"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos2_LS1993.csv",
"chars": 1682,
"preview": "-1.6118475133579944; -0.49344189016602824\n-1.5326414577339365; -0.49184546615581115\n-1.4491539936977675; -0.490249042145"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos2_R2016.csv",
"chars": 2286,
"preview": "-2.932662008494315; -0.4974329501915713\n-2.799938347718866; -0.4974329501915713\n-2.6672146869434172; -0.4966347381864626"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos3_DI2018.csv",
"chars": 1458,
"preview": "-2.9968831346759837; -0.9987100893997449\n-2.037847650363064; -0.9979118773946365\n-1.5026715988491577; -0.995517241379310"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig12_uyuy_profile_pos3_R2016.csv",
"chars": 2444,
"preview": "-2.9283806000822037; -1.000306513409962\n-2.795656939306755; -1.000306513409962\n-2.6672146869434172; -1.000306513409962\n-"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos1_BM1994.csv",
"chars": 1079,
"preview": "-1.9596469104665823; 1.1102230246251565e-16\n-0.8171500630517023; 0\n-0.7225725094577546; 0.0031796502384738856\n-0.6658259"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos1_DI2018.csv",
"chars": 1274,
"preview": "-2.992433795712484; 1.1102230246251565e-16\n-0.8776796973518284; 0\n-0.7641866330390923; 0.0015898251192369983\n-0.71122320"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos1_R2016.csv",
"chars": 1352,
"preview": "-2.822194199243379; 1.1102230246251565e-16\n-0.9382093316519544; -0.0015898251192367763\n-0.8020176544766708; 0.0015898251"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos2_BM1994.csv",
"chars": 1412,
"preview": "-1.9445145018915508; -0.5007949125596184\n-0.9533417402269864; -0.5023847376788554\n-0.8701134930643128; -0.50238473767885"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos2_DI2018.csv",
"chars": 1019,
"preview": "-2.992433795712484; -0.4992050874403816\n-0.9079445145018914; -0.5007949125596184\n-0.8095838587641864; -0.500794912559618"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos2_LS1993.csv",
"chars": 1648,
"preview": "-1.600252206809584; -0.5007949125596184\n-1.5208070617906682; -0.5007949125596184\n-1.4451450189155106; -0.500794912559618"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos2_R2016.csv",
"chars": 1269,
"preview": "-2.9432534678436317; -0.5007949125596184\n-1.059268600252207; -0.5007949125596184\n-0.9306431273644384; -0.499205087440381"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos3_BM1994.csv",
"chars": 1611,
"preview": "-1.9445145018915508; -0.9999999999999999\n-1.2938209331651955; -0.9999999999999999\n-1.119798234552333; -0.998410174880762"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos3_DI2018.csv",
"chars": 1181,
"preview": "-2.992433795712484; -0.9999999999999999\n-1.2786885245901636; -0.9999999999999999\n-1.1954602774274905; -0.999999999999999"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/profile_reference_data/Fig13_uxuy_profile_pos3_R2016.csv",
"chars": 1541,
"preview": "-2.9432534678436317; -0.9999999999999999\n-1.592686002522068; -0.9999999999999999\n-1.4754098360655736; -0.999999999999999"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/reporter/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/reporter/observables_force_coefficients.py",
"chars": 4010,
"preview": "\"\"\"Observables: force coefficients calculated from the force on an obstacle\n - coefficient of drag\n - coefficient "
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/reporter/reporter_ProfileReporter.py",
"chars": 2135,
"preview": "import torch\nimport numpy as np\nimport os\n\nfrom typing import List\n\nfrom lettuce._simulation import Reporter, Simulation"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/reporter/reporter_advanced_vtk_reporter.py",
"chars": 12117,
"preview": "import os\nfrom typing import Optional, List\n\nimport numpy as np\nimport pyevtk.hl as vtk\nimport torch\n\nfrom lettuce._simu"
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/simulation/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "examples/advanced_projects/efficient_bounce_back_obstacle/simulation/ebb_simulation.py",
"chars": 4686,
"preview": "import torch\n\nfrom timeit import default_timer as timer\nfrom typing import List\n\nfrom lettuce._simulation import *\nfrom "
},
{
"path": "examples/development/.gitignore",
"chars": 133,
"preview": "# don't trak manually_generate_cuda_native.py output directory\ncuda_native\n\nnative_generated\nnative_generated_orig\nnativ"
},
{
"path": "examples/development/example_progress_reporter_based_on_simplest_TGV.py",
"chars": 833,
"preview": "\"\"\"\nThis file showcases the simplicity of the lettuce code.\nThe following code will run a two-dimensional Taylor-Green v"
},
{
"path": "examples/development/manually_generate_cuda_native.py",
"chars": 2204,
"preview": "import lettuce as lt\nfrom lettuce import cuda_native, StreamingStrategy\n\nfrom os.path import join, dirname, abspath, isd"
},
{
"path": "examples/simple_flows/Couette.ipynb",
"chars": 57461,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Couette flow example\\n\",\n \"Thi"
},
{
"path": "examples/simple_flows/DecayingTurbulence.ipynb",
"chars": 981528,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Example: Decaying Turbulence\"\n "
},
{
"path": "examples/simple_flows/LambOseenVortex.py",
"chars": 873,
"preview": "\"\"\"\nThis file showcases the simplicity of the lettuce code.\nThe following code will run a two-dimensional Taylor-Green v"
},
{
"path": "examples/simple_flows/Obstacle.ipynb",
"chars": 53556,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"id\": \"8275480f\",\n \"metadata\": {},\n \"source\": [\n \"## Grid refine"
},
{
"path": "examples/simple_flows/Poiseuille.ipynb",
"chars": 57858,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# Poiseuille flow example\\n\",\n \""
},
{
"path": "lettuce/__init__.py",
"chars": 398,
"preview": "\"\"\"Top-level package for lettuce.\"\"\"\n\n__author__ = 'Andreas Kraemer'\n__email__ = 'kraemer.research@gmail.com'\n\nimport le"
},
{
"path": "lettuce/_context.py",
"chars": 4847,
"preview": "from typing import List, Optional, Union\n\nimport numpy as np\nimport torch\n\n__all__ = ['Context']\n\n\nclass Context:\n de"
},
{
"path": "lettuce/_flow.py",
"chars": 12139,
"preview": "import pickle\n\nimport numpy as np\nimport torch\nimport warnings\n\nfrom typing import Optional, List, Union, Callable\nfrom "
},
{
"path": "lettuce/_simulation.py",
"chars": 13810,
"preview": "import warnings\n\nimport torch\nimport numpy as np\n\nfrom timeit import default_timer as timer\nfrom typing import List, Opt"
},
{
"path": "lettuce/_stencil.py",
"chars": 1184,
"preview": "from abc import ABC\nfrom typing import cast\nfrom functools import cached_property\nfrom typing import List, Literal\n\nimpo"
},
{
"path": "lettuce/_unit.py",
"chars": 5668,
"preview": "\"\"\"\nUnit conversion into lattice units and back.\n\nlu = lattice units\npu = physical units\n\"\"\"\n\nimport numpy as np\n\n__all_"
},
{
"path": "lettuce/_version.py",
"chars": 23185,
"preview": "# This file helps to compute a version number in source trees obtained from\n# git-archive tarball (such as those provide"
},
{
"path": "lettuce/base.py",
"chars": 1566,
"preview": "from typing import Optional\n\n\nclass LatticeBase:\n \"\"\"Class LatticeBase\n\n LatticeBase is the Base Class for all Lat"
},
{
"path": "lettuce/cli.py",
"chars": 7104,
"preview": "# -*- coding: utf-8 -*-\n\n\"\"\"Console script for lettuce.\nTo get help for terminal commands, open a console and type:\n\n>>>"
},
{
"path": "lettuce/cuda_native/__init__.py",
"chars": 190,
"preview": "from ._util import *\nfrom ._transformer import *\nfrom ._template import *\nfrom ._registry import *\nfrom ._default_code_g"
},
{
"path": "lettuce/cuda_native/_default_code_gen.py",
"chars": 11375,
"preview": "import json\nfrom enum import Enum\nfrom functools import lru_cache as cached\nfrom typing import Optional, cast\n\nfrom . im"
},
{
"path": "lettuce/cuda_native/_generator.py",
"chars": 4459,
"preview": "import importlib\nimport os\nimport os.path\nimport shutil\nimport site\nimport subprocess\nimport sys\nimport tempfile\nfrom fu"
},
{
"path": "lettuce/cuda_native/_registry.py",
"chars": 4151,
"preview": "from dataclasses import dataclass\nfrom functools import cached_property\nfrom typing import Dict, Set, Hashable, Optional"
},
{
"path": "lettuce/cuda_native/_template.py",
"chars": 2912,
"preview": "from typing import Dict\n\n__all__ = [\n 'template',\n]\n\ntemplate: Dict[str, str] = {\n\".clang-format\": \"\"\"\nBasedOnStyle: "
},
{
"path": "lettuce/cuda_native/_transformer.py",
"chars": 741,
"preview": "from abc import abstractmethod, ABC\nfrom typing import Optional, List\n\nfrom . import *\n\n__all__ = [\n 'NativeTransform"
},
{
"path": "lettuce/cuda_native/_util.py",
"chars": 209,
"preview": "from typing import Union, List\n\nimport mmh3\n\n\ndef lettuce_hash(value: Union[str, List[str]]) -> str:\n if isinstance(v"
},
{
"path": "lettuce/cuda_native/ext/__init__.py",
"chars": 79,
"preview": "from ._boundary import *\nfrom ._collision import *\nfrom ._equilibrium import *\n"
},
{
"path": "lettuce/cuda_native/ext/_boundary/__init__.py",
"chars": 263,
"preview": "from .bounce_back_boundary import NativeBounceBackBoundary\nfrom .equilibrium_pu import NativeEquilibriumBoundaryPu\nfrom "
},
{
"path": "lettuce/cuda_native/ext/_boundary/bounce_back_boundary.py",
"chars": 677,
"preview": "from ... import *\n\n__all__ = ['NativeBounceBackBoundary']\n\n\nclass NativeBounceBackBoundary(NativeBoundary):\n\n def __i"
},
{
"path": "lettuce/cuda_native/ext/_boundary/equilibrium_pu.py",
"chars": 4615,
"preview": "from ... import NativeBoundary, DefaultCodeGeneration, Parameter, CodeRegistryList\n\n__all__ = ['NativeEquilibriumBoundar"
},
{
"path": "lettuce/cuda_native/ext/_boundary/no_boundary.py",
"chars": 326,
"preview": "from ... import NativeBoundary\n\n__all__ = ['NativeNoBoundary']\n\n\nclass NativeNoBoundary(NativeBoundary):\n def __init_"
},
{
"path": "lettuce/cuda_native/ext/_collision/__init__.py",
"chars": 156,
"preview": "from .bgk_collision import NativeBGKCollision\nfrom .no_collision import NativeNoCollision\n\n__all__ = [\n 'NativeBGKCol"
},
{
"path": "lettuce/cuda_native/ext/_collision/bgk_collision.py",
"chars": 1231,
"preview": "from typing import Optional\n\nfrom lettuce.cuda_native import DefaultCodeGeneration, Parameter\nfrom ... import NativeColl"
},
{
"path": "lettuce/cuda_native/ext/_collision/no_collision.py",
"chars": 317,
"preview": "from typing import Optional\n\nfrom ... import NativeCollision\n\n__all__ = ['NativeNoCollision']\n\n\nclass NativeNoCollision("
},
{
"path": "lettuce/cuda_native/ext/_equilibrium/__init__.py",
"chars": 111,
"preview": "from .quadratic_equilibrium import NativeQuadraticEquilibrium\n\n__all__ = [\n 'NativeQuadraticEquilibrium',\n]\n"
},
{
"path": "lettuce/cuda_native/ext/_equilibrium/quadratic_equilibrium.py",
"chars": 2066,
"preview": "from lettuce.cuda_native import DefaultCodeGeneration\nfrom lettuce.cuda_native import NativeEquilibrium\nfrom lettuce.cud"
},
{
"path": "lettuce/cuda_native/ext/_force/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "lettuce/cuda_native/ext/_force/_force.py",
"chars": 28,
"preview": "class NativeForce:\n pass\n"
},
{
"path": "lettuce/ext/__init__.py",
"chars": 172,
"preview": "from ._stencil import *\nfrom ._equilibrium import *\nfrom ._force import *\nfrom ._collision import *\nfrom ._boundary impo"
},
{
"path": "lettuce/ext/_boundary/__init__.py",
"chars": 437,
"preview": "from .anti_bounce_back_outlet import AntiBounceBackOutlet\nfrom .bounce_back_boundary import BounceBackBoundary\nfrom .equ"
},
{
"path": "lettuce/ext/_boundary/anti_bounce_back_outlet.py",
"chars": 4462,
"preview": "from typing import List\n\nimport numpy as np\nimport torch\n\nfrom ... import Collision\nfrom .._collision import BGKCollisio"
},
{
"path": "lettuce/ext/_boundary/bounce_back_boundary.py",
"chars": 899,
"preview": "import torch\n\nfrom typing import List, Optional\nfrom ... import Boundary, Flow, Context\nfrom ...cuda_native.ext import N"
},
{
"path": "lettuce/ext/_boundary/equilibrium_boundary_pu.py",
"chars": 3886,
"preview": "import numbers\nfrom typing import List, Optional, Union\n\nimport numpy as np\nimport torch\n\nfrom ... import Boundary\nfrom "
},
{
"path": "lettuce/ext/_boundary/equilibrium_outlet_p.py",
"chars": 3474,
"preview": "from typing import List, Optional\n\nimport numpy as np\nimport torch\n\n__all__ = ['EquilibriumOutletP']\n\nfrom ... import Fl"
},
{
"path": "lettuce/ext/_boundary/partially_saturated_boundary.py",
"chars": 1832,
"preview": "from typing import List\nimport torch\nfrom ... import Boundary\n\n\nclass PartiallySaturatedBC(Boundary):\n \"\"\"\n Partia"
},
{
"path": "lettuce/ext/_collision/__init__.py",
"chars": 555,
"preview": "from .bgk_collision import BGKCollision\nfrom .kbc_collision import KBCCollision3D, KBCCollision2D, KBCCollision\nfrom .mr"
},
{
"path": "lettuce/ext/_collision/bgk_collision.py",
"chars": 1144,
"preview": "import torch\n\nfrom typing import Optional\n\nfrom ... import Flow, Collision\nfrom ...cuda_native.ext import NativeBGKColli"
},
{
"path": "lettuce/ext/_collision/kbc_collision.py",
"chars": 6064,
"preview": "import warnings\n\nimport torch\n\nfrom ... import Flow, Collision, TorchStencil\nfrom .. import D3Q27, D2Q9\n\n__all__ = ['KBC"
},
{
"path": "lettuce/ext/_collision/mrt_collision.py",
"chars": 1049,
"preview": "import torch\n\nfrom ... import Flow, Collision\n\n__all__ = ['MRTCollision']\n\n\nclass MRTCollision(Collision):\n \"\"\"\n M"
},
{
"path": "lettuce/ext/_collision/no_collision.py",
"chars": 397,
"preview": "import torch\n\nfrom ... import Flow, Collision\nfrom ...cuda_native.ext import NativeNoCollision\n\n__all__ = ['NoCollision'"
},
{
"path": "lettuce/ext/_collision/regularized_collision.py",
"chars": 1710,
"preview": "import torch\n\nfrom ... import Flow, Collision\n\n__all__ = ['RegularizedCollision']\n\n\nclass RegularizedCollision(Collision"
},
{
"path": "lettuce/ext/_collision/smagorinsky_collision.py",
"chars": 1375,
"preview": "import torch\n\nfrom ... import Flow, Collision\nfrom .. import Force\n\n__all__ = ['SmagorinskyCollision']\n\n\nclass Smagorins"
},
{
"path": "lettuce/ext/_collision/trt_collision.py",
"chars": 967,
"preview": "from ... import Flow, Collision\n\n__all__ = ['TRTCollision']\n\n\nclass TRTCollision(Collision):\n \"\"\"\n Two relaxation "
},
{
"path": "lettuce/ext/_equilibrium/__init__.py",
"chars": 341,
"preview": "from .incompressible_quadratic_equilibrium import IncompressibleQuadraticEquilibrium\nfrom .quadratic_equilibrium import "
},
{
"path": "lettuce/ext/_equilibrium/incompressible_quadratic_equilibrium.py",
"chars": 807,
"preview": "import torch\n\nfrom ... import Flow, Equilibrium\n\n__all__ = ['IncompressibleQuadraticEquilibrium']\n\n\nclass Incompressible"
},
{
"path": "lettuce/ext/_equilibrium/quadratic_equilibrium.py",
"chars": 1048,
"preview": "import torch\n\nfrom ... import Flow, Equilibrium\n\n__all__ = ['QuadraticEquilibrium']\n\nfrom ...cuda_native.ext import Nati"
},
{
"path": "lettuce/ext/_equilibrium/quadratic_equilibrium_less_memory.py",
"chars": 1082,
"preview": "import torch\n\nfrom ... import Flow, Equilibrium\n\n__all__ = ['QuadraticEquilibriumLessMemory']\n\n\nclass QuadraticEquilibri"
},
{
"path": "lettuce/ext/_flows/__init__.py",
"chars": 279,
"preview": "from ._ext_flow import *\n\nfrom .taylorgreen import *\nfrom .couette import *\nfrom .poiseuille import *\nfrom .doublyshear "
},
{
"path": "lettuce/ext/_flows/_ext_flow.py",
"chars": 1724,
"preview": "from abc import ABC, abstractmethod\nfrom typing import List, Optional, Union\n\nfrom .. import D1Q3, D2Q9, D3Q19, Quadrati"
},
{
"path": "lettuce/ext/_flows/_flow_by_name.py",
"chars": 721,
"preview": "from typing import Dict, Tuple, Type, AnyStr\n\nfrom ... import Stencil\nfrom .. import D2Q9, D3Q19, D3Q27\nfrom . import (E"
},
{
"path": "lettuce/ext/_flows/couette.py",
"chars": 2500,
"preview": "\"\"\"\nCouette Flow\n\"\"\"\nfrom typing import Union, List, Optional\n\nimport numpy as np\nimport torch\n\nfrom ... import UnitConv"
},
{
"path": "lettuce/ext/_flows/decayingturbulence.py",
"chars": 7793,
"preview": "\"\"\"\nDecayingTurbulence vortex in 2D and 3D. Dimension is set by the stencil.\nSpecial Inputs & standard value: wavenumber"
},
{
"path": "lettuce/ext/_flows/doublyshear.py",
"chars": 3005,
"preview": "\"\"\"\nDoubly shear layer in 2D.\nSpecial Inputs & standard value: shear_layer_width = 80,\ninitial_perturbation_magnitude = "
},
{
"path": "lettuce/ext/_flows/lamboseenvortex.py",
"chars": 5629,
"preview": "\"\"\"\nLamb-Oseen Vortex in 2D.\n\nThis module defines the `LambOseenVortex2D` class, which simulates a 2D Lamb-Oseen vortex\n"
},
{
"path": "lettuce/ext/_flows/liddrivencavity.py",
"chars": 2451,
"preview": "\"\"\"\nCavity flow\n\"\"\"\nfrom typing import List, Union, Optional\n\nimport numpy as np\nimport torch\n\nfrom ... import UnitConve"
},
{
"path": "lettuce/ext/_flows/obstacle.py",
"chars": 5717,
"preview": "import warnings\nfrom typing import Union, List, Optional\n\nimport numpy as np\nimport torch\n\nfrom . import ExtFlow\nfrom .."
},
{
"path": "lettuce/ext/_flows/poiseuille.py",
"chars": 3044,
"preview": "\"\"\"\nPoiseuille Flow\n\"\"\"\nfrom typing import Union, List, Optional\n\nimport numpy as np\nimport torch\n\nfrom . import ExtFlow"
},
{
"path": "lettuce/ext/_flows/taylorgreen.py",
"chars": 5251,
"preview": "\"\"\"\nTaylor-Green vortex in 2D and 3D.\n\"\"\"\nimport warnings\nfrom typing import Union, List, Optional\n\nimport torch\n\nfrom ."
},
{
"path": "lettuce/ext/_force/__init__.py",
"chars": 120,
"preview": "from ._force import *\nfrom .guo import *\nfrom .shan_chen import *\n\n__all__ = [\n 'Force',\n 'Guo',\n 'ShanChen'\n]\n"
},
{
"path": "lettuce/ext/_force/_force.py",
"chars": 532,
"preview": "from abc import ABC, abstractmethod\n\n__all__ = ['Force']\n\n\nclass Force(ABC):\n @abstractmethod\n def __init__(self, "
},
{
"path": "lettuce/ext/_force/guo.py",
"chars": 1411,
"preview": "import torch\n\nfrom . import Force\nfrom lettuce.util import append_axes\n\n__all__ = ['Guo']\n\n\nclass Guo(Force):\n\n def _"
},
{
"path": "lettuce/ext/_force/shan_chen.py",
"chars": 672,
"preview": "from . import Force\nfrom lettuce.util import append_axes\n\n__all__ = ['ShanChen']\n\n\nclass ShanChen(Force):\n\n def __ini"
},
{
"path": "lettuce/ext/_reporter/__init__.py",
"chars": 185,
"preview": "from .error_reporter import *\nfrom .observable_reporter import *\nfrom .vtk_reporter import *\nfrom .write_image import *\n"
},
{
"path": "lettuce/ext/_reporter/error_reporter.py",
"chars": 1556,
"preview": "import sys\nimport torch\n\nfrom ... import Reporter\n\n__all__ = ['ErrorReporter']\n\n\nclass ErrorReporter(Reporter):\n \"\"\"R"
},
{
"path": "lettuce/ext/_reporter/failure_reporter.py",
"chars": 7657,
"preview": "import torch\n\nimport os\nfrom typing import List, Tuple, Optional\nfrom abc import ABC, abstractmethod\n\nfrom ... import Re"
},
{
"path": "lettuce/ext/_reporter/observable_reporter.py",
"chars": 7142,
"preview": "import sys\nfrom abc import ABC, abstractmethod\nfrom typing import Optional\n\nimport torch\nimport numpy as np\n\nfrom ... im"
},
{
"path": "lettuce/ext/_reporter/progress_reporter.py",
"chars": 6360,
"preview": "import os\nimport datetime\nfrom timeit import default_timer as timer\nfrom lettuce import Reporter, Simulation\n\ndef append"
},
{
"path": "lettuce/ext/_reporter/vtk_reporter.py",
"chars": 2730,
"preview": "import numpy as np\nimport pyevtk.hl as vtk\nimport os\n\nfrom ... import Reporter\n\n__all__ = ['VTKReporter', 'write_vtk']\n\n"
},
{
"path": "lettuce/ext/_reporter/write_image.py",
"chars": 326,
"preview": "__all__ = ['write_image']\n\n\ndef write_image(filename, array2d):\n from matplotlib import pyplot as plt\n fig, ax = p"
},
{
"path": "lettuce/ext/_stencil/__init__.py",
"chars": 198,
"preview": "from .d1q3 import D1Q3\nfrom .d2q9 import D2Q9\nfrom .d3q15 import D3Q15\nfrom .d3q19 import D3Q19\nfrom .d3q27 import D3Q27"
},
{
"path": "lettuce/ext/_stencil/d1q3.py",
"chars": 210,
"preview": "from ... import Stencil\n\n__all__ = ['D1Q3']\n\n\nclass D1Q3(Stencil):\n def __init__(self):\n self.e = [[0], [1], ["
},
{
"path": "lettuce/ext/_stencil/d2q9.py",
"chars": 305,
"preview": "from ... import Stencil\n\n__all__ = ['D2Q9']\n\n\nclass D2Q9(Stencil):\n def __init__(self):\n self.e = [[0, 0], [1,"
},
{
"path": "lettuce/ext/_stencil/d3q15.py",
"chars": 468,
"preview": "from ... import Stencil\n\n__all__ = ['D3Q15']\n\n\nclass D3Q15(Stencil):\n def __init__(self):\n self.e = [[0, 0, 0]"
},
{
"path": "lettuce/ext/_stencil/d3q19.py",
"chars": 548,
"preview": "from ... import Stencil\n\n__all__ = ['D3Q19']\n\n\nclass D3Q19(Stencil):\n def __init__(self):\n self.e = [[0, 0, 0]"
},
{
"path": "lettuce/ext/_stencil/d3q27.py",
"chars": 683,
"preview": "from ... import Stencil\n\n__all__ = ['D3Q27']\n\n\nclass D3Q27(Stencil):\n def __init__(self):\n self.e = [[0, 0, 0]"
},
{
"path": "lettuce/util/__init__.py",
"chars": 642,
"preview": "'''\nUtility functions.\n'''\n\nfrom .utility import *\n# not importing moments due to cyclic import issue\n# from .moments im"
},
{
"path": "lettuce/util/datautils.py",
"chars": 5523,
"preview": "\"\"\"\ndatautils for writing/reading hdf5 files.\n\"\"\"\n\nimport h5py\nfrom torch.utils import data\nfrom lettuce._version import"
},
{
"path": "lettuce/util/moments.py",
"chars": 26339,
"preview": "\"\"\"\nMoments and cumulants of the distribution function.\n\"\"\"\n\nimport warnings\nfrom typing import List\n\nimport torch\nfrom "
},
{
"path": "lettuce/util/utility.py",
"chars": 6482,
"preview": "import inspect as _inspect\nimport torch as _torch\n\n__all__ = ['get_subclasses',\n 'LettuceException',\n "
},
{
"path": "native_cuda_synopsis.md",
"chars": 1319,
"preview": "The native-cuda update introduced some major updates to the lettuce structure. Here, you find the main changes. Below, y"
},
{
"path": "pyproject.toml",
"chars": 2575,
"preview": "[build-system]\nrequires = [\"setuptools>=61\", \"wheel\", \"versioneer>=0.28\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[proj"
},
{
"path": "requirements.txt",
"chars": 2339,
"preview": "# This file was autogenerated by uv via the following command:\n# uv pip compile pyproject.toml -o requirements.txt\ncl"
},
{
"path": "tests/__init__.py",
"chars": 59,
"preview": "\"\"\"Top-level package for tests.\"\"\"\n\n__all__ = [\"conftest\"]\n"
},
{
"path": "tests/boundary/test_antibounceback_outlet_bc.py",
"chars": 4257,
"preview": "from copy import copy\n\nfrom tests.conftest import *\n\n\ndef test_anti_bounce_back_outlet(fix_configuration, fix_stencil):\n"
},
{
"path": "tests/boundary/test_bc_masks.py",
"chars": 900,
"preview": "from tests.conftest import *\n\n\ndef test_masks(fix_configuration):\n \"\"\"test if masks are applied from boundary conditi"
},
{
"path": "tests/boundary/test_bounceback_bc.py",
"chars": 1549,
"preview": "from tests.conftest import *\n\nfrom copy import copy\n\n\ndef test_bounce_back_boundary(fix_stencil, fix_configuration):\n "
},
{
"path": "tests/boundary/test_equilibrium_bc_outlet_p.py",
"chars": 1404,
"preview": "from tests.conftest import *\n\n\n# TODO: Implement cuda_native generator and test suite\n\ndef test_equilibrium_outlet_p_alg"
}
]
// ... and 56 more files (download for full content)
About this extraction
This page contains the full source code of the lettucecfd/lettuce GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 256 files (3.9 MB), approximately 1.0M tokens, and a symbol index with 827 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.