├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── SECURITY.md ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── documentation.yml │ ├── extract_nd.yml │ └── extract_nd_main.py ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── docs └── source │ ├── _static │ ├── alabaster.css_t │ └── custom.css │ ├── conf.py │ ├── conf_params │ ├── alabaster_params.py │ ├── mathjax_params.py │ └── pstyle.py │ ├── equations │ ├── image │ │ ├── draw_figure_schematic.py │ │ └── schematic.png │ └── main.rst │ ├── examples │ ├── energy │ │ ├── data │ │ │ ├── exec_2d.sh │ │ │ ├── exec_3d.sh │ │ │ └── process.py │ │ └── main.rst │ ├── main.rst │ ├── nusselt │ │ ├── data │ │ │ ├── exec_2d.sh │ │ │ ├── exec_3d.sh │ │ │ └── process.py │ │ └── main.rst │ └── typical │ │ ├── data │ │ ├── divergence.py │ │ ├── exec_2d.sh │ │ ├── exec_3d.sh │ │ ├── nusselt_time.py │ │ ├── nusselt_x.py │ │ ├── snapshot_2d.py │ │ ├── snapshot_3d.py │ │ └── std.py │ │ └── main.rst │ ├── ext │ ├── mydeclare.py │ ├── mydetails.py │ └── myliteralinclude.py │ ├── index.rst │ ├── introduction.rst │ ├── numerical_method │ ├── linear_system.rst │ ├── main.rst │ ├── poisson.rst │ ├── spatial_discretisation │ │ ├── discrete_governing_equations │ │ │ ├── figures │ │ │ │ ├── plot.gp │ │ │ │ └── result.png │ │ │ ├── main.rst │ │ │ ├── resulting_schemes │ │ │ │ ├── main.rst │ │ │ │ ├── momentum │ │ │ │ │ ├── adv.rst │ │ │ │ │ ├── buo.rst │ │ │ │ │ ├── dif.rst │ │ │ │ │ └── pre.rst │ │ │ │ ├── symbols │ │ │ │ │ ├── average.rst │ │ │ │ │ ├── differentiation.rst │ │ │ │ │ └── summation.rst │ │ │ │ └── t │ │ │ │ │ ├── adv.rst │ │ │ │ │ └── dif.rst │ │ │ └── strong_conservation_form.rst │ │ ├── domain_setup │ │ │ ├── images │ │ │ │ ├── domain.png │ │ │ │ ├── draw_figure_domain.py │ │ │ │ ├── draw_figure_grid.py │ │ │ │ ├── draw_figure_staggered.py │ │ │ │ ├── grid1.png │ │ │ │ ├── grid2.png │ │ │ │ ├── grid3.png │ │ │ │ ├── grid4.png │ │ │ │ ├── staggered1.png │ │ │ │ ├── staggered2.png │ │ │ │ ├── staggered3.png │ │ │ │ └── staggered4.png │ │ │ └── main.rst │ │ ├── main.rst │ │ ├── nusselt.rst │ │ └── quadratic_quantities │ │ │ ├── derivation │ │ │ ├── advective.rst │ │ │ ├── diffusive.rst │ │ │ ├── prerequisite │ │ │ │ ├── main.rst │ │ │ │ ├── t.rst │ │ │ │ ├── x.rst │ │ │ │ ├── y.rst │ │ │ │ └── z.rst │ │ │ └── pressure_gradient.rst │ │ │ ├── main.rst │ │ │ ├── squared_temperature.rst │ │ │ └── squared_velocity.rst │ ├── tdm.rst │ └── temporal_discretisation │ │ ├── derivation │ │ ├── cn.rst │ │ └── rk.rst │ │ ├── implicit.rst │ │ ├── main.rst │ │ ├── momentum.rst │ │ ├── temperature.rst │ │ └── time_marcher.rst │ ├── references.rst │ ├── references.txt │ ├── snapshot2d.png │ ├── snapshot3d.png │ └── thumbnail.gif ├── exec.sh ├── include ├── array.h ├── array_macros │ ├── domain │ │ ├── hxxc.h │ │ ├── hxxf.h │ │ ├── jdxc.h │ │ ├── jdxf.h │ │ ├── xc.h │ │ └── xf.h │ ├── fluid │ │ ├── p.h │ │ ├── psi.h │ │ ├── srct.h │ │ ├── srcux.h │ │ ├── srcuy.h │ │ ├── srcuz.h │ │ ├── t.h │ │ ├── ux.h │ │ ├── uy.h │ │ └── uz.h │ └── statistics │ │ ├── adv.h │ │ ├── dif.h │ │ ├── t1.h │ │ ├── t2.h │ │ ├── ux1.h │ │ ├── ux2.h │ │ ├── uy1.h │ │ ├── uy2.h │ │ ├── uz1.h │ │ └── uz2.h ├── config.h ├── decide_dt.h ├── domain.h ├── fileio.h ├── fluid.h ├── fluid_solver.h ├── halo.h ├── integrate.h ├── linear_system.h ├── logging.h ├── memory.h ├── param.h ├── runge_kutta.h ├── save.h ├── statistics.h ├── tdm.h └── timer.h ├── initial_condition ├── Makefile ├── README.rst ├── main.py └── main.sh ├── src ├── array.c ├── config.c ├── decide_dt.c ├── domain.c ├── fileio.c ├── fluid │ ├── boundary │ │ ├── p.c │ │ ├── psi.c │ │ ├── t.c │ │ ├── ux.c │ │ └── uy.c │ ├── compute_diffusivity.c │ ├── compute_potential.c │ ├── correct │ │ ├── internal.h │ │ ├── main.c │ │ ├── ux.c │ │ └── uy.c │ ├── init.c │ ├── predict │ │ ├── internal.h │ │ ├── main.c │ │ ├── t.c │ │ ├── ux.c │ │ └── uy.c │ ├── save.c │ └── update_pressure.c ├── halo.c ├── integrate.c ├── linear_system.c ├── logging │ ├── dissipated_squared_temperature.c │ ├── dissipated_squared_velocity.c │ ├── heat_transfer.c │ ├── injected_squared_velocity.c │ ├── internal.h │ ├── main.c │ ├── max_divergence.c │ ├── total_energy.c │ └── total_momentum.c ├── main.c ├── memory.c ├── param │ ├── boundary-condition.c │ ├── buoyancy.c │ └── implicit.c ├── runge_kutta.c ├── save.c ├── statistics.c ├── tdm.c └── timer.c └── tools ├── README.rst └── define_arrays.py /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | First of all, thank you for your interest in my project. 4 | 5 | Although this is my personal work and I develop it just for fun, bug reports (including typos) or suggestions (e.g. new features) are always appreciated. 6 | 7 | Questions about implementation or documentation are also welcome, as your comments will definitely improve the quality of the project. 8 | 9 | Please do not hesitate to [open a new issue](https://github.com/NaokiHori/SimpleNSSolver/issues/new), or [write to me](https://github.com/NaokiHori). 10 | 11 | Naoki Hori 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Please do not hesitate to [write to me](https://github.com/NaokiHori). 4 | 5 | Naoki Hori 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Motivation / Background 2 | 3 | 4 | 5 | This Pull Request has been created because [REPLACE ME] 6 | 7 | # Detail 8 | 9 | This Pull Request changes [REPLACE ME] 10 | 11 | # Additional information 12 | 13 | 14 | 15 | # Checklist 16 | 17 | Before submitting the PR make sure the following are checked: 18 | 19 | * This Pull Request is related to one change. Changes that are unrelated should be opened in separate PRs. 20 | * There are no typos in commit messages and comments. 21 | * Commit message has a detailed description of what changed and why. 22 | * Feature branch is up-to-date with `main` (if not - rebase it). 23 | * Pull request only contains one commit for bug fixes and small features. If it's a larger feature, multiple commits are permitted but must be descriptive. 24 | * Tests are added if you fix a bug or add a feature. 25 | * PR is not in a draft state. 26 | * CI is passing. 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | 5 | workflow_run: 6 | workflows: [ExtractND] 7 | types: 8 | - completed 9 | workflow_dispatch: 10 | 11 | jobs: 12 | 13 | build-and-deploy-doc: 14 | name: Build and deploy documentation 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | environment: 23 | name: github-pages 24 | url: ${{ steps.deployment.outputs.page_url }} 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@main 29 | with: 30 | ref: 'main' 31 | - name: Build documentation using Sphinx 32 | run: | 33 | docker run \ 34 | --rm \ 35 | --volume ${PWD}:/project \ 36 | --workdir /project \ 37 | sphinxdoc/sphinx:latest \ 38 | sphinx-build docs/source docs/build 39 | - name: Setup GitHub Pages 40 | uses: actions/configure-pages@main 41 | - name: Upload HTML 42 | uses: actions/upload-pages-artifact@main 43 | with: 44 | path: docs/build 45 | - name: Deploy to GitHub Pages 46 | id: deployment 47 | uses: actions/deploy-pages@main 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/extract_nd.yml: -------------------------------------------------------------------------------- 1 | name: ExtractND 2 | 3 | on: 4 | 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - src/** 10 | - include/** 11 | workflow_dispatch: 12 | 13 | jobs: 14 | 15 | push-branches: 16 | name: Create branch 2D and 3D which only contains the dimension 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | dimension: [2, 3] 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@main 24 | with: 25 | repository: "NaokiHori/SimpleNSSolver" 26 | ref: "main" 27 | submodules: "recursive" 28 | - name: Install dependencies 29 | run: | 30 | sudo apt-get -y update && \ 31 | sudo apt-get -y install make libopenmpi-dev libfftw3-dev 32 | - name: Remove another dimension 33 | run: | 34 | set -x 35 | set -e 36 | python .github/workflows/extract_nd_main.py ${{ matrix.dimension }} 37 | - name: Modify Makefile 38 | run: | 39 | set -x 40 | set -e 41 | sed -i "s/DNDIMS=2/DNDIMS=${{ matrix.dimension }}/g" Makefile 42 | - name: Compile 43 | run: | 44 | make all 45 | - name: Commit and push change 46 | run: | 47 | set -x 48 | set -e 49 | git switch -c ${{ matrix.dimension }}d 50 | git config --local user.email "36466440+NaokiHori@users.noreply.github.com" 51 | git config --local user.name "NaokiHori" 52 | # add, commit, and push 53 | git add Makefile 54 | git add src 55 | git add include 56 | git commit -m "Extract ${{ matrix.dimension }}d sources" -a || true 57 | git push -f origin ${{ matrix.dimension }}d 58 | 59 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SimpleDecomp"] 2 | path = SimpleDecomp 3 | url = https://github.com/NaokiHori/SimpleDecomp 4 | branch = submodule 5 | [submodule "SimpleNpyIO"] 6 | path = SimpleNpyIO 7 | url = https://github.com/NaokiHori/SimpleNpyIO 8 | branch = submodule 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 NaokiHori 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := mpicc 2 | CFLAG := -std=c99 -Wall -Wextra -O3 -DNDIMS=2 3 | INC := -Iinclude -ISimpleDecomp/include -ISimpleNpyIO/include 4 | LIB := -lfftw3 -lm 5 | SRCDIR := src SimpleDecomp/src SimpleNpyIO/src 6 | OBJDIR := obj 7 | SRCS := $(shell find $(SRCDIR) -type f -name *.c) 8 | OBJS := $(patsubst %.c,obj/%.o,$(SRCS)) 9 | DEPS := $(patsubst %.c,obj/%.d,$(SRCS)) 10 | OUTDIR := output 11 | TARGET := a.out 12 | 13 | help: 14 | @echo "all : create \"$(TARGET)\"" 15 | @echo "clean : remove \"$(TARGET)\" and object files under \"$(OBJDIR)\"" 16 | @echo "output : create \"$(OUTDIR)\" to store output" 17 | @echo "datadel : clean-up \"$(OUTDIR)\"" 18 | @echo "help : show this message" 19 | 20 | all: $(TARGET) 21 | 22 | $(TARGET): $(OBJS) 23 | $(CC) $(CFLAG) -o $@ $^ $(LIB) 24 | 25 | $(OBJDIR)/%.o: %.c 26 | @if [ ! -e $(dir $@) ]; then \ 27 | mkdir -p $(dir $@); \ 28 | fi 29 | $(CC) $(CFLAG) -MMD $(INC) -c $< -o $@ 30 | 31 | clean: 32 | $(RM) -r $(OBJDIR) $(TARGET) 33 | 34 | output: 35 | @if [ ! -e $(OUTDIR)/log ]; then \ 36 | mkdir -p $(OUTDIR)/log; \ 37 | fi 38 | @if [ ! -e $(OUTDIR)/save ]; then \ 39 | mkdir -p $(OUTDIR)/save; \ 40 | fi 41 | @if [ ! -e $(OUTDIR)/stat ]; then \ 42 | mkdir -p $(OUTDIR)/stat; \ 43 | fi 44 | 45 | datadel: 46 | $(RM) -r $(OUTDIR)/log/* 47 | $(RM) -r $(OUTDIR)/save/* 48 | $(RM) -r $(OUTDIR)/stat/* 49 | 50 | -include $(DEPS) 51 | 52 | .PHONY : all clean output datadel help 53 | 54 | -------------------------------------------------------------------------------- /docs/source/_static/custom.css: -------------------------------------------------------------------------------- 1 | div.body { 2 | max-width: 95vw; 3 | } 4 | 5 | div.MathJax_Display { 6 | overflow-x: scroll; 7 | overflow-y: clip; 8 | width: 95%; 9 | margin-left: auto; 10 | margin-right: auto; 11 | margin-top: 5px; 12 | margin-bottom: 5px; 13 | } 14 | 15 | a:visited { 16 | color: #ffb494; 17 | } 18 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.path.append(os.path.abspath("./ext")) 5 | sys.path.append(os.path.abspath("./conf_params")) 6 | 7 | project = "Simple NS Solver" 8 | author = "Naoki Hori" 9 | copyright = f"2019, {author}" 10 | 11 | extensions = [ 12 | "myliteralinclude", 13 | "mydeclare", 14 | "mydetails", 15 | "sphinx.ext.mathjax", 16 | ] 17 | 18 | from alabaster_params import html_theme 19 | from alabaster_params import html_static_path 20 | from alabaster_params import html_theme_options 21 | 22 | html_sidebars = { 23 | "**": [ 24 | "about.html", 25 | "navigation.html", 26 | ] 27 | } 28 | 29 | from mathjax_params import mathjax_path 30 | from mathjax_params import mathjax3_config 31 | 32 | pygments_style = "pstyle.MyAlabaster" 33 | 34 | -------------------------------------------------------------------------------- /docs/source/conf_params/alabaster_params.py: -------------------------------------------------------------------------------- 1 | html_theme = "alabaster" 2 | html_static_path = ["_static"] 3 | html_theme_options = { 4 | "description": "Massively-parallelised Navier-Stokes solver", 5 | "fixed_sidebar": "false", 6 | "github_banner": "false", 7 | "github_button": "true", 8 | "github_count": "true", 9 | "github_repo": "SimpleNSSolver", 10 | "github_type": "star", 11 | "github_user": "NaokiHori", 12 | "navigation_with_keys": "true", 13 | "nosidebar": "false", 14 | "page_width": "95vw", 15 | "show_powered_by": "true", 16 | "show_related": "false", 17 | "show_relbars": "false", 18 | "sidebar_collapse": "true", 19 | "sidebar_includehidden": "false", 20 | "sidebar_width": "25vw", 21 | "gray_1": "#bbb", 22 | "gray_2": "#111", 23 | "gray_3": "#555", 24 | "pink_1": "#033", 25 | "pink_2": "#055", 26 | "pink_3": "#2ad3d3", 27 | "base_bg": "#000", 28 | "base_text": "#fff", 29 | "hr_border": "#4e4b49", 30 | "body_text": "#c1bcb6", 31 | "footer_text": "#777", 32 | "link": "#ffb494", 33 | "link_hover": "#92beff", 34 | "sidebar_text": "#aaa", 35 | "sidebar_link_underscore": "#666", 36 | "sidebar_search_button": "#333", 37 | "sidebar_list": "#fff", 38 | "anchor": "#222", 39 | "anchor_hover_bg": "#151515", 40 | "table_border": "#777", 41 | "admonition_border": "#333", 42 | "note_border": "#333", 43 | "seealso_border": "#333", 44 | "tip_border": "#333", 45 | "hint_border": "#333", 46 | "important_border": "#333", 47 | "highlight_bg": "#050c17", 48 | "xref_border": "#000", 49 | "xref_bg": "#040404", 50 | "admonition_xref_border": "#050505", 51 | "footnote_bg": "#020202", 52 | "narrow_sidebar_bg": "#ccc", 53 | "narrow_sidebar_fg": "#000", 54 | "viewcode_target_bg": "#002", 55 | "code_bg": "#130f0c", 56 | "code_text": "#ddd", 57 | "code_hover": "#111", 58 | "code_highlight": "#003", 59 | } 60 | 61 | -------------------------------------------------------------------------------- /docs/source/equations/image/draw_figure_schematic.py: -------------------------------------------------------------------------------- 1 | import os 2 | import matplotlib 3 | matplotlib.use("Agg") 4 | from matplotlib import pyplot 5 | 6 | def main(): 7 | lx = 3. 8 | ly = 2. 9 | fig = pyplot.figure(figsize=(lx, ly)) 10 | ax = pyplot.Axes(fig, [0., 0., 1., 1.]) 11 | ax.set_axis_off() 12 | fig.add_axes(ax) 13 | ax.plot([0.5, 2.5], [0.5, 0.5], color="#FF0000", linewidth=5) 14 | ax.plot([0.5, 2.5], [1.5, 1.5], color="#0000FF", linewidth=5) 15 | ax.text(1.5, 0.25, "$T_H$", color="#FF0000", ha="center", va="center") 16 | ax.text(1.5, 1.75, "$T_L$", color="#0000FF", ha="center", va="center") 17 | # horizontal length 18 | ax.text(1.0, 0.8, "$l_y$", ha="center", va="center") 19 | for case in [True, False]: 20 | x = 0.5 if case else 2.5 21 | y = 0.6 22 | dx = +2.0 if case else -2.0 23 | dy = 0. 24 | ax.arrow(x, y, dx, dy, width=0.03, length_includes_head=True, head_width=0.15, head_length=0.25, shape="right", edgecolor="#000000", facecolor="#000000") 25 | # vertical length 26 | ax.text(2.5, 1.0, "$l_x$", ha="center", va="center") 27 | for case in [True, False]: 28 | x = 2.7 29 | y = 0.5 if case else 1.5 30 | dx = 0. 31 | dy = +1.0 if case else -1.0 32 | ax.arrow(x, y, dx, dy, width=0.03, length_includes_head=True, head_width=0.15, head_length=0.25, shape="right", edgecolor="#000000", facecolor="#000000") 33 | # gravity 34 | ax.text(0.5, 1.0, "$g$", ha="center", va="center") 35 | x = 0.3 36 | y = 1.25 37 | dx = 0. 38 | dy = -0.5 39 | ax.arrow(x, y, dx, dy, width=0.03, length_includes_head=True, head_width=0.15, head_length=0.25, shape="full", edgecolor="#000000", facecolor="#000000") 40 | keywords = { 41 | "aspect": "equal", 42 | "xlabel": "", 43 | "ylabel": "", 44 | "xlim": [0, lx], 45 | "ylim": [0, ly], 46 | "xticks": [], 47 | "yticks": [], 48 | } 49 | ax.set(**keywords) 50 | abspath = os.path.realpath(__file__) 51 | dirname = os.path.dirname(abspath) 52 | filename = f"{dirname}/schematic.png" 53 | print(filename) 54 | pyplot.savefig(filename) 55 | pyplot.close() 56 | 57 | if __name__ == "__main__": 58 | matplotlib.rcParams["font.size"] = 20 59 | main() 60 | -------------------------------------------------------------------------------- /docs/source/equations/image/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/equations/image/schematic.png -------------------------------------------------------------------------------- /docs/source/examples/energy/data/exec_2d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | # set initial condition 7 | cd initial_condition 8 | make output 9 | lx=1.0e+0 \ 10 | ly=1.0e+0 \ 11 | glisize=32 \ 12 | gljsize=32 \ 13 | python main.py output 14 | cd .. 15 | 16 | # configure 17 | export wtimemax=3.0e+2 18 | export save_rate=1.0e+3 19 | export save_after=1.0e+3 20 | export stat_rate=1.0e+0 21 | export stat_after=1.0e+3 22 | export coef_dt_dif=0.95 23 | export Ra=1.0e+100 24 | export Pr=1.0e+0 25 | 26 | # create random fields 27 | make all && make output 28 | timemax=5.0e+1 \ 29 | log_rate=5.0e-1 \ 30 | coef_dt_adv=0.95 \ 31 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 32 | 33 | # stash last flow field 34 | dirname_ic=$(find output/save -type d | sort | tail -n 1) 35 | mkdir dirname_ic 36 | mv ${dirname_ic}/*.npy dirname_ic/ 37 | 38 | # check decays for different time steps 39 | for factor_adv in 0.1 0.2 0.4 0.8; do 40 | sed -i "s/param_add_buoyancy.*$/param_add_buoyancy = false;/g" src/param/buoyancy.c && cat src/param/buoyancy.c 41 | make datadel && make all && make output 42 | timemax=6.0e+1 \ 43 | log_rate=1.0e-1 \ 44 | coef_dt_adv=${factor_adv} \ 45 | mpirun -n 2 --oversubscribe ./a.out dirname_ic 46 | mv output/log/total_energy.dat ./energy-${factor_adv}.dat 47 | done 48 | 49 | # post process 50 | mkdir artifacts 51 | python \ 52 | docs/source/examples/energy/data/process.py \ 53 | . \ 54 | artifacts/energy1.png \ 55 | artifacts/energy2.png 56 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci.txt 57 | echo "Date :" $(date) >> artifacts/ci.txt 58 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci.txt 59 | 60 | -------------------------------------------------------------------------------- /docs/source/examples/energy/data/exec_3d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | # set initial condition 7 | cd initial_condition 8 | make output 9 | lx=1.0e+0 \ 10 | ly=1.0e+0 \ 11 | lz=1.0e+0 \ 12 | glisize=24 \ 13 | gljsize=24 \ 14 | glksize=24 \ 15 | python main.py output 16 | cd .. 17 | 18 | # configure 19 | export wtimemax=3.0e+2 20 | export save_rate=1.0e+3 21 | export save_after=1.0e+3 22 | export stat_rate=1.0e+0 23 | export stat_after=1.0e+3 24 | export coef_dt_dif=0.95 25 | export Ra=1.0e+100 26 | export Pr=1.0e+0 27 | 28 | # create random fields 29 | make all && make output 30 | timemax=5.0e+1 \ 31 | log_rate=5.0e-1 \ 32 | coef_dt_adv=0.95 \ 33 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 34 | 35 | # stash last flow field 36 | dirname_ic=$(find output/save -type d | sort | tail -n 1) 37 | mkdir dirname_ic 38 | mv ${dirname_ic}/*.npy dirname_ic/ 39 | 40 | # check decays for different time steps 41 | for factor_adv in 0.1 0.2 0.4 0.8; do 42 | sed -i "s/param_add_buoyancy.*$/param_add_buoyancy = false;/g" src/param/buoyancy.c && cat src/param/buoyancy.c 43 | make datadel && make all && make output 44 | timemax=6.0e+1 \ 45 | log_rate=1.0e-1 \ 46 | coef_dt_adv=${factor_adv} \ 47 | mpirun -n 2 --oversubscribe ./a.out dirname_ic 48 | mv output/log/total_energy.dat ./energy-${factor_adv}.dat 49 | done 50 | 51 | # post process 52 | mkdir artifacts 53 | python \ 54 | docs/source/examples/energy/data/process.py \ 55 | . \ 56 | artifacts/energy1.png \ 57 | artifacts/energy2.png 58 | 59 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci.txt 60 | echo "Date :" $(date) >> artifacts/ci.txt 61 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci.txt 62 | 63 | -------------------------------------------------------------------------------- /docs/source/examples/energy/data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | import matplotlib 5 | matplotlib.use("Agg") 6 | from matplotlib import pyplot 7 | 8 | def load(dname): 9 | fnames = [f"{dname}/{fname}" for fname in os.listdir(dname) if fname.startswith("energy") and fname.endswith(".dat")] 10 | fnames = sorted(fnames) 11 | ls = list() 12 | xs = list() 13 | y1s = list() 14 | y2s = list() 15 | for fname in fnames: 16 | data = np.loadtxt(fname) 17 | is3d = 5 == len(data[0]) 18 | t = data[:, 0] 19 | if is3d: 20 | kx = data[:, 1] 21 | ky = data[:, 2] 22 | kz = data[:, 3] 23 | k = kx + ky + kz 24 | h = data[:, 4] 25 | kref = k[0] 26 | href = h[0] 27 | else: 28 | kx = data[:, 1] 29 | ky = data[:, 2] 30 | k = kx + ky 31 | h = data[:, 3] 32 | kref = k[0] 33 | href = h[0] 34 | ls.append(fname.strip().split("energy-")[1].split(".dat")[0]) 35 | xs.append(t[1:]) 36 | y1s.append(k[1:] - kref) 37 | y2s.append(h[1:] - href) 38 | return ls, xs, y1s, y2s 39 | 40 | if __name__ == "__main__": 41 | argv = sys.argv 42 | assert 4 == len(argv) 43 | idname = argv[1] 44 | ofname1 = argv[2] 45 | ofname2 = argv[3] 46 | ls, xs, y1s, y2s = load(idname) 47 | colors = pyplot.rcParams["axes.prop_cycle"].by_key()["color"] 48 | # 49 | fig = pyplot.figure() 50 | ax = fig.add_subplot(111) 51 | for l, x, y1, y2, color in zip(ls, xs, y1s, y2s, colors): 52 | ax.plot(x, -y1, color=color, linestyle="-", label=l) 53 | ax.plot(x, -y2, color=color, linestyle="--") 54 | kwrds = { 55 | "title": "", 56 | "xlabel": "time", 57 | "ylabel": "$-\Delta K$, $-\Delta H$", 58 | "yscale": "log", 59 | } 60 | ax.legend() 61 | ax.set(**kwrds) 62 | pyplot.savefig(ofname1) 63 | pyplot.close() 64 | # 65 | fig = pyplot.figure() 66 | ax = fig.add_subplot(111) 67 | xs = list() 68 | z1s = list() 69 | z2s = list() 70 | for l, y1, y2 in zip(ls, y1s, y2s): 71 | xs.append(float(l)) 72 | z1s.append(-y1[-1]) 73 | z2s.append(-y2[-1]) 74 | xs = np.array(xs) 75 | z1s = np.array(z1s) 76 | z2s = np.array(z2s) 77 | ax.plot(xs, z1s, marker="o", label="$-\Delta K$", color="#FF0000") 78 | ax.plot(xs, z2s, marker="o", label="$-\Delta H$", color="#0000FF") 79 | ax.plot(xs, 2. * z1s[0] / xs[0]**3. * xs**3., label="3rd order", color="#000000") 80 | kwrds = { 81 | "title": "", 82 | "xlabel": "$\Delta t$", 83 | "ylabel": "$-\Delta K$, $-\Delta H$", 84 | "xscale": "log", 85 | "yscale": "log", 86 | } 87 | ax.legend() 88 | ax.set(**kwrds) 89 | pyplot.savefig(ofname2) 90 | pyplot.close() 91 | 92 | -------------------------------------------------------------------------------- /docs/source/examples/energy/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _example_conservation_q: 3 | 4 | .. include:: /references.txt 5 | 6 | #################################### 7 | Conservation of Quadratic Quantities 8 | #################################### 9 | 10 | In this section, we check the conservations of the volume-integrated quadratic quantities. 11 | See :ref:`the governing equations ` for the definitions of these quantities. 12 | 13 | ************* 14 | Configuration 15 | ************* 16 | 17 | First, we simulate for :math:`50` time units to get a random flow. 18 | :math:`Ra` is set to an extremely high value to mimic an inviscid condition. 19 | This is followed by another run for :math:`10` time units, restarted from the previous simulation without the buoyancy force, so that the quadratic quantities should be conserved. 20 | 21 | To see the effect of the time step size, I consider four different :ref:`Courant numbers ` :math:`0.1`, :math:`0.2`, :math:`0.4`, :math:`0.8`. 22 | 23 | ******* 24 | Results 25 | ******* 26 | 27 | As derived in :ref:`the governing equaations `, the quadratic quantities should be constant over time. 28 | This is not the case in this project, since we adopt an :ref:`explicit Runge-Kutta scheme ` to integrate the advective terms in time, which is dissipative (see |MORINISHI1998|, |COPPOLA2019|). 29 | Thus these two quantities decrease monotonically over time, which is unfavourable but advantageous from a stability point of view. 30 | 31 | The following graphs show the quadratic quantities as a function of time: 32 | 33 | 2D: 34 | 35 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/energy-2d/energy1.png 36 | :width: 600 37 | 38 | 3D: 39 | 40 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/energy-3d/energy1.png 41 | :width: 600 42 | 43 | Here four different time step sizes are considered. 44 | Also, the decays of :math:`K` and :math:`H` (:math:`t = 50` and :math:`60` are compared) are displayed. 45 | 46 | 2D: 47 | 48 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/energy-2d/energy2.png 49 | :width: 600 50 | 51 | 3D: 52 | 53 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/energy-3d/energy2.png 54 | :width: 600 55 | 56 | Here the third-order convergence is observed, which is also reported by the previous works (e.g., |MORINISHI1998|, |HAM2002| and |COPPOLA2019|). 57 | This indicates that the decay, which is a numerical artifact, is properly converged. 58 | 59 | -------------------------------------------------------------------------------- /docs/source/examples/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _examples: 3 | 4 | ######## 5 | Examples 6 | ######## 7 | 8 | Several example cases are displayed in this section. 9 | 10 | .. note:: 11 | 12 | To reduce the computational effort, ``timemax`` is set to relatively small values. 13 | As a result, the statistics might be collected before the system reaches statistically-stationary state. 14 | 15 | .. toctree:: 16 | :maxdepth: 1 17 | 18 | typical/main 19 | energy/main 20 | nusselt/main 21 | 22 | -------------------------------------------------------------------------------- /docs/source/examples/nusselt/data/exec_2d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | lx=1.0e+0 7 | ly=2.0e+0 8 | Ra=1.0e+4 9 | Pr=${1} 10 | 11 | # set initial condition 12 | cd initial_condition 13 | make output 14 | lx=${lx} \ 15 | ly=${ly} \ 16 | glisize=32 \ 17 | gljsize=64 \ 18 | python main.py output 19 | cd .. 20 | 21 | # build and execute 22 | make all && make output 23 | timemax=1.0e+3 \ 24 | wtimemax=6.0e+2 \ 25 | log_rate=1.0e+0 \ 26 | save_rate=1.0e+3 \ 27 | save_after=1.0e+3 \ 28 | stat_rate=1.0e+0 \ 29 | stat_after=1.0e+3 \ 30 | coef_dt_adv=0.95 \ 31 | coef_dt_dif=0.95 \ 32 | Ra=${Ra} \ 33 | Pr=${Pr} \ 34 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 35 | 36 | # post process 37 | mkdir artifacts 38 | 39 | ly=${ly} \ 40 | Ra=${Ra} \ 41 | Pr=${Pr} \ 42 | python \ 43 | docs/source/examples/nusselt/data/process.py \ 44 | output/log/heat_transfer.dat \ 45 | output/log/injected_squared_velocity.dat \ 46 | output/log/dissipated_squared_velocity.dat \ 47 | output/log/dissipated_squared_temperature.dat \ 48 | artifacts/nusselt.png 49 | 50 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci_${Pr}.txt 51 | echo "Date :" $(date) >> artifacts/ci_${Pr}.txt 52 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci_${Pr}.txt 53 | 54 | -------------------------------------------------------------------------------- /docs/source/examples/nusselt/data/exec_3d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | lx=1.0e+0 7 | ly=1.0e+0 8 | lz=1.0e+0 9 | Ra=5.0e+3 10 | Pr=${1} 11 | 12 | # set initial condition 13 | cd initial_condition 14 | make output 15 | lx=${lx} \ 16 | ly=${ly} \ 17 | lz=${lz} \ 18 | glisize=16 \ 19 | gljsize=16 \ 20 | glksize=16 \ 21 | python main.py output 22 | cd .. 23 | 24 | # build and execute 25 | sed -i "s/false/true/g" src/param/implicit.c 26 | make all && make output 27 | timemax=5.0e+3 \ 28 | wtimemax=6.0e+2 \ 29 | log_rate=1.0e+0 \ 30 | save_rate=5.0e+3 \ 31 | save_after=1.0e+3 \ 32 | stat_rate=1.0e+0 \ 33 | stat_after=1.0e+3 \ 34 | coef_dt_adv=0.95 \ 35 | coef_dt_dif=0.95 \ 36 | Ra=${Ra} \ 37 | Pr=${Pr} \ 38 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 39 | 40 | # post process 41 | mkdir artifacts 42 | 43 | ly=${ly} \ 44 | lz=${lz} \ 45 | Ra=${Ra} \ 46 | Pr=${Pr} \ 47 | python \ 48 | docs/source/examples/nusselt/data/process.py \ 49 | output/log/heat_transfer.dat \ 50 | output/log/injected_squared_velocity.dat \ 51 | output/log/dissipated_squared_velocity.dat \ 52 | output/log/dissipated_squared_temperature.dat \ 53 | artifacts/nusselt.png 54 | 55 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci.txt 56 | echo "Date :" $(date) >> artifacts/ci.txt 57 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci.txt 58 | 59 | -------------------------------------------------------------------------------- /docs/source/examples/nusselt/data/process.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | import matplotlib 5 | matplotlib.use("Agg") 6 | from matplotlib import pyplot 7 | 8 | def load(fname): 9 | data = np.loadtxt(fname) 10 | x = data[:, 0] 11 | y = data[:, 1] 12 | return x, y 13 | 14 | def get_ref_heat_transfer(): 15 | ly = os.environ.get("ly") 16 | lz = os.environ.get("lz") 17 | Ra = os.environ.get("Ra") 18 | Pr = os.environ.get("Pr") 19 | ly = float(ly) 20 | lz = float(lz) if lz else 1. 21 | Ra = float(Ra) 22 | Pr = float(Pr) 23 | return ly * lz / Ra**0.5 / Pr**0.5 24 | 25 | if __name__ == "__main__": 26 | argv = sys.argv 27 | assert 6 == len(argv) 28 | ifnames = argv[1:-1] 29 | ofname = argv[-1] 30 | xs = list() 31 | ys = list() 32 | for ifname in ifnames: 33 | x, y = load(ifname) 34 | xs.append(x) 35 | ys.append(y) 36 | q_ref = get_ref_heat_transfer() 37 | converters = [ 38 | lambda x: x / q_ref, 39 | lambda x: (x + q_ref) / q_ref, 40 | lambda x: (x + q_ref) / q_ref, 41 | lambda x: x / q_ref, 42 | ] 43 | for cnt, converter in enumerate(converters): 44 | ys[cnt] = converter(ys[cnt]) 45 | fig = pyplot.figure() 46 | ax = fig.add_subplot() 47 | ax.plot(xs[0], np.abs(ys[1] - ys[0]), color="#FF0000") 48 | ax.plot(xs[0], np.abs(ys[2] - ys[0]), color="#0000FF") 49 | ax.plot(xs[0], np.abs(ys[3] - ys[0]), color="#33AA00") 50 | kwrds = { 51 | "title": "", 52 | "xlabel": "time", 53 | "ylabel": "deviations", 54 | "yticks": [1.e-16, 1.e-12, 1.e-8, 1.e-4, 1.e+0], 55 | "yscale": "log", 56 | } 57 | ax.set(**kwrds) 58 | pyplot.savefig(ofname) 59 | pyplot.close() 60 | 61 | -------------------------------------------------------------------------------- /docs/source/examples/nusselt/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _example_nu_agreement: 3 | 4 | ######################### 5 | Nusselt Number Agreements 6 | ######################### 7 | 8 | ************* 9 | Configuration 10 | ************* 11 | 12 | I consider three Prandtl numbers: :math:`Pr = 10^{-1}, 10^0, 10^1`. 13 | The other parameters are listed below. 14 | 15 | ****** 16 | Result 17 | ****** 18 | 19 | :math:`Nu` calculated by four different formulae are considered: 20 | 21 | * reference: heat flux on the walls 22 | 23 | * red: energy injection 24 | 25 | * blue: kinetic energy dissipation 26 | 27 | * green: thermal energy dissipation 28 | 29 | Their deviations from the reference value :math:`Nu_{wall}` are plotted to highlight the difference. 30 | The reason why the lines are partly discontinuous is that the discrepancies are smaller than :math:`10^{-15}`. 31 | 32 | 2D, :math:`Pr = 10^{-1}`: 33 | 34 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-2d-1.e-1/nusselt.png 35 | :width: 600 36 | 37 | 2D, :math:`Pr = 10^{ 0}`: 38 | 39 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-2d-1.e+0/nusselt.png 40 | :width: 600 41 | 42 | 2D, :math:`Pr = 10^{ 1}`: 43 | 44 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-2d-1.e+1/nusselt.png 45 | :width: 600 46 | 47 | 3D, :math:`Pr = 10^{-1}`: 48 | 49 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-3d-1.e-1/nusselt.png 50 | :width: 600 51 | 52 | 3D, :math:`Pr = 10^{ 0}`: 53 | 54 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-3d-1.e+0/nusselt.png 55 | :width: 600 56 | 57 | 3D, :math:`Pr = 10^{ 1}`: 58 | 59 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/nusselt-3d-1.e+1/nusselt.png 60 | :width: 600 61 | 62 | The deviations should be small enough (around the rounding error). 63 | 64 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/divergence.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import matplotlib 4 | matplotlib.use("Agg") 5 | from matplotlib import pyplot 6 | 7 | def load(fname, xmin): 8 | data = np.loadtxt(fname) 9 | x = data[:, 0] 10 | y = data[:, 1] 11 | y = y[x > xmin] 12 | x = x[x > xmin] 13 | return x, y 14 | 15 | if __name__ == "__main__": 16 | argv = sys.argv 17 | assert 3 == len(argv) 18 | ifname = argv[1] 19 | ofname = argv[2] 20 | xmin = 200. 21 | x, y = load(ifname, xmin) 22 | fig = pyplot.figure() 23 | ax = fig.add_subplot(111) 24 | ax.plot(x, y, color="#FF0000") 25 | kwrds = { 26 | "title": "", 27 | "xlim": [200., 300.], 28 | "ylim": [1.e-16, 1.e-13], 29 | "xlabel": "time", 30 | "ylabel": "maximum divergence", 31 | "xticks": [200., 250., 300.], 32 | "yticks": [1.e-16, 1.e-15, 1.e-14, 1.e-13], 33 | "yscale": "log", 34 | } 35 | ax.set(**kwrds) 36 | pyplot.savefig(ofname) 37 | pyplot.close() 38 | 39 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/exec_2d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | lx=1.0e+0 7 | ly=2.0e+0 8 | Ra=1.0e+8 9 | Pr=1.0e+1 10 | 11 | # set initial condition 12 | cd initial_condition 13 | make output 14 | lx=${lx} \ 15 | ly=${ly} \ 16 | glisize=128 \ 17 | gljsize=256 \ 18 | python main.py output 19 | cd .. 20 | 21 | # build and execute 22 | make all && make output 23 | timemax=3.0e+2 \ 24 | wtimemax=6.0e+2 \ 25 | log_rate=5.0e-1 \ 26 | save_rate=5.0e+1 \ 27 | save_after=0.0e+0 \ 28 | stat_rate=1.0e-1 \ 29 | stat_after=2.0e+2 \ 30 | coef_dt_adv=0.95 \ 31 | coef_dt_dif=0.95 \ 32 | Ra=${Ra} \ 33 | Pr=${Pr} \ 34 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 35 | 36 | # post process 37 | mkdir artifacts 38 | 39 | # visualise 40 | python \ 41 | docs/source/examples/typical/data/snapshot_2d.py \ 42 | $(find output/save -type d | sort | tail -n 1) \ 43 | artifacts/snapshot.png 44 | 45 | # divergence-t plot 46 | python \ 47 | docs/source/examples/typical/data/divergence.py \ 48 | output/log/max_divergence.dat \ 49 | artifacts/divergence.png 50 | 51 | # Nu-t plot 52 | ly=${ly} \ 53 | Ra=${Ra} \ 54 | Pr=${Pr} \ 55 | python \ 56 | docs/source/examples/typical/data/nusselt_time.py \ 57 | output/log/heat_transfer.dat \ 58 | output/log/injected_squared_velocity.dat \ 59 | output/log/dissipated_squared_velocity.dat \ 60 | output/log/dissipated_squared_temperature.dat \ 61 | artifacts/nusselt_time.png 62 | 63 | # Nu-x plot 64 | ly=${ly} \ 65 | Ra=${Ra} \ 66 | Pr=${Pr} \ 67 | python \ 68 | docs/source/examples/typical/data/nusselt_x.py \ 69 | $(find output/stat -type d | sort | tail -n 1) \ 70 | artifacts/nusselt_x.png 71 | 72 | # standard deviations in x 73 | python \ 74 | docs/source/examples/typical/data/std.py \ 75 | $(find output/stat -type d | sort | tail -n 1) \ 76 | artifacts/std.png 77 | 78 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci.txt 79 | echo "Date :" $(date) >> artifacts/ci.txt 80 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci.txt 81 | 82 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/exec_3d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | lx=1.0e+0 7 | ly=1.0e+0 8 | lz=1.0e+0 9 | Ra=1.0e+6 10 | Pr=1.0e+1 11 | 12 | # set initial condition 13 | cd initial_condition 14 | make output 15 | lx=${lx} \ 16 | ly=${ly} \ 17 | lz=${lz} \ 18 | glisize=32 \ 19 | gljsize=32 \ 20 | glksize=32 \ 21 | python main.py output 22 | cd .. 23 | 24 | # build and execute 25 | make all && make output 26 | timemax=3.0e+2 \ 27 | wtimemax=6.0e+2 \ 28 | log_rate=5.0e-1 \ 29 | save_rate=5.0e+1 \ 30 | save_after=0.0e+0 \ 31 | stat_rate=1.0e-1 \ 32 | stat_after=2.0e+2 \ 33 | coef_dt_adv=0.95 \ 34 | coef_dt_dif=0.95 \ 35 | Ra=${Ra} \ 36 | Pr=${Pr} \ 37 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 38 | 39 | # post process 40 | mkdir artifacts 41 | 42 | # visualise 43 | python \ 44 | docs/source/examples/typical/data/snapshot_3d.py \ 45 | $(find output/save -type d | sort | tail -n 1) \ 46 | artifacts/snapshot.png 47 | 48 | # divergence-t plot 49 | python \ 50 | docs/source/examples/typical/data/divergence.py \ 51 | output/log/max_divergence.dat \ 52 | artifacts/divergence.png 53 | 54 | # Nu-t plot 55 | ly=${ly} \ 56 | lz=${lz} \ 57 | Ra=${Ra} \ 58 | Pr=${Pr} \ 59 | python \ 60 | docs/source/examples/typical/data/nusselt_time.py \ 61 | output/log/heat_transfer.dat \ 62 | output/log/injected_squared_velocity.dat \ 63 | output/log/dissipated_squared_velocity.dat \ 64 | output/log/dissipated_squared_temperature.dat \ 65 | artifacts/nusselt_time.png 66 | 67 | # Nu-x plot 68 | ly=${ly} \ 69 | lz=${lz} \ 70 | Ra=${Ra} \ 71 | Pr=${Pr} \ 72 | python \ 73 | docs/source/examples/typical/data/nusselt_x.py \ 74 | $(find output/stat -type d | sort | tail -n 1) \ 75 | artifacts/nusselt_x.png 76 | 77 | # standard deviations in x 78 | python \ 79 | docs/source/examples/typical/data/std.py \ 80 | $(find output/stat -type d | sort | tail -n 1) \ 81 | artifacts/std.png 82 | 83 | echo "OS :" $(cat /etc/os-release | grep PRETTY_NAME | awk -F "=" '{print $2}') >> artifacts/ci.txt 84 | echo "Date :" $(date) >> artifacts/ci.txt 85 | echo "Hash :" $(git rev-parse HEAD) >> artifacts/ci.txt 86 | 87 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/nusselt_time.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | import matplotlib 5 | matplotlib.use("Agg") 6 | from matplotlib import pyplot 7 | 8 | def load(fname, xmin): 9 | data = np.loadtxt(fname) 10 | x = data[:, 0] 11 | y = data[:, 1] 12 | y = y[xmin < x] 13 | x = x[xmin < x] 14 | return x, y 15 | 16 | def get_ref_heat_transfer(): 17 | ly = os.environ.get("ly") 18 | lz = os.environ.get("lz") 19 | Ra = os.environ.get("Ra") 20 | Pr = os.environ.get("Pr") 21 | ly = float(ly) 22 | lz = float(lz) if lz else 1. 23 | Ra = float(Ra) 24 | Pr = float(Pr) 25 | return ly * lz / Ra**0.5 / Pr**0.5 26 | 27 | if __name__ == "__main__": 28 | argv = sys.argv 29 | assert 6 == len(argv) 30 | ifnames = argv[1:-1] 31 | ofname = argv[-1] 32 | is2d = True if None == os.environ.get("lz") else False 33 | xmin = 200. 34 | q_ref = get_ref_heat_transfer() 35 | fig = pyplot.figure() 36 | ax = fig.add_subplot(111) 37 | colors = [ 38 | "#FF0000", 39 | "#0000FF", 40 | "#33AA00", 41 | "#FF00FF", 42 | ] 43 | labels = [ 44 | "heat transfer", 45 | "kinetic energy injection", 46 | "kinetic energy dissipation", 47 | "thermal energy dissipation", 48 | ] 49 | converters = [ 50 | lambda x: x / q_ref, 51 | lambda x: (x + q_ref) / q_ref, 52 | lambda x: (x + q_ref) / q_ref, 53 | lambda x: x / q_ref, 54 | ] 55 | for color, label, converter, ifname in zip(colors, labels, converters, ifnames): 56 | x, y = load(ifname, xmin) 57 | y = converter(y) 58 | ax.plot(x, y, color=color, label=label) 59 | if is2d: 60 | # van der Poel et al., JFM, 2013 61 | y = np.full(x.shape, 27.25) 62 | ax.plot(x, y, color="#000000", linestyle="dashed") 63 | kwrds = { 64 | "title": "", 65 | "xlim": [xmin, 300.], 66 | "xlabel": "time", 67 | "ylabel": "Nusselt numbers", 68 | "xticks": [200., 250., 300.], 69 | } 70 | ax.set(**kwrds) 71 | ax.legend() 72 | pyplot.savefig(ofname) 73 | pyplot.close() 74 | 75 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/nusselt_x.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | import matplotlib 5 | matplotlib.use("Agg") 6 | from matplotlib import pyplot 7 | 8 | def get_ref_heat_transfer(): 9 | ly = os.environ.get("ly") 10 | lz = os.environ.get("lz") 11 | Ra = os.environ.get("Ra") 12 | Pr = os.environ.get("Pr") 13 | ly = float(ly) 14 | lz = float(lz) if lz else 1. 15 | Ra = float(Ra) 16 | Pr = float(Pr) 17 | return ly * lz / Ra**0.5 / Pr**0.5 18 | 19 | def load_and_process(dname): 20 | xf = np.load(f"{dname}/xf.npy") 21 | num = np.load(f"{dname}/num.npy") 22 | adv = np.load(f"{dname}/adv.npy") 23 | dif = np.load(f"{dname}/dif.npy") 24 | is3d = 3 == len(adv.shape) 25 | # normalise 26 | adv /= get_ref_heat_transfer() 27 | dif /= get_ref_heat_transfer() 28 | # divide by the number of samples 29 | adv /= num 30 | dif /= num 31 | # average in the homogeneous direction(s) 32 | adv = np.sum(adv, axis=0) 33 | dif = np.sum(dif, axis=0) 34 | if is3d: 35 | adv = np.sum(adv, axis=0) 36 | dif = np.sum(dif, axis=0) 37 | # average bottom-half and top-half 38 | nx = len(xf) // 2 39 | adv = 0.5 * adv + 0.5 * adv[::-1] 40 | dif = 0.5 * dif + 0.5 * dif[::-1] 41 | return xf[:nx+1], adv[:nx+1], dif[:nx+1] 42 | 43 | if __name__ == "__main__": 44 | argv = sys.argv 45 | assert 3 == len(argv) 46 | idname = argv[1] 47 | ofname = argv[2] 48 | x, adv, dif = load_and_process(idname) 49 | tot = adv + dif 50 | fig = pyplot.figure() 51 | ax = fig.add_subplot(111) 52 | ax.plot(x, adv, color="#FF0000", linestyle="-", label="advection") 53 | ax.plot(x, dif, color="#0000FF", linestyle="-", label="diffusion") 54 | ax.plot(x, tot, color="#000000", linestyle=":", label="total") 55 | kwrds = { 56 | "title": "", 57 | "xlim": [0., 0.5], 58 | "xlabel": "wall-normal position", 59 | "ylabel": "Nusselt contributions", 60 | "xticks": [0., 0.25, 0.5], 61 | } 62 | ax.set(**kwrds) 63 | ax.legend() 64 | pyplot.savefig(ofname, dpi=150) 65 | pyplot.close() 66 | 67 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/snapshot_2d.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import matplotlib 4 | matplotlib.use("Agg") 5 | from matplotlib import pyplot 6 | 7 | def load(dname): 8 | lengths = np.load(f"{dname}/lengths.npy") 9 | glsizes = np.load(f"{dname}/glsizes.npy") 10 | xc = np.load(f"{dname}/xc.npy") 11 | lx = lengths[0] 12 | ly = lengths[1] 13 | ny = glsizes[1] 14 | dy = ly / ny 15 | yc = np.linspace(0.5 * dy, ly - 0.5 * dy, ny) 16 | t = np.load(f"{dname}/t.npy") 17 | return lx, ly, xc, yc, t 18 | 19 | if __name__ == "__main__": 20 | argv = sys.argv 21 | assert(3 == len(argv)) 22 | idname = argv[1] 23 | ofname = argv[2] 24 | lx, ly, x, y, t = load(idname) 25 | # visualise transposed array since my screen is wider 26 | fig = pyplot.figure(figsize=(8, 4)) 27 | fig.set_size_inches(8, 4) 28 | ax = pyplot.Axes(fig, [0., 0., 1., 1.]) 29 | ax.set_axis_off() 30 | fig.add_axes(ax) 31 | ax.contourf(y, x, t.T, vmin=-0.5, vmax=+0.5, cmap="bwr", levels=51) 32 | kwrds = { 33 | "title": "", 34 | "aspect": "equal", 35 | "xlim": [0.0, ly], 36 | "ylim": [0.0, lx], 37 | "xlabel": "", 38 | "ylabel": "", 39 | "xticks": [], 40 | "yticks": [], 41 | } 42 | ax.set(**kwrds) 43 | pyplot.savefig(ofname, dpi=150) 44 | pyplot.close() 45 | 46 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/snapshot_3d.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import pyvista 4 | from pyvista import themes 5 | 6 | def load(dname): 7 | time = np.load(f"{dname}/time.npy") 8 | lengths = np.load(f"{dname}/lengths.npy") 9 | glsizes = np.load(f"{dname}/glsizes.npy") 10 | xc = np.load(f"{dname}/xc.npy") 11 | lx = lengths[0] 12 | ly = lengths[1] 13 | lz = lengths[2] 14 | ny = glsizes[1] 15 | nz = glsizes[2] 16 | dy = ly / ny 17 | dz = lz / nz 18 | yc = np.linspace(0.5 * dy, ly - 0.5 * dy, ny) 19 | zc = np.linspace(0.5 * dz, lz - 0.5 * dz, nz) 20 | t = np.load(f"{dname}/t.npy") 21 | return time, lx, ly, lz, xc, yc, zc, t 22 | 23 | if __name__ == "__main__": 24 | argv = sys.argv 25 | assert(3 == len(argv)) 26 | idname = argv[1] 27 | ofname = argv[2] 28 | time, lx, ly, lz, x, y, z, t = load(idname) 29 | grid = pyvista.RectilinearGrid(x, y, z) 30 | t = np.ravel(t) 31 | my_theme = themes.Theme() 32 | my_theme.lighting = True 33 | my_theme.show_edges = False 34 | my_theme.background = "#000000" 35 | my_theme.window_size = [1200, 800] 36 | thresholds = [-0.1, +0.1] 37 | colours = ["#0000FF", "#FF0000"] 38 | isosurfaces = 1 39 | plotter = pyvista.Plotter(theme=my_theme, off_screen=True) 40 | for threshold, colour in zip(thresholds, colours): 41 | contour = grid.contour(isosurfaces=isosurfaces, scalars=t, rng=[threshold, threshold]) 42 | contour = contour.smooth_taubin(n_iter=30, pass_band=0.05) 43 | plotter.add_mesh(contour, color=colour, opacity=1.) 44 | plotter.camera_position = 'xy' 45 | plotter.camera.roll = 90 46 | plotter.camera.azimuth = 30 47 | plotter.camera.elevation = 10. 48 | plotter.camera.zoom(1.2) 49 | plotter.show(screenshot=ofname) 50 | plotter.close() 51 | 52 | -------------------------------------------------------------------------------- /docs/source/examples/typical/data/std.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import matplotlib 4 | matplotlib.use("Agg") 5 | from matplotlib import pyplot 6 | 7 | def load(dname): 8 | glsizes = np.load(f"{dname}/glsizes.npy") 9 | is3d = True if 3 == len(glsizes) else False 10 | num = np.load(f"{dname}/num.npy") 11 | xf = np.load(f"{dname}/xf.npy") 12 | xc = np.load(f"{dname}/xc.npy") 13 | ux1 = np.load(f"{dname}/ux1.npy") 14 | ux2 = np.load(f"{dname}/ux2.npy") 15 | uy1 = np.load(f"{dname}/uy1.npy") 16 | uy2 = np.load(f"{dname}/uy2.npy") 17 | if is3d: 18 | uz1 = np.load(f"{dname}/uz1.npy") 19 | uz2 = np.load(f"{dname}/uz2.npy") 20 | else: 21 | uz1 = None 22 | uz2 = None 23 | t1 = np.load(f"{dname}/t1.npy") 24 | t2 = np.load(f"{dname}/t2.npy") 25 | return is3d, num, xf, xc, ux1, ux2, uy1, uy2, uz1, uz2, t1, t2 26 | 27 | def compute_rms(data1, data2): 28 | rms2 = data2 - np.power(data1, 2.) 29 | rms2[rms2 < 0.] = 0. 30 | return np.sqrt(rms2) 31 | 32 | def trunc(arr): 33 | n = len(arr) 34 | arr = arr[:n//2+1] 35 | return arr 36 | 37 | if __name__ == "__main__": 38 | idname = sys.argv[1] 39 | ofname = sys.argv[2] 40 | is3d, num, xf, xc, ux1, ux2, uy1, uy2, uz1, uz2, t1, t2 = load(idname) 41 | # 42 | t1 /= num 43 | ux1 /= num 44 | uy1 /= num 45 | t2 /= num 46 | ux2 /= num 47 | uy2 /= num 48 | if is3d: 49 | uz1 /= num 50 | uz2 /= num 51 | # 52 | t2 = compute_rms(t1, t2) 53 | ux2 = compute_rms(ux1, ux2) 54 | uy2 = compute_rms(uy1, uy2) 55 | if is3d: 56 | uz2 = compute_rms(uz1, uz2) 57 | t2 = np.average(t2, axis=0) 58 | ux2 = np.average(ux2, axis=0) 59 | uy2 = np.average(uy2, axis=0) 60 | if is3d: 61 | uz2 = np.average(uz2, axis=0) 62 | if is3d: 63 | t2 = np.average(t2, axis=0) 64 | ux2 = np.average(ux2, axis=0) 65 | uy2 = np.average(uy2, axis=0) 66 | uz2 = np.average(uz2, axis=0) 67 | t2 = 0.5 * t2[:] + 0.5 * t2[::-1] 68 | ux2 = 0.5 * ux2[:] + 0.5 * ux2[::-1] 69 | uy2 = 0.5 * uy2[:] + 0.5 * uy2[::-1] 70 | if is3d: 71 | uz2 = 0.5 * uz2[:] + 0.5 * uz2[::-1] 72 | # 73 | xf = trunc(xf) 74 | xc = trunc(xc) 75 | t2 = trunc(t2) 76 | ux2 = trunc(ux2) 77 | uy2 = trunc(uy2) 78 | if is3d: 79 | uz2 = trunc(uz2) 80 | # 81 | fig = pyplot.figure() 82 | ax = fig.add_subplot(111) 83 | ax.plot(xf, ux2, color="#FF0000", label="ux") 84 | ax.plot(xc, uy2, color="#0000FF", label="uy") 85 | if is3d: 86 | ax.plot(xc, uz2, color="#FF00FF", label="uz") 87 | ax.plot(xc, t2, color="#33AA00", label="T") 88 | kwrds = { 89 | "title": "", 90 | "xlim": [0., 0.5], 91 | "xlabel": "wall-normal position", 92 | "ylabel": "standard deviations", 93 | "xticks": [0., 0.25, 0.5], 94 | } 95 | ax.set(**kwrds) 96 | ax.legend() 97 | pyplot.savefig(ofname, dpi=150) 98 | pyplot.close() 99 | 100 | -------------------------------------------------------------------------------- /docs/source/examples/typical/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _example_typical_case: 3 | 4 | .. include:: /references.txt 5 | 6 | ############# 7 | Typical Cases 8 | ############# 9 | 10 | ************** 11 | Visualisations 12 | ************** 13 | 14 | Temperature fields at the end of the simulations. 15 | 16 | 2D: 17 | 18 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-2d/snapshot.png 19 | :width: 600 20 | 21 | 3D: 22 | 23 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-3d/snapshot.png 24 | :width: 600 25 | 26 | **************************** 27 | Incompressibility constraint 28 | **************************** 29 | 30 | Maximum divergence of the velocity field, which should be sufficiently small. 31 | 32 | 2D: 33 | 34 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-2d/divergence.png 35 | :width: 600 36 | 37 | 3D: 38 | 39 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-3d/divergence.png 40 | :width: 600 41 | 42 | *************** 43 | Nusselt numbers 44 | *************** 45 | 46 | ========= 47 | Evolution 48 | ========= 49 | 50 | :math:`Nu` calculated using the different formulae, which are monitored during the run, are shown as a function of time: 51 | 52 | * red: heat fluxes on the walls 53 | 54 | * blue: energy input 55 | 56 | * green: kinetic energy dissipation 57 | 58 | * magenta: thermal energy dissipation 59 | 60 | 2D: 61 | 62 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-2d/nusselt_time.png 63 | :width: 600 64 | 65 | 3D: 66 | 67 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-3d/nusselt_time.png 68 | :width: 600 69 | 70 | .. note:: 71 | 72 | The black-dashed line in the two-dimensional result shows a reference value by |VANDERPOEL2013| with the same :math:`Ra` and :math:`Pr` but the different domain geometry is different (box). 73 | 74 | .. seealso:: 75 | 76 | :ref:`Nusselt number relations `. 77 | 78 | ========================= 79 | Temporary-Averaged Values 80 | ========================= 81 | 82 | As derived :ref:`here `, there are two contributions which transfer heat: advective contribution: 83 | 84 | .. math:: 85 | 86 | \sumzc 87 | \sumyc 88 | \frac{J}{\sfact{1}} 89 | \vel{1} 90 | \ave{T}{\gcs{1}}, 91 | 92 | and diffusive contribution: 93 | 94 | .. math:: 95 | 96 | - 97 | \sumzc 98 | \sumyc 99 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 100 | \frac{J}{\sfact{1}} 101 | \frac{1}{\sfact{1}} 102 | \dif{T}{\gcs{1}}. 103 | 104 | After averaged over time and homogeneous directions, they are displayed as a function of the wall-normal position :math:`x` here: 105 | 106 | 2D: 107 | 108 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-2d/nusselt_x.png 109 | :width: 600 110 | 111 | 3D: 112 | 113 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-3d/nusselt_x.png 114 | :width: 600 115 | 116 | ******************* 117 | Standard deviations 118 | ******************* 119 | 120 | Variances of (red) :math:`\ux`, (blue) :math:`\uy`, (magenta) :math:`\uz`, and (green) :math:`T` are shown here. 121 | 122 | 2D: 123 | 124 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-2d/std.png 125 | :width: 600 126 | 127 | 3D: 128 | 129 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/artifacts/artifacts/typical-3d/std.png 130 | :width: 600 131 | 132 | .. note:: 133 | 134 | Although the :math:`y` and the :math:`z` directions are homogeneous, the blue and magenta lines may deviate, which is attributed to the low :math:`Ra` and short time. 135 | 136 | -------------------------------------------------------------------------------- /docs/source/ext/mydeclare.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import List 3 | from docutils import nodes 4 | from docutils.nodes import Node 5 | from docutils.parsers.rst import directives 6 | from sphinx.directives import optional_int 7 | from sphinx.util.docutils import SphinxDirective 8 | from sphinx.util.typing import OptionSpec 9 | from sphinx.directives.code import LiteralIncludeReader 10 | 11 | def get_lines(filename, tag): 12 | # find "/**" and tag (declaration of function) 13 | # l0: line number of the upper-closest "/**" 14 | # l1: line number of the end of function 15 | l0 = -1 16 | l1 = -1 17 | with open(filename, "r") as f: 18 | in_def = False 19 | for cnt, line in enumerate(f): 20 | if "/**" in line: 21 | l0 = cnt 22 | if f"{tag}(" in line: 23 | # function name is found 24 | in_def = True 25 | if in_def and "){" in line: 26 | l1 = cnt 27 | break 28 | # index in python starts from 0, while line number is from 1 29 | l0 += 1 30 | l1 += 1 31 | if l0 <= 0: 32 | msg = f"non-positive l0: {l0}" 33 | raise RuntimeError(msg) 34 | if l1 <= 0: 35 | msg = f"non-positive l1: {l1}" 36 | raise RuntimeError(msg) 37 | if l1 <= l0: 38 | msg = f"l1 ({l1}) < l0 {l0}" 39 | raise RuntimeError(msg) 40 | return "{}-{}".format(l0, l1) 41 | 42 | def reshape_text(text): 43 | # replace last "){" with ");" 44 | return text.replace("){", ");") 45 | 46 | class MyDeclare(SphinxDirective): 47 | """ 48 | Customised LiteralInclude class 49 | """ 50 | has_content = False 51 | required_arguments = 1 52 | optional_arguments = 0 53 | final_argument_whitespace = True 54 | option_spec: OptionSpec = { 55 | "language": directives.unchanged_required, 56 | "tag": directives.unchanged_required, 57 | } 58 | def run(self) -> List[Node]: 59 | document = self.state.document 60 | if not document.settings.file_insertion_enabled: 61 | return [document.reporter.warning("File insertion disabled", 62 | line=self.lineno)] 63 | try: 64 | rel_filename, filename = self.env.relfn2path(self.arguments[0]) 65 | self.env.note_dependency(rel_filename) 66 | self.options["lines"] = get_lines(filename, self.options["tag"]) 67 | reader = LiteralIncludeReader(filename, self.options, self.config) 68 | text, lines = reader.read() 69 | text = reshape_text(text) 70 | retnode: Element = nodes.literal_block(text, text, source=filename) 71 | retnode["force"] = "force" in self.options 72 | self.set_source_info(retnode) 73 | retnode["language"] = self.options["language"] 74 | retnode["linenos"] = False 75 | self.add_name(retnode) 76 | return [retnode] 77 | except Exception as exc: 78 | return [document.reporter.warning(exc, line=self.lineno)] 79 | 80 | def setup(app): 81 | app.add_directive("mydeclare", MyDeclare) 82 | return { 83 | "version": "0.1", 84 | "parallel_read_safe": True, 85 | "parallel_write_safe": True, 86 | } 87 | 88 | -------------------------------------------------------------------------------- /docs/source/ext/mydetails.py: -------------------------------------------------------------------------------- 1 | from docutils import nodes 2 | from docutils.parsers.rst import Directive, directives 3 | from sphinx.transforms.post_transforms import SphinxPostTransform 4 | from sphinx.util.nodes import NodeMatcher 5 | 6 | 7 | class details(nodes.Element, nodes.General): 8 | pass 9 | 10 | class summary(nodes.TextElement, nodes.General): 11 | pass 12 | 13 | def visit_details(self, node): 14 | self.body.append("
") 15 | 16 | def depart_details(self, node): 17 | self.body.append("
") 18 | 19 | def visit_summary(self, node): 20 | self.body.append("") 21 | 22 | def depart_summary(self, node): 23 | self.body.append("") 24 | 25 | class MyDetails(Directive): 26 | required_arguments = 1 27 | final_argument_whitespace = True 28 | has_content = True 29 | option_spec = { 30 | "class": directives.class_option, 31 | "name": directives.unchanged, 32 | } 33 | def run(self): 34 | admonition = nodes.container( 35 | "", 36 | classes=self.options.get("classes", []), 37 | type="mydetails" 38 | ) 39 | textnodes, messages = self.state.inline_text( 40 | self.arguments[0], 41 | self.lineno 42 | ) 43 | admonition += nodes.paragraph(self.arguments[0], "", *textnodes) 44 | admonition += messages 45 | self.state.nested_parse(self.content, self.content_offset, admonition) 46 | self.add_name(admonition) 47 | return [admonition] 48 | 49 | class MyDetailsTransform(SphinxPostTransform): 50 | default_priority = 200 51 | def run(self): 52 | matcher = NodeMatcher(nodes.container, type="mydetails") 53 | for node in self.document.traverse(matcher): 54 | newnode = details(**node.attributes) 55 | newnode += summary("", "", *node[0]) 56 | newnode.extend(node[1:]) 57 | node.replace_self(newnode) 58 | 59 | def setup(app): 60 | app.add_node(details, html=(visit_details, depart_details)) 61 | app.add_node(summary, html=(visit_summary, depart_summary)) 62 | app.add_directive("mydetails", MyDetails) 63 | app.add_post_transform(MyDetailsTransform) 64 | return { 65 | "version": "0.1", 66 | "parallel_read_safe": True, 67 | "parallel_write_safe": True, 68 | } 69 | 70 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | ############# 2 | Documentation 3 | ############# 4 | 5 | .. image:: snapshot2d.png 6 | :width: 800 7 | 8 | .. image:: snapshot3d.png 9 | :width: 800 10 | 11 | .. toctree:: 12 | :hidden: 13 | 14 | introduction 15 | equations/main 16 | numerical_method/main 17 | examples/main 18 | references 19 | 20 | -------------------------------------------------------------------------------- /docs/source/introduction.rst: -------------------------------------------------------------------------------- 1 | ############ 2 | Introduction 3 | ############ 4 | 5 | ******** 6 | Overview 7 | ******** 8 | 9 | This library is developed with the following three main reasons in mind. 10 | 11 | #. Bridging the gap between methods and implementations 12 | 13 | Despite the existence of numerous elegant libraries, not all of them have comprehensive documentation. 14 | In some cases, there can be a significant discrepancy between the methods (equations) and the actual implementations (code). 15 | The goal of this project is to reduce this gap and provide clear links. 16 | 17 | #. Ensuring validation and verification 18 | 19 | While code validations are typically shown in publications, it can be challenging to determine if the code really works, and sometimes compiling the code itself can be tedious. 20 | This project aims to validate the code and automatically publish the results when changes are made, ensuring that the library is always well-validated and verified. 21 | 22 | #. Shedding light on small but non-trivial details 23 | 24 | Although the background algorithm of this solver (integration of mass, momentum, and scalar fields) is well-known and straightforward, minor details are often overlooked, and the correct approaches can be counter-intuitive. 25 | Adopting Rayleigh-Bénard convection as a model problem, this project aims to shed light on these small but non-trivial details, such as discrete energy conservation, calculation of dissipation rates, and Nusselt number agreements, providing insights into these important aspects. 26 | 27 | ************ 28 | Dependencies 29 | ************ 30 | 31 | ====== 32 | Solver 33 | ====== 34 | 35 | * `C compiler `_ 36 | * `GNU Make `_ 37 | * `MPI `_ 38 | * `FFTW3 `_ 39 | 40 | ======= 41 | Utility 42 | ======= 43 | 44 | * `Git `_ 45 | * `Python `_ with `NumPy `_ (for easy flow initialisation) 46 | 47 | ***** 48 | Usage 49 | ***** 50 | 51 | #. Prepare workplace 52 | 53 | .. code-block:: console 54 | 55 | mkdir -p /path/to/your/directory 56 | cd /path/to/your/directory 57 | 58 | #. Get source 59 | 60 | .. code-block:: console 61 | 62 | git clone --recurse-submodules https://github.com/NaokiHori/SimpleNSSolver 63 | cd SimpleNSSolver 64 | 65 | #. Set initial condition 66 | 67 | A set of initial conditions must be provided, as this is a PDE solver: 68 | 69 | .. code-block:: console 70 | 71 | cd initial_condition 72 | make output 73 | bash exec.sh 74 | cd .. 75 | 76 | #. Build solver 77 | 78 | .. code-block:: console 79 | 80 | make output 81 | make all 82 | 83 | #. Execute 84 | 85 | .. code-block:: console 86 | 87 | bash exec.sh 88 | 89 | Run-time parameters are defined in `exec.sh `_ as environment variables. 90 | 91 | -------------------------------------------------------------------------------- /docs/source/numerical_method/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _numerics: 3 | 4 | ################ 5 | Numerical Method 6 | ################ 7 | 8 | Numerical treatments of :ref:`the governing equations ` are discussed here. 9 | 10 | In the first part, the discretization of the variables in the computational (discrete) domain is discussed. 11 | Although there are :ref:`five equations `, the relations with respect to :math:`k` and :math:`h` are not solved numerically because they depend on the other three. 12 | These dependencies, which are obvious in theory, are so fragile that they are not satisfied if we do not treat the main three relations properly. 13 | The proper spatial numerical treatment is our main interest. 14 | 15 | In the second part, conventional techniques to integrate the given ordinary differential equations in time are briefly discussed. 16 | Specifically, we focus on the SMAC method for dealing with the momentum balance and the incompressibility constraint, and the implicit treatment of the diffusive terms. 17 | 18 | To update the flow field, we need to solve linear systems (when diffusive terms are treated implicitly) and a Poisson equation, which are separately discussed. 19 | Both rely on solving tri-diagonal matrices, which is also elaborated. 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | 24 | spatial_discretisation/main 25 | temporal_discretisation/main 26 | linear_system 27 | poisson 28 | tdm 29 | 30 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/figures/plot.gp: -------------------------------------------------------------------------------- 1 | # physical coordinate 2 | { 3 | reset 4 | xmin = - 0.5 5 | xmax = + 4.0 6 | ymin = - 0.5 7 | ymax = + 4.0 8 | lx = xmax-xmin 9 | ly = ymax-ymin 10 | set terminal epslatex standalone color size lx,ly font ',12' 11 | set output 'car.tex' 12 | unset border 13 | set lmargin 0 14 | set rmargin 0 15 | set bmargin 0 16 | set tmargin 0 17 | unset xlabel 18 | unset ylabel 19 | set xrange [xmin:xmax] 20 | set yrange [ymin:ymax] 21 | unset xtics 22 | unset ytics 23 | set size ratio -1 24 | set samples 10000 25 | set style line 1 lc rgb '#000000' lw 10 26 | num = 8 27 | xmin = 0. 28 | xmax = 3.5 29 | ymin = 0. 30 | ymax = 3.5 31 | deltax = (xmax - xmin) / num 32 | deltay = (ymax - ymin) / num 33 | do for [i = 0 : num : 1] { 34 | if (0 == i) { 35 | x = xmin 36 | } else if (num == i) { 37 | x = xmax 38 | } else { 39 | x = i - num / 2 40 | x = xmin + (xmax - xmin) * 1. / (1. + exp(- 1. * x)) 41 | } 42 | set arrow from first x, first ymin to first x, first ymax nohead ls 1 43 | y = ymin + i * deltay 44 | set arrow from first xmin, first y to first xmax, first y nohead ls 1 45 | } 46 | plot \ 47 | NaN notitle 48 | } 49 | 50 | # computational coordinate 51 | { 52 | reset 53 | xmin = - 0.5 54 | xmax = + 4.0 55 | ymin = - 0.5 56 | ymax = + 4.0 57 | lx = xmax-xmin 58 | ly = ymax-ymin 59 | set terminal epslatex standalone color size lx,ly font ',12' 60 | set output 'comp.tex' 61 | unset border 62 | set lmargin 0 63 | set rmargin 0 64 | set bmargin 0 65 | set tmargin 0 66 | unset xlabel 67 | unset ylabel 68 | set xrange [xmin:xmax] 69 | set yrange [ymin:ymax] 70 | unset xtics 71 | unset ytics 72 | set size ratio -1 73 | set samples 10000 74 | set style line 1 lc rgb '#000000' lw 10 75 | num = 8 76 | xmin = 0. 77 | xmax = 3.5 78 | ymin = 0. 79 | ymax = 3.5 80 | deltax = (xmax - xmin) / num 81 | deltay = (ymax - ymin) / num 82 | do for [i = 0 : num : 1] { 83 | x = xmin + i * deltax 84 | set arrow from first x, first ymin to first x, first ymax nohead ls 1 85 | y = ymin + i * deltay 86 | set arrow from first xmin, first y to first xmax, first y nohead ls 1 87 | } 88 | plot \ 89 | NaN notitle 90 | } 91 | 92 | # merge above elements 93 | { 94 | reset 95 | xmin = 0.0 96 | xmax = 9.0 97 | ymin = 0.0 98 | ymax = 5.25 99 | lx = xmax - xmin 100 | ly = ymax - ymin 101 | set terminal epslatex standalone color size lx,ly font ',20' 102 | set output 'result.tex' 103 | unset border 104 | set lmargin 0 105 | set rmargin 0 106 | set bmargin 0 107 | set tmargin 0 108 | unset xlabel 109 | unset ylabel 110 | set xrange [xmin:xmax] 111 | set yrange [ymin:ymax] 112 | unset xtics 113 | unset ytics 114 | set size ratio -1 115 | ref = 4.5 116 | set label 'Physical coordinate' center at first 0.5 * ref, first 1. * ref + 0.35 textcolor rgb '#000000' 117 | set label 'Computational coordinate' center at first 1.5 * ref, first 1. * ref + 0.35 textcolor rgb '#000000' 118 | set label '$\left( x, y \right)$' center at first 0.5 * ref, first 1. * ref - 0.05 textcolor rgb '#000000' 119 | set label '$\left( \xi^1, \xi^2 \right)$' center at first 1.5 * ref, first 1. * ref - 0.05 textcolor rgb '#000000' 120 | set label '\includegraphics[width=4.500in, height=4.500in]{car.pdf}' center at first 0.5 * ref, first 0.5 * ref 121 | set label '\includegraphics[width=4.500in, height=4.500in]{comp.pdf}' center at first 1.5 * ref, first 0.5 * ref 122 | plot \ 123 | NaN notitle 124 | } 125 | 126 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/figures/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/figures/result.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _discrete_governing_equations: 3 | 4 | .. include:: /references.txt 5 | 6 | ############################ 7 | Discrete Governing Equations 8 | ############################ 9 | 10 | :ref:`The SMAC method ` adopted in :ref:`the temporal discretization ` is a *de facto standard* to integrate the momentum balance in time while keeping the incompressibility constraint. 11 | Spatial treatments are, on the other hand, more flexible, and a proper scheme is totally case-dependent. 12 | In this section, we focus on the following two features and derive the discrete governing equations which are implemented in this project. 13 | 14 | * Being simple 15 | 16 | In this project, we only consider second-order-accurate central-difference schemes, where three points in one direction (one and its two neighboring points) are used to evaluate the differentiations. 17 | Although its accuracy is not at all comparable to spectral methods, it is versatile, robust, and also applicable to multiphase flows due to its locality. 18 | 19 | * Preserving properties of the original equations 20 | 21 | Since we approximate the equations by discretizations, it is impossible to keep all properties that the original equations have in the continuous domain. 22 | However, as reviewed in :ref:`the governing equations `, there are several important relations, among others, e.g., 23 | 24 | * The conservative terms do not alter the net amount of quadratic quantities, namely :math:`\int k dV` and :math:`\int h dV` are conserved in the absence of viscous effects. 25 | 26 | * The dissipative terms in the equations of the squared quantities (:math:`k` and :math:`h`) reduce the total amount of the quantity. 27 | 28 | We focus on replicating these properties in the discrete domain. 29 | 30 | In short, the conclusive treatment for the advective terms here is known as the energy-conserving scheme, and we refer to the overall scheme which treat all other terms in a consistent manner as *energy-consistent* scheme. 31 | 32 | .. toctree:: 33 | :maxdepth: 1 34 | 35 | strong_conservation_form 36 | resulting_schemes/main 37 | 38 | .. seealso:: 39 | 40 | * |KAJISHIMA1999| 41 | * |KAJISHIMA2017| 42 | 43 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. include:: /references.txt 3 | 4 | ################# 5 | Resulting schemes 6 | ################# 7 | 8 | We discretize the mentioned equations as follows. 9 | Note that we define several symbols for notational convenience. 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | 14 | symbols/average 15 | symbols/differentiation 16 | symbols/summation 17 | 18 | The advective terms are implemented in tri-diagonal-like ways to insist the advective operators are skew-symmetric (c.f., |VERSTAPPEN2003|). 19 | Since the diffusive terms are given by the vector Laplacian of the velocity vector, the discrete Laplace operators are pre-computed. 20 | 21 | .. _discrete_incompressibility: 22 | 23 | **************************** 24 | Incompressibility constraint 25 | **************************** 26 | 27 | We define this relation for each cell center :math:`\left( \ccidx{i}, \ccidx{j}, \ccidx{k} \right)`: 28 | 29 | .. math:: 30 | 31 | \ddiv{1} 32 | + 33 | \ddiv{2} 34 | + 35 | \ddiv{3} 36 | = 37 | 0. 38 | 39 | The left-hand side is monitored to confirm if the maximum divergence of the flow field is sufficiently small (:math:`\approx 0`): 40 | 41 | .. myliteralinclude:: /../../src/logging/max_divergence.c 42 | :language: c 43 | :tag: check max local divergence 44 | 45 | .. _discrete_momentum_balance: 46 | 47 | **************** 48 | Momentum balance 49 | **************** 50 | 51 | The following relations are defined at the corresponding cell faces. 52 | 53 | .. math:: 54 | 55 | \pder{\vel{1}}{t} 56 | = 57 | & 58 | - 59 | \dmomadv{1}{1} 60 | - 61 | \dmomadv{2}{1} 62 | - 63 | \dmomadv{3}{1} 64 | 65 | & 66 | - 67 | \dmompre{1} 68 | 69 | & 70 | + 71 | \dmomdif{1}{1} 72 | + 73 | \dmomdif{2}{1} 74 | + 75 | \dmomdif{3}{1} 76 | 77 | & 78 | + 79 | \dmombuo. 80 | 81 | .. math:: 82 | 83 | \pder{\vel{2}}{t} 84 | = 85 | & 86 | - 87 | \dmomadv{1}{2} 88 | - 89 | \dmomadv{2}{2} 90 | - 91 | \dmomadv{3}{2} 92 | 93 | & 94 | - 95 | \dmompre{2} 96 | 97 | & 98 | + 99 | \dmomdif{1}{2} 100 | + 101 | \dmomdif{2}{2} 102 | + 103 | \dmomdif{3}{2}. 104 | 105 | .. math:: 106 | 107 | \pder{\vel{3}}{t} 108 | = 109 | & 110 | - 111 | \dmomadv{1}{3} 112 | - 113 | \dmomadv{2}{3} 114 | - 115 | \dmomadv{3}{3} 116 | 117 | & 118 | - 119 | \dmompre{3} 120 | 121 | & 122 | + 123 | \dmomdif{1}{3} 124 | + 125 | \dmomdif{2}{3} 126 | + 127 | \dmomdif{3}{3}. 128 | 129 | The implementations are elaborated below. 130 | 131 | .. toctree:: 132 | :maxdepth: 1 133 | 134 | momentum/adv 135 | momentum/pre 136 | momentum/dif 137 | momentum/buo 138 | 139 | .. _discrete_internal_energy_balance: 140 | 141 | *********************** 142 | Internal energy balance 143 | *********************** 144 | 145 | We define this relation for each cell center :math:`\left( \ccidx{i}, \ccidx{j}, \ccidx{k} \right)`: 146 | 147 | .. math:: 148 | 149 | \pder{T}{t} 150 | = 151 | & 152 | - 153 | \dtempadv{1} 154 | - 155 | \dtempadv{2} 156 | - 157 | \dtempadv{3} 158 | 159 | & 160 | + 161 | \dtempdif{1} 162 | + 163 | \dtempdif{2} 164 | + 165 | \dtempdif{3}. 166 | 167 | The implementations are elaborated below. 168 | 169 | .. toctree:: 170 | :maxdepth: 1 171 | 172 | t/adv 173 | t/dif 174 | 175 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/momentum/adv.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Advection 3 | ######### 4 | 5 | ******************** 6 | Wall-normal relation 7 | ******************** 8 | 9 | .. math:: 10 | 11 | - 12 | \dmomadv{1}{1} 13 | 14 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 15 | :language: c 16 | :tag: advected in x 17 | 18 | .. math:: 19 | 20 | - 21 | \dmomadv{2}{1} 22 | 23 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 24 | :language: c 25 | :tag: advected in y 26 | 27 | .. math:: 28 | 29 | - 30 | \dmomadv{3}{1} 31 | 32 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 33 | :language: c 34 | :tag: advected in z 35 | 36 | ******************** 37 | Stream-wise relation 38 | ******************** 39 | 40 | .. math:: 41 | 42 | - 43 | \dmomadv{1}{2} 44 | 45 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 46 | :language: c 47 | :tag: advected in x 48 | 49 | .. math:: 50 | 51 | - 52 | \dmomadv{2}{2} 53 | 54 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 55 | :language: c 56 | :tag: advected in y 57 | 58 | .. math:: 59 | 60 | - 61 | \dmomadv{3}{2} 62 | 63 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 64 | :language: c 65 | :tag: advected in z 66 | 67 | ****************** 68 | Span-wise relation 69 | ****************** 70 | 71 | .. math:: 72 | 73 | - 74 | \dmomadv{1}{3} 75 | 76 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 77 | :language: c 78 | :tag: advected in x 79 | 80 | .. math:: 81 | 82 | - 83 | \dmomadv{2}{3} 84 | 85 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 86 | :language: c 87 | :tag: advected in y 88 | 89 | .. math:: 90 | 91 | - 92 | \dmomadv{3}{3} 93 | 94 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 95 | :language: c 96 | :tag: advected in z 97 | 98 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/momentum/buo.rst: -------------------------------------------------------------------------------- 1 | ######## 2 | Buoyancy 3 | ######## 4 | 5 | .. math:: 6 | 7 | \dmombuo 8 | 9 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 10 | :language: c 11 | :tag: buoyancy effect 12 | 13 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/momentum/dif.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Diffusion 3 | ######### 4 | 5 | ******************** 6 | Wall-normal relation 7 | ******************** 8 | 9 | .. math:: 10 | 11 | \dmomdif{1}{1} 12 | 13 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 14 | :language: c 15 | :tag: vector laplacian in x 16 | 17 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 18 | :language: c 19 | :tag: diffused in x 20 | 21 | .. math:: 22 | 23 | \dmomdif{2}{1} 24 | 25 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 26 | :language: c 27 | :tag: vector laplacian in y 28 | 29 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 30 | :language: c 31 | :tag: diffused in y 32 | 33 | .. math:: 34 | 35 | \dmomdif{3}{1} 36 | 37 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 38 | :language: c 39 | :tag: vector laplacian in z 40 | 41 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 42 | :language: c 43 | :tag: diffused in z 44 | 45 | ******************** 46 | Stream-wise relation 47 | ******************** 48 | 49 | .. math:: 50 | 51 | \dmomdif{1}{2} 52 | 53 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 54 | :language: c 55 | :tag: vector laplacian in x 56 | 57 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 58 | :language: c 59 | :tag: diffused in x 60 | 61 | .. math:: 62 | 63 | \dmomdif{2}{2} 64 | 65 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 66 | :language: c 67 | :tag: vector laplacian in y 68 | 69 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 70 | :language: c 71 | :tag: diffused in y 72 | 73 | .. math:: 74 | 75 | \dmomdif{3}{2} 76 | 77 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 78 | :language: c 79 | :tag: vector laplacian in z 80 | 81 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 82 | :language: c 83 | :tag: diffused in z 84 | 85 | ****************** 86 | Span-wise relation 87 | ****************** 88 | 89 | .. math:: 90 | 91 | \dmomdif{1}{3} 92 | 93 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 94 | :language: c 95 | :tag: diffused in x 96 | 97 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 98 | :language: c 99 | :tag: vector laplacian in x 100 | 101 | .. math:: 102 | 103 | \dmomdif{2}{3} 104 | 105 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 106 | :language: c 107 | :tag: diffused in y 108 | 109 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 110 | :language: c 111 | :tag: vector laplacian in y 112 | 113 | .. math:: 114 | 115 | \dmomdif{3}{3} 116 | 117 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 118 | :language: c 119 | :tag: vector laplacian in z 120 | 121 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 122 | :language: c 123 | :tag: diffused in z 124 | 125 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/momentum/pre.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Pressure-gradient 3 | ################# 4 | 5 | ******************** 6 | Wall-normal relation 7 | ******************** 8 | 9 | .. math:: 10 | 11 | - 12 | \dmompre{1} 13 | 14 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 15 | :language: c 16 | :tag: pressure gradient effect 17 | 18 | ******************** 19 | Stream-wise relation 20 | ******************** 21 | 22 | .. math:: 23 | 24 | - 25 | \dmompre{2} 26 | 27 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 28 | :language: c 29 | :tag: pressure gradient effect 30 | 31 | ****************** 32 | Span-wise relation 33 | ****************** 34 | 35 | .. math:: 36 | 37 | - 38 | \dmompre{3} 39 | 40 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 41 | :language: c 42 | :tag: pressure gradient effect 43 | 44 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/symbols/average.rst: -------------------------------------------------------------------------------- 1 | ####### 2 | Average 3 | ####### 4 | 5 | At :math:`\gcs{1}` cell faces: 6 | 7 | .. math:: 8 | 9 | \vat{ 10 | \ave{q}{\gcs{1}} 11 | }{ 12 | i + \frac{1}{2} 13 | } 14 | = 15 | \left\{ 16 | \begin{alignedat}{2} 17 | & \text{Negative wall:} & \vat{q}{\frac{1}{2}}, \\ 18 | & \text{Positive wall:} & \vat{q}{\ngp{1} + \frac{1}{2}}, \\ 19 | & \text{Otherwise:} & \frac{1}{2} \vat{q}{i} + \frac{1}{2} \vat{q}{i + 1}. 20 | \end{alignedat} 21 | \right. 22 | 23 | At :math:`\gcs{1}` cell centers: 24 | 25 | .. math:: 26 | 27 | \vat{ 28 | \ave{q}{\gcs{1}} 29 | }{ 30 | i 31 | } 32 | = 33 | \frac{1}{2} \vat{q}{i - \frac{1}{2}} 34 | + 35 | \frac{1}{2} \vat{q}{i + \frac{1}{2}}. 36 | 37 | At :math:`\gcs{2}` cell faces: 38 | 39 | .. math:: 40 | 41 | \vat{ 42 | \ave{q}{\gcs{2}} 43 | }{ 44 | j + \frac{1}{2} 45 | } 46 | = 47 | \frac{1}{2} \vat{q}{j} 48 | + 49 | \frac{1}{2} \vat{q}{j + 1}. 50 | 51 | At :math:`\gcs{2}` cell centers: 52 | 53 | .. math:: 54 | 55 | \vat{ 56 | \ave{q}{\gcs{2}} 57 | }{ 58 | j 59 | } 60 | = 61 | \frac{1}{2} \vat{q}{j - \frac{1}{2}} 62 | + 63 | \frac{1}{2} \vat{q}{j + \frac{1}{2}}. 64 | 65 | At :math:`\gcs{3}` cell faces: 66 | 67 | .. math:: 68 | 69 | \vat{ 70 | \ave{q}{\gcs{3}} 71 | }{ 72 | k + \frac{1}{2} 73 | } 74 | = 75 | \frac{1}{2} \vat{q}{k} 76 | + 77 | \frac{1}{2} \vat{q}{k + 1}. 78 | 79 | At :math:`\gcs{3}` cell centers: 80 | 81 | .. math:: 82 | 83 | \vat{ 84 | \ave{q}{\gcs{3}} 85 | }{ 86 | k 87 | } 88 | = 89 | \frac{1}{2} \vat{q}{k - \frac{1}{2}} 90 | + 91 | \frac{1}{2} \vat{q}{k + \frac{1}{2}}. 92 | 93 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/symbols/differentiation.rst: -------------------------------------------------------------------------------- 1 | ############### 2 | Differentiation 3 | ############### 4 | 5 | At :math:`\gcs{1}` cell faces: 6 | 7 | .. math:: 8 | 9 | \vat{ 10 | \dif{q}{\gcs{1}} 11 | }{ 12 | i + \frac{1}{2} 13 | } 14 | = 15 | \left\{ 16 | \begin{alignedat}{2} 17 | & \text{Negative wall:} & - \vat{q}{\frac{1}{2}} + \vat{q}{1}, \\ 18 | & \text{Positive wall:} & - \vat{q}{\ngp{1}} + \vat{q}{\ngp{1} + \frac{1}{2}}, \\ 19 | & \text{Otherwise:} & - \vat{q}{i} + \vat{q}{i + 1}. 20 | \end{alignedat} 21 | \right. 22 | 23 | At :math:`\gcs{1}` cell centers: 24 | 25 | .. math:: 26 | 27 | \vat{ 28 | \dif{q}{\gcs{1}} 29 | }{ 30 | i 31 | } 32 | = 33 | - \vat{q}{i - \frac{1}{2}} 34 | + \vat{q}{i + \frac{1}{2}}. 35 | 36 | At :math:`\gcs{2}` cell faces: 37 | 38 | .. math:: 39 | 40 | \vat{ 41 | \dif{q}{\gcs{2}} 42 | }{ 43 | j + \frac{1}{2} 44 | } 45 | = 46 | - 47 | \vat{q}{j} 48 | + 49 | \vat{q}{j + 1}. 50 | 51 | At :math:`\gcs{2}` cell centers: 52 | 53 | .. math:: 54 | 55 | \vat{ 56 | \dif{q}{\gcs{2}} 57 | }{ 58 | j 59 | } 60 | = 61 | - 62 | \vat{q}{j - \frac{1}{2}} 63 | + 64 | \vat{q}{j + \frac{1}{2}}. 65 | 66 | At :math:`\gcs{3}` cell faces: 67 | 68 | .. math:: 69 | 70 | \vat{ 71 | \dif{q}{\gcs{3}} 72 | }{ 73 | k + \frac{1}{2} 74 | } 75 | = 76 | - 77 | \vat{q}{k} 78 | + 79 | \vat{q}{k + 1}. 80 | 81 | At :math:`\gcs{3}` cell centers: 82 | 83 | .. math:: 84 | 85 | \vat{ 86 | \dif{q}{\gcs{3}} 87 | }{ 88 | k 89 | } 90 | = 91 | - 92 | \vat{q}{k - \frac{1}{2}} 93 | + 94 | \vat{q}{k + \frac{1}{2}}. 95 | 96 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/symbols/summation.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Summation 3 | ######### 4 | 5 | At :math:`\gcs{1}` cell faces: 6 | 7 | .. math:: 8 | 9 | \sumxf q 10 | \equiv 11 | \vat{q}{\frac{1}{2}} 12 | + 13 | \vat{q}{\frac{3}{2}} 14 | + 15 | \cdots 16 | + 17 | \vat{q}{\ngp{1} - \frac{1}{2}} 18 | + 19 | \vat{q}{\ngp{1} + \frac{1}{2}}. 20 | 21 | At :math:`\gcs{1}` cell centers: 22 | 23 | .. math:: 24 | 25 | \sumxc q 26 | \equiv 27 | \vat{q}{1} 28 | + 29 | \vat{q}{2} 30 | + 31 | \cdots 32 | + 33 | \vat{q}{\ngp{1} - 1} 34 | + 35 | \vat{q}{\ngp{1}}. 36 | 37 | At :math:`\gcs{2}` cell faces: 38 | 39 | .. math:: 40 | 41 | \sumyf q 42 | \equiv 43 | \vat{q}{\frac{1}{2}} 44 | + 45 | \vat{q}{\frac{3}{2}} 46 | + 47 | \cdots 48 | + 49 | \vat{q}{\ngp{2} - \frac{3}{2}} 50 | + 51 | \vat{q}{\ngp{2} - \frac{1}{2}}. 52 | 53 | At :math:`\gcs{2}` cell centers: 54 | 55 | .. math:: 56 | 57 | \sumyc q 58 | \equiv 59 | \vat{q}{1} 60 | + 61 | \vat{q}{2} 62 | + 63 | \cdots 64 | + 65 | \vat{q}{\ngp{2} - 1} 66 | + 67 | \vat{q}{\ngp{2}}. 68 | 69 | At :math:`\gcs{3}` cell faces: 70 | 71 | .. math:: 72 | 73 | \sumzf q 74 | \equiv 75 | \vat{q}{\frac{1}{2}} 76 | + 77 | \vat{q}{\frac{3}{2}} 78 | + 79 | \cdots 80 | + 81 | \vat{q}{\ngp{3} - \frac{3}{2}} 82 | + 83 | \vat{q}{\ngp{3} - \frac{1}{2}}. 84 | 85 | At :math:`\gcs{3}` cell centers: 86 | 87 | .. math:: 88 | 89 | \sumzc q 90 | \equiv 91 | \vat{q}{1} 92 | + 93 | \vat{q}{2} 94 | + 95 | \cdots 96 | + 97 | \vat{q}{\ngp{3} - 1} 98 | + 99 | \vat{q}{\ngp{3}}. 100 | 101 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/t/adv.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Advection 3 | ######### 4 | 5 | .. math:: 6 | 7 | - 8 | \dtempadv{1} 9 | 10 | .. myliteralinclude:: /../../src/fluid/predict/t.c 11 | :language: c 12 | :tag: advected in x 13 | 14 | .. math:: 15 | 16 | - 17 | \dtempadv{2} 18 | 19 | .. myliteralinclude:: /../../src/fluid/predict/t.c 20 | :language: c 21 | :tag: advected in y 22 | 23 | .. math:: 24 | 25 | - 26 | \dtempadv{3} 27 | 28 | .. myliteralinclude:: /../../src/fluid/predict/t.c 29 | :language: c 30 | :tag: advected in z 31 | 32 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/discrete_governing_equations/resulting_schemes/t/dif.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Diffusion 3 | ######### 4 | 5 | .. math:: 6 | 7 | \dtempdif{1} 8 | 9 | .. myliteralinclude:: /../../src/fluid/predict/t.c 10 | :language: c 11 | :tag: diffused in x 12 | 13 | .. myliteralinclude:: /../../src/fluid/predict/t.c 14 | :language: c 15 | :tag: scalar laplacian in x 16 | 17 | .. math:: 18 | 19 | \dtempdif{2} 20 | 21 | .. myliteralinclude:: /../../src/fluid/predict/t.c 22 | :language: c 23 | :tag: diffused in y 24 | 25 | .. myliteralinclude:: /../../src/fluid/predict/t.c 26 | :language: c 27 | :tag: scalar laplacian in y 28 | 29 | .. math:: 30 | 31 | \dtempdif{3} 32 | 33 | .. myliteralinclude:: /../../src/fluid/predict/t.c 34 | :language: c 35 | :tag: diffused in z 36 | 37 | .. myliteralinclude:: /../../src/fluid/predict/t.c 38 | :language: c 39 | :tag: scalar laplacian in z 40 | 41 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/domain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/domain.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/draw_figure_domain.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import matplotlib 4 | matplotlib.use("Agg") 5 | from matplotlib import pyplot 6 | from matplotlib import patches 7 | 8 | def general(ax, glisize, gljsize): 9 | # vertical lines 10 | xs = np.arange(1, glisize, 1) 11 | ys = [0., gljsize] 12 | ax.vlines(xs, ys[0], ys[1], colors="#000000", linestyles="--") 13 | # horizontal lines 14 | xs = [0., glisize] 15 | ys = np.arange(1, gljsize, 1) 16 | ax.hlines(ys, xs[0], xs[1], colors="#000000", linestyles="--") 17 | keywords = { 18 | "aspect": "equal", 19 | "xlabel": "", 20 | "ylabel": "", 21 | "xlim": [0, glisize], 22 | "ylim": [0, gljsize], 23 | } 24 | ax.set(**keywords) 25 | 26 | def main(): 27 | glisize = 7 28 | gljsize = 10 29 | myisize = glisize 30 | myjsize = [3, 3, 4] 31 | offsets = [0, 3, 6] 32 | fig = pyplot.figure(figsize=(7.0, 3.5)) 33 | ax121 = fig.add_subplot(121) 34 | ax122 = fig.add_subplot(122) 35 | general(ax121, glisize, gljsize) 36 | general(ax122, glisize, gljsize) 37 | ax121.set_title("global domain") 38 | ax122.set_title("local domain") 39 | ax121.set_xticks(ticks=[0.5, glisize-0.5], labels=["1", "glsizes[0]"]) 40 | ax121.set_yticks(ticks=[0.5, gljsize-0.5], labels=["1", "glsizes[1]"]) 41 | ax122.set_xticks(ticks=[0.5, myisize-0.5], labels=["1", "mysizes[0]"]) 42 | ax122.set_yticks( 43 | ticks=[ 44 | offsets[0]+0.5, offsets[0]+myjsize[0]-0.5, 45 | offsets[1]+0.5, offsets[1]+myjsize[1]-0.5, 46 | offsets[2]+0.5, offsets[2]+myjsize[2]-0.5, 47 | ], 48 | labels=[ 49 | "1", "mysizes[1]", 50 | "1", "mysizes[1]", 51 | "1", "mysizes[1]", 52 | ] 53 | ) 54 | ax121.add_patch(patches.Rectangle(xy=(0, 0), width=glisize, height=gljsize, facecolor="#888888", edgecolor="#888888", zorder=-10, alpha=0.5)) 55 | ax122.add_patch(patches.Rectangle(xy=(0, offsets[0]), width=myisize, height=myjsize[0], facecolor="#FF0000", edgecolor="#FF0000", zorder=-10, alpha=0.5)) 56 | ax122.add_patch(patches.Rectangle(xy=(0, offsets[1]), width=myisize, height=myjsize[1], facecolor="#0000FF", edgecolor="#0000FF", zorder=-10, alpha=0.5)) 57 | ax122.add_patch(patches.Rectangle(xy=(0, offsets[2]), width=myisize, height=myjsize[2], facecolor="#33AA00", edgecolor="#33AA00", zorder=-10, alpha=0.5)) 58 | abspath = os.path.realpath(__file__) 59 | dirname = os.path.dirname(abspath) 60 | filename = f"{dirname}/domain.png" 61 | print(filename) 62 | pyplot.savefig(filename) 63 | pyplot.close() 64 | 65 | if __name__ == "__main__": 66 | matplotlib.rcParams["lines.linewidth"] = 1 67 | matplotlib.rcParams["axes.linewidth"] = 5 68 | main() 69 | 70 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid1.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid2.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid3.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/grid4.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered1.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered2.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered3.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/numerical_method/spatial_discretisation/domain_setup/images/staggered4.png -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _spatial_discretization: 3 | 4 | .. include:: /references.txt 5 | 6 | ###################### 7 | Spatial Discretization 8 | ###################### 9 | 10 | In this section, we extensively discuss spatial discretizations. 11 | 12 | First, we describe how variables (coordinates, velocities, pressure, and temperature) are located within the computational domain using staggered grids. 13 | We also briefly explain the domain decomposition technique used for parallelizing the domain. 14 | 15 | Second, we address the numerical handling of equations, focusing on ambiguities in interpolations. 16 | To achieve proper discretizations, we consider a computational coordinate system with uniform grid spacings, using equations in general rectilinear orthogonal coordinates. 17 | We provide appropriate discretizations for the :ref:`governing equations `: incompressibility, momentum balance, and internal energy balance. 18 | 19 | Third, we prove that the resulting relations satisfy the desired properties in terms of the quadratic quantities :math:`k` and :math:`h`. 20 | Specifically, the advective terms conserve the net :math:`k` and :math:`h`, while the diffusive terms conduct and dissipate them, as derived :ref:`here `. 21 | Additionally, we focus on the global energy balance. 22 | For the squared velocity and the squared temperature, the source and sink terms must exactly balance in a statistically steady manner, which is not achieved unless energy consistency is fulfilled. 23 | We show that with our proper treatment, all relations are indeed satisfied numerically. 24 | 25 | Finally, the squared velocity and temperature are linked via the Nusselt number: a non-dimensional number measuring the heat transfer enhancement due to the convective effects. 26 | There are several ways to calculate the Nusselt number, which all give an identical result in theory. 27 | This relation is, not necessarily preserved from a numerical standpoint (c.f., |OSTILLAMONICO2015|). 28 | We show that this exact relation can be replicated with our energy-consistent treatment. 29 | 30 | .. toctree:: 31 | :maxdepth: 1 32 | 33 | domain_setup/main 34 | discrete_governing_equations/main 35 | quadratic_quantities/main 36 | nusselt 37 | 38 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/diffusive.rst: -------------------------------------------------------------------------------- 1 | ############### 2 | Diffusive terms 3 | ############### 4 | 5 | We utilise :ref:`the relations listed in the prerequisite ` to derive the following relations. 6 | 7 | **************** 8 | Squared velocity 9 | **************** 10 | 11 | From the wall-normal momentum balance, we obtain 12 | 13 | .. math:: 14 | 15 | - 16 | \sumzc 17 | \sumyc 18 | \sumxc 19 | \dkdis{1}{1} 20 | - 21 | \sumzc 22 | \sumyf 23 | \sumxf 24 | \dkdis{2}{1} 25 | - 26 | \sumzf 27 | \sumyc 28 | \sumxf 29 | \dkdis{3}{1}. 30 | 31 | From the stream-wise momentum balance, we obtain 32 | 33 | .. math:: 34 | 35 | - 36 | \sumzc 37 | \sumyf 38 | \sumxf 39 | \dkdis{1}{2} 40 | - 41 | \sumzc 42 | \sumyc 43 | \sumxc 44 | \dkdis{2}{2} 45 | - 46 | \sumzf 47 | \sumyf 48 | \sumxc 49 | \dkdis{3}{2}. 50 | 51 | From the span-wise momentum balance, we obtain 52 | 53 | .. math:: 54 | 55 | - 56 | \sumzf 57 | \sumyc 58 | \sumxf 59 | \dkdis{1}{3} 60 | - 61 | \sumzf 62 | \sumyf 63 | \sumxc 64 | \dkdis{2}{3} 65 | - 66 | \sumzc 67 | \sumyc 68 | \sumxc 69 | \dkdis{3}{3}. 70 | 71 | In total, all terms work to dissipate :math:`k`. 72 | 73 | ******************* 74 | Squared temperature 75 | ******************* 76 | 77 | We obtain 78 | 79 | .. math:: 80 | 81 | - 82 | \sumzc 83 | \sumyc 84 | \sumxf 85 | J 86 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 87 | \left( 88 | \frac{1}{\sfact{1}} 89 | \dif{T}{\gcs{1}} 90 | \right)^2 91 | - 92 | \sumzc 93 | \sumyf 94 | \sumxc 95 | J 96 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 97 | \left( 98 | \frac{1}{\sfact{2}} 99 | \dif{T}{\gcs{2}} 100 | \right)^2 101 | - 102 | \sumzf 103 | \sumyc 104 | \sumxc 105 | J 106 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 107 | \left( 108 | \frac{1}{\sfact{3}} 109 | \dif{T}{\gcs{3}} 110 | \right)^2 111 | 112 | as the dissipative terms, while 113 | 114 | .. math:: 115 | 116 | - 117 | \sumzc 118 | \sumyc 119 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 120 | \vat{ 121 | \left( 122 | \frac{J}{\sfact{1}} 123 | T 124 | \frac{1}{\sfact{1}} 125 | \dif{T}{\gcs{1}} 126 | \right) 127 | }{\frac{1}{2}} 128 | + 129 | \sumzc 130 | \sumyc 131 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 132 | \vat{ 133 | \left( 134 | \frac{J}{\sfact{1}} 135 | T 136 | \frac{1}{\sfact{1}} 137 | \dif{T}{\gcs{1}} 138 | \right) 139 | }{\ngp{1} + \frac{1}{2}} 140 | 141 | as the conduction on the walls. 142 | 143 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/prerequisite/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _energy_prerequisite: 3 | 4 | ############ 5 | Prerequisite 6 | ############ 7 | 8 | Discrete operators which are frequently used to derive the discrete energy relations are listed. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | x 14 | y 15 | z 16 | t 17 | 18 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/prerequisite/t.rst: -------------------------------------------------------------------------------- 1 | ############################### 2 | Relations involving temperature 3 | ############################### 4 | 5 | **************** 6 | Differentiations 7 | **************** 8 | 9 | .. math:: 10 | 11 | \sumzc 12 | \sumyc 13 | \sumxc 14 | T 15 | \dif{q}{\gcs{1}} 16 | = 17 | - 18 | \sumzc 19 | \sumyc 20 | \left( 21 | \vat{\left(T q\right)}{\frac{1}{2}} 22 | + 23 | \sumxf 24 | \dif{T}{\gcs{1}} 25 | q 26 | - 27 | \vat{\left(T q\right)}{\ngp{1} + \frac{1}{2}} 28 | \right). 29 | 30 | .. math:: 31 | 32 | \sumzc 33 | \sumyc 34 | \sumxc 35 | T 36 | \dif{q}{\gcs{2}} 37 | = 38 | - 39 | \sumzc 40 | \sumyf 41 | \sumxc 42 | \dif{T}{\gcs{2}} 43 | q. 44 | 45 | .. math:: 46 | 47 | \sumzc 48 | \sumyc 49 | \sumxc 50 | T 51 | \dif{q}{\gcs{3}} 52 | = 53 | - 54 | \sumzf 55 | \sumyc 56 | \sumxc 57 | \dif{T}{\gcs{3}} 58 | q. 59 | 60 | ******** 61 | Averages 62 | ******** 63 | 64 | .. math:: 65 | 66 | \sumzc 67 | \sumyc 68 | \sumxc 69 | T 70 | \ave{q}{\gcs{1}} 71 | = 72 | \sumzc 73 | \sumyc 74 | \left( 75 | \vat{T}{1} 76 | \frac{\vat{q}{\frac{1}{2}}}{2} 77 | + 78 | \sum_{i = \frac{3}{2}}^{\ngp{1} - \frac{1}{2}} 79 | \ave{T}{\gcs{1}} 80 | q 81 | + 82 | \vat{T}{\ngp{1}} 83 | \frac{\vat{q}{\ngp{1} + \frac{1}{2}}}{2} 84 | \right). 85 | 86 | .. math:: 87 | 88 | \sumzc 89 | \sumyc 90 | \sumxc 91 | T 92 | \ave{q}{\gcs{2}} 93 | = 94 | \sumzc 95 | \sumyf 96 | \sumxc 97 | \ave{T}{\gcs{2}} 98 | q. 99 | 100 | .. math:: 101 | 102 | \sumzc 103 | \sumyc 104 | \sumxc 105 | T 106 | \ave{q}{\gcs{3}} 107 | = 108 | \sumzf 109 | \sumyc 110 | \sumxc 111 | \ave{T}{\gcs{3}} 112 | q. 113 | 114 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/prerequisite/x.rst: -------------------------------------------------------------------------------- 1 | ######################################## 2 | Relations involving wall-normal velocity 3 | ######################################## 4 | 5 | **************** 6 | Differentiations 7 | **************** 8 | 9 | .. math:: 10 | 11 | \sumzc 12 | \sumyc 13 | \sumxf 14 | \vel{1} 15 | \dif{q}{\gcs{1}} 16 | = 17 | - 18 | \sumzc 19 | \sumyc 20 | \sumxc 21 | \dif{\vel{1}}{\gcs{1}} 22 | q, 23 | 24 | where :math:`\vat{\vel{1}}{\frac{1}{2}} = \vat{\vel{1}}{\ngp{1} + \frac{1}{2}} = 0` is used. 25 | 26 | .. math:: 27 | 28 | \sumzc 29 | \sumyc 30 | \sumxf 31 | \vel{1} 32 | \dif{q}{\gcs{2}} 33 | = 34 | - 35 | \sumzc 36 | \sumyf 37 | \sumxf 38 | \dif{\vel{1}}{\gcs{2}} 39 | q. 40 | 41 | .. math:: 42 | 43 | \sumzc 44 | \sumyc 45 | \sumxf 46 | \vel{1} 47 | \dif{q}{\gcs{3}} 48 | = 49 | - 50 | \sumzf 51 | \sumyc 52 | \sumxf 53 | \dif{\vel{1}}{\gcs{3}} 54 | q. 55 | 56 | ******** 57 | Averages 58 | ******** 59 | 60 | .. math:: 61 | 62 | \sumzc 63 | \sumyc 64 | \sumxf 65 | \vel{1} 66 | \ave{q}{\gcs{1}} 67 | = 68 | \sumzc 69 | \sumyc 70 | \sumxc 71 | \ave{\vel{1}}{\gcs{1}} 72 | q. 73 | 74 | .. math:: 75 | 76 | \sumzc 77 | \sumyc 78 | \sumxf 79 | \vel{1} 80 | \ave{q}{\gcs{2}} 81 | = 82 | \sumzc 83 | \sumyf 84 | \sumxf 85 | \ave{\vel{1}}{\gcs{2}} 86 | q. 87 | 88 | .. math:: 89 | 90 | \sumzc 91 | \sumyc 92 | \sumxf 93 | \vel{1} 94 | \ave{q}{\gcs{3}} 95 | = 96 | \sumzf 97 | \sumyc 98 | \sumxf 99 | \ave{\vel{1}}{\gcs{3}} 100 | q. 101 | 102 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/prerequisite/y.rst: -------------------------------------------------------------------------------- 1 | ######################################## 2 | Relations involving stream-wise velocity 3 | ######################################## 4 | 5 | **************** 6 | Differentiations 7 | **************** 8 | 9 | .. math:: 10 | 11 | \sumzc 12 | \sumyf 13 | \sumxc 14 | \vel{2} 15 | \dif{q}{\gcs{1}} 16 | = 17 | - 18 | \sumzc 19 | \sumyf 20 | \left( 21 | \vat{\left(\vel{2} q\right)}{\frac{1}{2}} 22 | + 23 | \sumxf 24 | \dif{\vel{2}}{\gcs{1}} 25 | q 26 | - 27 | \vat{\left(\vel{2} q\right)}{\ngp{1} + \frac{1}{2}} 28 | \right). 29 | 30 | .. math:: 31 | 32 | \sumzc 33 | \sumyf 34 | \sumxc 35 | \vel{2} 36 | \dif{q}{\gcs{2}} 37 | = 38 | - 39 | \sumzc 40 | \sumyc 41 | \sumxc 42 | \dif{\vel{2}}{\gcs{2}} 43 | q. 44 | 45 | .. math:: 46 | 47 | \sumzc 48 | \sumyf 49 | \sumxc 50 | \vel{2} 51 | \dif{q}{\gcs{3}} 52 | = 53 | - 54 | \sumzf 55 | \sumyf 56 | \sumxc 57 | \dif{\vel{2}}{\gcs{3}} 58 | q. 59 | 60 | ******** 61 | Averages 62 | ******** 63 | 64 | .. math:: 65 | 66 | \sumzc 67 | \sumyf 68 | \sumxc 69 | \vel{2} 70 | \ave{q}{\gcs{1}} 71 | = 72 | \sumzc 73 | \sumyf 74 | \left( 75 | \vat{\vel{2}}{1} 76 | \frac{\vat{q}{\frac{1}{2}}}{2} 77 | + 78 | \sum_{i = \frac{3}{2}}^{\ngp{1} - \frac{1}{2}} 79 | \ave{\vel{2}}{\gcs{1}} 80 | q 81 | + 82 | \vat{\vel{2}}{\ngp{1}} 83 | \frac{\vat{q}{\ngp{1} + \frac{1}{2}}}{2} 84 | \right). 85 | 86 | .. math:: 87 | 88 | \sumzc 89 | \sumyf 90 | \sumxc 91 | \vel{2} 92 | \ave{q}{\gcs{2}} 93 | = 94 | \sumzc 95 | \sumyc 96 | \sumxc 97 | \ave{\vel{2}}{\gcs{2}} 98 | q. 99 | 100 | .. math:: 101 | 102 | \sumzc 103 | \sumyf 104 | \sumxc 105 | \vel{2} 106 | \ave{q}{\gcs{3}} 107 | = 108 | \sumzf 109 | \sumyf 110 | \sumxc 111 | \ave{\vel{2}}{\gcs{3}} 112 | q. 113 | 114 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/prerequisite/z.rst: -------------------------------------------------------------------------------- 1 | ###################################### 2 | Relations involving span-wise velocity 3 | ###################################### 4 | 5 | **************** 6 | Differentiations 7 | **************** 8 | 9 | .. math:: 10 | 11 | \sumzf 12 | \sumyc 13 | \sumxc 14 | \vel{3} 15 | \dif{q}{\gcs{1}} 16 | = 17 | - 18 | \sumzf 19 | \sumyc 20 | \sumxf 21 | \dif{\vel{3}}{\gcs{1}} 22 | q, 23 | 24 | where :math:`\vat{\vel{3}}{\frac{1}{2},\ccindex{j},\cpindex{k}} = \vat{\vel{3}}{\ngp{1} + \frac{1}{2},\ccindex{j},\cpindex{k}} = 0` is assumed (i.e., the walls do not move in the :math:`z` direction). 25 | 26 | .. math:: 27 | 28 | \sumzf 29 | \sumyc 30 | \sumxc 31 | \vel{3} 32 | \dif{q}{\gcs{2}} 33 | = 34 | - 35 | \sumzf 36 | \sumyf 37 | \sumxc 38 | \dif{\vel{3}}{\gcs{2}} 39 | q. 40 | 41 | .. math:: 42 | 43 | \sumzf 44 | \sumyc 45 | \sumxc 46 | \vel{3} 47 | \dif{q}{\gcs{3}} 48 | = 49 | - 50 | \sumzc 51 | \sumyc 52 | \sumxc 53 | \dif{\vel{3}}{\gcs{3}} 54 | q. 55 | 56 | ******** 57 | Averages 58 | ******** 59 | 60 | .. math:: 61 | 62 | \sumzf 63 | \sumyc 64 | \sumxc 65 | \vel{3} 66 | \ave{q}{\gcs{1}} 67 | = 68 | \sumzf 69 | \sumyc 70 | \left( 71 | \vat{\vel{3}}{1} 72 | \frac{\vat{q}{\frac{1}{2}}}{2} 73 | + 74 | \sum_{i = \frac{3}{2}}^{\ngp{1} - \frac{1}{2}} 75 | \ave{\vel{3}}{\gcs{1}} 76 | q 77 | + 78 | \vat{\vel{3}}{\ngp{1}} 79 | \frac{\vat{q}{\ngp{1} + \frac{1}{2}}}{2} 80 | \right). 81 | 82 | 83 | .. math:: 84 | 85 | \sumzf 86 | \sumyc 87 | \sumxc 88 | \vel{3} 89 | \ave{q}{\gcs{2}} 90 | = 91 | \sumzf 92 | \sumyf 93 | \sumxc 94 | \ave{\vel{3}}{\gcs{2}} 95 | q. 96 | 97 | .. math:: 98 | 99 | \sumzf 100 | \sumyc 101 | \sumxc 102 | \vel{3} 103 | \ave{q}{\gcs{3}} 104 | = 105 | \sumzc 106 | \sumyc 107 | \sumxc 108 | \ave{\vel{3}}{\gcs{3}} 109 | q. 110 | 111 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/derivation/pressure_gradient.rst: -------------------------------------------------------------------------------- 1 | ####################### 2 | Pressure-gradient terms 3 | ####################### 4 | 5 | The pressure-gradient terms: 6 | 7 | .. math:: 8 | 9 | - 10 | \frac{1}{\sfact{i}} 11 | \dif{p}{\gcs{i}} 12 | 13 | contribute to the energy balance as follows: 14 | 15 | .. math:: 16 | 17 | \newcommand{\tmp}[1]{ 18 | J 19 | \vel{#1} 20 | \frac{1}{\sfact{#1}} 21 | \dif{p}{\gcs{#1}} 22 | = 23 | \sumzc 24 | \sumyc 25 | \sumxc 26 | J 27 | p 28 | \frac{1}{J} 29 | \dif{ 30 | \left( 31 | \frac{J}{\sfact{#1}} 32 | \vel{#1} 33 | \right) 34 | }{\gcs{#1}} 35 | } 36 | - 37 | \sumzc 38 | \sumyc 39 | \sumxf 40 | \tmp{1}, 41 | 42 | - 43 | \sumzc 44 | \sumyf 45 | \sumxc 46 | \tmp{2}, 47 | 48 | - 49 | \sumzf 50 | \sumyc 51 | \sumxc 52 | \tmp{3}. 53 | 54 | The sum of these three relations is 55 | 56 | .. math:: 57 | 58 | \sumzc 59 | \sumyc 60 | \sumxc 61 | J 62 | p 63 | \left\{ 64 | \ddiv{1} 65 | + 66 | \ddiv{2} 67 | + 68 | \ddiv{3} 69 | \right\}, 70 | 71 | which is zero because the component inside the wavy parentheses is :ref:`the incompressibility constraint `. 72 | 73 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/squared_temperature.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _global_balance_squared_temperature: 3 | 4 | ##################################### 5 | Global Balance of Squared Temperature 6 | ##################################### 7 | 8 | ****************** 9 | Sink (Dissipation) 10 | ****************** 11 | 12 | There are 3 terms dissipating the squared temperature, which are computed separately. 13 | 14 | .. math:: 15 | 16 | \sumzc 17 | \sumyc 18 | \sumxf 19 | \dhdis{1} 20 | 21 | .. myliteralinclude:: /../../src/logging/dissipated_squared_temperature.c 22 | :language: c 23 | :tag: dtdx component 24 | 25 | .. math:: 26 | 27 | \sumzc 28 | \sumyf 29 | \sumxc 30 | \dhdis{2} 31 | 32 | .. myliteralinclude:: /../../src/logging/dissipated_squared_temperature.c 33 | :language: c 34 | :tag: dtdy component 35 | 36 | .. math:: 37 | 38 | \sumzf 39 | \sumyc 40 | \sumxc 41 | \dhdis{3} 42 | 43 | .. myliteralinclude:: /../../src/logging/dissipated_squared_temperature.c 44 | :language: c 45 | :tag: dtdz component 46 | 47 | ****************** 48 | Source (Injection) 49 | ****************** 50 | 51 | .. math:: 52 | 53 | \dhinjall 54 | 55 | injects squared temperature, which will be elaborated :ref:`later `. 56 | 57 | -------------------------------------------------------------------------------- /docs/source/numerical_method/spatial_discretisation/quadratic_quantities/squared_velocity.rst: -------------------------------------------------------------------------------- 1 | ################################## 2 | Global Balance of Squared Velocity 3 | ################################## 4 | 5 | ****************** 6 | Sink (Dissipation) 7 | ****************** 8 | 9 | There are 9 terms dissipating the squared velocity, which are computed separately. 10 | 11 | .. math:: 12 | 13 | \sumzc 14 | \sumyc 15 | \sumxc 16 | \dkdis{1}{1} 17 | 18 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 19 | :language: c 20 | :tag: duxdx component 21 | 22 | .. math:: 23 | 24 | \sumzc 25 | \sumyf 26 | \sumxf 27 | \dkdis{2}{1} 28 | 29 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 30 | :language: c 31 | :tag: duxdy component 32 | 33 | .. math:: 34 | 35 | \sumzf 36 | \sumyc 37 | \sumxf 38 | \dkdis{3}{1} 39 | 40 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 41 | :language: c 42 | :tag: duxdz component 43 | 44 | .. math:: 45 | 46 | \sumzc 47 | \sumyf 48 | \sumxf 49 | \dkdis{1}{2} 50 | 51 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 52 | :language: c 53 | :tag: duydx component 54 | 55 | .. math:: 56 | 57 | \sumzc 58 | \sumyc 59 | \sumxc 60 | \dkdis{2}{2} 61 | 62 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 63 | :language: c 64 | :tag: duydy component 65 | 66 | .. math:: 67 | 68 | \sumzf 69 | \sumyf 70 | \sumxc 71 | \dkdis{3}{2} 72 | 73 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 74 | :language: c 75 | :tag: duydz component 76 | 77 | .. math:: 78 | 79 | \sumzf 80 | \sumyc 81 | \sumxf 82 | \dkdis{1}{3} 83 | 84 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 85 | :language: c 86 | :tag: duzdx component 87 | 88 | .. math:: 89 | 90 | \sumzf 91 | \sumyf 92 | \sumxc 93 | \dkdis{2}{3} 94 | 95 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 96 | :language: c 97 | :tag: duzdy component 98 | 99 | .. math:: 100 | 101 | \sumzc 102 | \sumyc 103 | \sumxc 104 | \dkdis{3}{3} 105 | 106 | .. myliteralinclude:: /../../src/logging/dissipated_squared_velocity.c 107 | :language: c 108 | :tag: duzdz component 109 | 110 | ****************** 111 | Source (Injection) 112 | ****************** 113 | 114 | .. math:: 115 | 116 | \sumzc 117 | \sumyc 118 | \sumxc 119 | J 120 | \vel{1} 121 | \ave{T}{\gcs{1}} 122 | 123 | increases the total amount of the squared velocity. 124 | Physically this term accounts for the kinetic energy injection due to the buoyancy effects. 125 | 126 | This quantity is implemented to monitor as follows: 127 | 128 | .. myliteralinclude:: /../../src/logging/injected_squared_velocity.c 129 | :language: c 130 | :tag: compute injected squared velocity 131 | 132 | -------------------------------------------------------------------------------- /docs/source/numerical_method/tdm.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _tdm: 3 | 4 | ########################## 5 | Tri-diagonal Matrix Solver 6 | ########################## 7 | 8 | .. seealso:: 9 | 10 | `Thomas Algorithm `_. 11 | 12 | -------------------------------------------------------------------------------- /docs/source/numerical_method/temporal_discretisation/derivation/cn.rst: -------------------------------------------------------------------------------- 1 | Because of 2 | 3 | .. math:: 4 | 5 | g^{n+1} 6 | = 7 | \frac{d\newvar{f}}{dt} 8 | = 9 | \frac{df^n}{dt} + \frac{d^2f^n}{dt^2} \Delta t + \frac{1}{2} \frac{d^3f^n}{dt^3} \Delta t^2 + \oerror{3}, 10 | 11 | we find 12 | 13 | .. math:: 14 | 15 | \newvar{f} 16 | & 17 | = 18 | f^n 19 | + 20 | \frac{1}{2} 21 | \frac{df^n}{dt} 22 | \Delta t 23 | + 24 | \frac{1}{2} \left( \frac{df^n}{dt} + \frac{d^2f^n}{dt^2} \Delta t + \frac{1}{2} \frac{d^3f^n}{dt^3} \Delta t^2 + \frac{df^n}{dt} \right) \Delta t 25 | 26 | & 27 | = 28 | f^n + \frac{df^n}{dt} \Delta t + \frac{1}{2} \frac{d^2f^n}{dt^2} \Delta t^2 + \oerror{3}, 29 | 30 | indicating that this scheme has the third-order accuracy (locally) and the second-order accuracy (globally). 31 | 32 | -------------------------------------------------------------------------------- /docs/source/numerical_method/temporal_discretisation/derivation/rk.rst: -------------------------------------------------------------------------------- 1 | Because of 2 | 3 | .. math:: 4 | 5 | f^{k+1} 6 | = 7 | f^{k } 8 | + 9 | \alpha^k g^{k } \Delta t 10 | + 11 | \beta^k g^{k-1} \Delta t, 12 | 13 | we find 14 | 15 | .. math:: 16 | 17 | g^{k+1} 18 | = 19 | \frac{df^{k+1}}{dt} 20 | = 21 | \frac{df^k}{dt} 22 | + 23 | \alpha^k \frac{d^2f^k}{dt^2} \Delta t 24 | + 25 | \beta^k \frac{d^2f^{k-1}}{dt^2} \Delta t. 26 | 27 | We use this relation repeatedly. 28 | For :math:`k = 1`, we have 29 | 30 | .. math:: 31 | 32 | f^1 33 | = 34 | f^n 35 | + 36 | \alpha^0 g^n \Delta t 37 | = 38 | f^n + \alpha^0 \frac{df^n}{dt} \Delta t, 39 | 40 | whose derivation leads to 41 | 42 | .. math:: 43 | 44 | g^1 45 | = 46 | \frac{df^n}{dt} 47 | + 48 | \alpha^0 \frac{d^2f^n}{dt^2} \Delta t. 49 | 50 | Note that :math:`k = 0` corresponds to :math:`n` (old information). 51 | For :math:`k = 2`, we have 52 | 53 | .. math:: 54 | 55 | f^2 56 | & 57 | = 58 | f^1 59 | + 60 | \alpha^1 g^1 \Delta t + \beta^1 g^0 \Delta t 61 | 62 | & 63 | = 64 | f^n 65 | + 66 | \alpha^0 \frac{df^n}{dt} \Delta t + \alpha^1 \left( \frac{df^n}{dt} + \alpha^0 \frac{d^2f^n}{dt^2} \Delta t \right) \Delta t + \beta^1 \frac{df^n}{dt} \Delta t, 67 | 68 | & 69 | = 70 | f^n + \left( \alpha^0 + \alpha^1 + \beta^1 \right) \frac{df^n}{dt} \Delta t + \alpha^0 \alpha^1 \frac{d^2f^n}{dt^2} \Delta t^2, 71 | 72 | whose derivation leads to 73 | 74 | .. math:: 75 | 76 | g^2 77 | = 78 | \frac{df^n}{dt} + \left( \alpha^0 + \alpha^1 + \beta^1 \right) \frac{d^2f^n}{dt^2} \Delta t + \alpha^0 \alpha^1 \frac{d^3f^n}{dt^3} \Delta t^2. 79 | 80 | For :math:`k = 3`, we have 81 | 82 | .. math:: 83 | 84 | f^3 85 | & 86 | = 87 | f^2 + \alpha^2 g^2 \Delta t + \beta^2 g^1 \Delta t 88 | 89 | & 90 | = 91 | f^n + \left( \alpha^0 + \alpha^1 + \beta^1 \right) \frac{df^n}{dt} \Delta t + \alpha^0 \alpha^1 \frac{d^2f^n}{dt^2} \Delta t^2 92 | + 93 | \alpha^2 \left( \frac{df^n}{dt} + \left( \alpha^0 + \alpha^1 + \beta^1 \right) \frac{d^2f^n}{dt^2} \Delta t + \alpha^0 \alpha^1 \frac{d^3f^n}{dt^3} \Delta t^2 \right) \Delta t 94 | + 95 | \beta^2 \left( \frac{df^n}{dt} + \alpha^0 \frac{d^2f^n}{dt^2} \Delta t \right) \Delta t, 96 | 97 | & 98 | = 99 | f^n + \left( \alpha^0 + \alpha^1 + \beta^1 + \alpha^2 + \beta^2 \right) \frac{df^n}{dt} \Delta t 100 | + 101 | \left( \alpha^0 \alpha^1 + \alpha^0 \alpha^2 + \alpha^1 \alpha^2 + \alpha^2 \beta^1 + \alpha^0 \beta^2 \right) \frac{d^2f^n}{dt^2} \Delta t^2 102 | + 103 | \oerror{3} 104 | 105 | & 106 | = 107 | f^n + \frac{df^n}{dt} \Delta t + \frac{1}{2} \frac{d^2f^n}{dt^2} \Delta t^2 + \oerror{3}. 108 | 109 | Since :math:`k = 3` corresponds to :math:`n + 1` (new information), we find 110 | 111 | .. math:: 112 | 113 | \newvar{f} 114 | = 115 | f^n 116 | + 117 | \frac{df^n}{dt} \Delta t 118 | + 119 | \frac{1}{2} \frac{d^2f^n}{dt^2} \left( \Delta t^2 \right) 120 | + 121 | \oerror{3}, 122 | 123 | indicating that this scheme has the third-order accuracy (locally) and the second-order accuracy (globally). 124 | 125 | -------------------------------------------------------------------------------- /docs/source/numerical_method/temporal_discretisation/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _temporal_discretization: 3 | 4 | .. include:: /references.txt 5 | 6 | ####################### 7 | Temporal Discretization 8 | ####################### 9 | 10 | In this section, we discuss how :ref:`the governing equations ` are integrated over time. 11 | 12 | First, we briefly introduce several explicit and implicit schemes for integrating general ordinary differential equations over time. 13 | 14 | We then elaborate on the implicit treatment applied to the diffusive terms to avoid severe restrictions on time-step sizes. 15 | 16 | These fundamental techniques are first applied to the internal energy equation (evolution of temperature) due to its simplicity, and are then extended to the integration of the velocity field, where the momentum balance is integrated while keeping the incompressibility constraint. 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | 21 | time_marcher 22 | implicit 23 | temperature 24 | momentum 25 | 26 | -------------------------------------------------------------------------------- /docs/source/numerical_method/temporal_discretisation/temperature.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _temperature_integration: 3 | 4 | .. include:: /references.txt 5 | 6 | ####################### 7 | Internal Energy Balance 8 | ####################### 9 | 10 | The equation of the internal energy is 11 | 12 | .. math:: 13 | 14 | \pder{T}{t} 15 | = 16 | A 17 | + 18 | D_x 19 | + 20 | D_y 21 | + 22 | D_z, 23 | 24 | where :math:`A` is the advective terms: 25 | 26 | .. math:: 27 | 28 | A 29 | \equiv 30 | - 31 | \dtempadv{1} 32 | - 33 | \dtempadv{2} 34 | - 35 | \dtempadv{3}, 36 | 37 | while :math:`D_i` is the diffusive term involving spatial differentiation in the :math:`i`-th direction: 38 | 39 | .. math:: 40 | 41 | D_i 42 | \equiv 43 | \dtempdif{i} 44 | \,\, 45 | (\text{no summation over}\,i). 46 | 47 | See :ref:`the spatial discretization `. 48 | 49 | The temporal discretization for each Runge-Kutta iteration leads to 50 | 51 | .. math:: 52 | 53 | \Delta T 54 | & 55 | = 56 | \alpha^k \Delta t \left( A^{k } + D^{k } \right) 57 | + 58 | \beta^k \Delta t \left( A^{k-1} + D^{k-1} \right), 59 | 60 | T^{k+1} 61 | & 62 | = 63 | T^k 64 | + 65 | \Delta T, 66 | 67 | when all diffusive terms are treated explicitly, while 68 | 69 | .. math:: 70 | 71 | \newcommand{\lap}[2]{ 72 | {#2} \gamma^k \Delta t 73 | \frac{1}{\sqrt{Pr} \sqrt{Ra}} 74 | \frac{1}{J} 75 | \dif{}{\gcs{#1}} 76 | \left( 77 | \frac{J}{\sfact{#1}} 78 | \frac{1}{\sfact{#1}} 79 | \dif{}{\gcs{#1}} 80 | \right) 81 | } 82 | \Delta T 83 | & 84 | = 85 | \alpha^k \Delta t A^{k } 86 | + 87 | \beta^k \Delta t A^{k-1} 88 | + 89 | \gamma^k \Delta t D^{k }, 90 | 91 | T^{k+1} 92 | & 93 | = 94 | T^k 95 | + 96 | \left\{ 97 | 1 98 | - 99 | \lap{3}{c} 100 | \right\}^{-1} 101 | \left\{ 102 | 1 103 | - 104 | \lap{2}{c} 105 | \right\}^{-1} 106 | \left\{ 107 | 1 108 | - 109 | \lap{1}{c} 110 | \right\}^{-1} 111 | \Delta T, 112 | 113 | when all diffusive terms are treated implicitly. 114 | 115 | Diffusive terms are sometimes partially treated implicitly (c.f., |VANDERPOEL2015|). 116 | When only the diffusive term in :math:`x` direction is implicitly treated (the default configuration in this project), we have 117 | 118 | .. math:: 119 | 120 | \Delta T 121 | & 122 | = 123 | \alpha^k \Delta t \left( A^{k } + D_2^{k } + D_3^{k } \right) 124 | + 125 | \beta^k \Delta t \left( A^{k-1} + D_2^{k-1} + D_3^{k-1} \right) 126 | + 127 | \gamma^k \Delta t D_1^{k }, 128 | 129 | T^{k+1} 130 | & 131 | = 132 | T^k 133 | + 134 | \left\{ 135 | 1 136 | - 137 | \lap{1}{c} 138 | \right\}^{-1} 139 | \Delta T. 140 | 141 | First, the explicit and implicit terms are calculated and stored to the corresponding buffers: 142 | 143 | .. myliteralinclude:: /../../src/fluid/predict/t.c 144 | :language: c 145 | :tag: compute right-hand-side terms, which are added to buffers 146 | 147 | The buffers are used to compute :math:`\Delta T`: 148 | 149 | .. myliteralinclude:: /../../src/fluid/predict/t.c 150 | :language: c 151 | :tag: compute increments 152 | 153 | When necessary, linear systems are solved to take care of the implicit treatments: 154 | 155 | .. myliteralinclude:: /../../src/fluid/predict/t.c 156 | :language: c 157 | :tag: solve linear systems in x 158 | 159 | .. myliteralinclude:: /../../src/fluid/predict/t.c 160 | :language: c 161 | :tag: solve linear systems in y 162 | 163 | .. myliteralinclude:: /../../src/fluid/predict/t.c 164 | :language: c 165 | :tag: solve linear systems in z 166 | 167 | Finally the temperature field is updated: 168 | 169 | .. myliteralinclude:: /../../src/fluid/predict/t.c 170 | :language: c 171 | :tag: update temperature field 172 | 173 | -------------------------------------------------------------------------------- /docs/source/references.rst: -------------------------------------------------------------------------------- 1 | ########## 2 | References 3 | ########## 4 | 5 | .. include:: /references.txt 6 | 7 | * |AMSDEN1970| 8 | * |RAI1991| 9 | * |DUKOWICZ1992| 10 | * |VERZICCO1996| 11 | * |MORINISHI1998| 12 | * |KAJISHIMA1999| 13 | * |HORVATH2000| 14 | * |HAM2002| 15 | * |VERSTAPPEN2003| 16 | * |VANDERPOEL2013| 17 | * |VANDERPOEL2015| 18 | * |OSTILLAMONICO2015| 19 | * |KAJISHIMA2017| 20 | * |COSTA2018| 21 | * |COPPOLA2019| 22 | -------------------------------------------------------------------------------- /docs/source/references.txt: -------------------------------------------------------------------------------- 1 | .. |AMSDEN1970| replace:: Amsden and Harlow, *J. Comput. Phys.* (**6**), 1970 2 | .. |RAI1991| replace:: Rai and Moin, *J. Comput. Phys.* (**96**), 1991 3 | .. |DUKOWICZ1992| replace:: Dukowicz and Dvinsky, *J. Comput. Phys.* (**102**), 1992 4 | .. |VERZICCO1996| replace:: Verzicco and Orlandi, *J. Comput. Phys.* (**123**), 1996 5 | .. |MORINISHI1998| replace:: Morinishi et al., *J. Comput. Phys.* (**143**), 1998 6 | .. |KAJISHIMA1999| replace:: Kajishima, Trans. *JSME* (**65-633, 1607**), 1999 (in Japanese) 7 | .. |HORVATH2000| replace:: Horváth, *RANA* (**0015**), 2000 8 | .. |HAM2002| replace:: Ham et al., *J. Comput. Phys.* (**177**), 2002 9 | .. |VERSTAPPEN2003| replace:: Verstappen and Veldman, *J. Comput. Phys.* (**187**), 2003 10 | .. |VANDERPOEL2013| replace:: van der Poel et al., *J. Fluid Mech.* (**736**), 2013 11 | .. |VANDERPOEL2015| replace:: van der Poel et al., *Comput. Fluids* (**116**), 2015 12 | .. |OSTILLAMONICO2015| replace:: Ostilla-Monico et al., *J. Comput. Phys* (**301**), 2015 13 | .. |KAJISHIMA2017| replace:: Kajishima and Taira, Springer International Publishing, 2017 14 | .. |COSTA2018| replace:: Costa, *Comput. Math Appl.* (**76**), 2018 15 | .. |COPPOLA2019| replace:: Coppola et al., *Appl. Mech. Rev.* (**71**), 2019 16 | -------------------------------------------------------------------------------- /docs/source/snapshot2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/snapshot2d.png -------------------------------------------------------------------------------- /docs/source/snapshot3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/snapshot3d.png -------------------------------------------------------------------------------- /docs/source/thumbnail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleNSSolver/34fbcd8de2322cfd1e97779a48f8ac16a513ee3d/docs/source/thumbnail.gif -------------------------------------------------------------------------------- /exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## temporal information 4 | # maximum duration (in free-fall time) 5 | export timemax=2.0e+2 6 | # maximum duration (in wall time [s]) 7 | export wtimemax=6.0e+2 8 | # logging rate (in free-fall time) 9 | export log_rate=5.0e-1 10 | # save rate (in free-fall time) 11 | export save_rate=2.0e+1 12 | # save after (in free-fall time) 13 | export save_after=0.0e+0 14 | # statistics collection rate (in free-fall time) 15 | export stat_rate=1.0e-1 16 | # statistics collection after (in free-fall time) 17 | export stat_after=1.0e+2 18 | 19 | ## safety factors to decide time step size 20 | ## for advective and diffusive terms 21 | export coef_dt_adv=0.95 22 | export coef_dt_dif=0.95 23 | 24 | ## physical parameters 25 | export Ra=1.0e+8 26 | export Pr=1.0e+1 27 | 28 | # give name of the directory in which the initial conditions 29 | # (incl. domain size etc.) are stored as an argument 30 | dirname_ic=initial_condition/output 31 | 32 | mpirun -n 2 --oversubscribe ./a.out ${dirname_ic} 33 | -------------------------------------------------------------------------------- /include/array.h: -------------------------------------------------------------------------------- 1 | #if !defined(ARRAY_H) 2 | #define ARRAY_H 3 | 4 | // struct and methods for multi-dimensional arrays 5 | // distributed among multiple processes 6 | 7 | #include 8 | #include "domain.h" 9 | 10 | typedef struct { 11 | // size of each element 12 | size_t size; 13 | // number of additional cells w.r.t. no-halo array 14 | // i.e. 0th elements: [1 : mysizes[0]] 15 | // 1st elements: [1 : mysizes[1]] 16 | // 2nd elements: [1 : mysizes[2]] 17 | // ... 18 | int (* nadds)[2]; 19 | // total size of local array (i.e. product of mysizes) 20 | size_t datasize; 21 | // pointer to the raw local array 22 | void * data; 23 | } array_t; 24 | 25 | typedef struct { 26 | // allocate array and store its size information 27 | int (* const create)( 28 | const domain_t * domain, 29 | const int nadds[NDIMS][2], 30 | const size_t size, 31 | array_t * array 32 | ); 33 | // clean-up local memory to store the array 34 | int (* const destroy)( 35 | array_t * array 36 | ); 37 | // load array from NPY file 38 | int (* const load)( 39 | const domain_t * domain, 40 | const char dirname[], 41 | const char dsetname[], 42 | const char dtype[], 43 | array_t * array 44 | ); 45 | // save array to NPY file 46 | int (* const dump)( 47 | const domain_t * domain, 48 | const char dirname[], 49 | const char dsetname[], 50 | const char dtype[], 51 | const array_t * array 52 | ); 53 | } array_method_t; 54 | 55 | extern const array_method_t array; 56 | 57 | #endif // ARRAY_H 58 | -------------------------------------------------------------------------------- /include/array_macros/domain/hxxc.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_HXXC_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_HXXC_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0] 7 | #define HXXC(I) (hxxc[(I-1)]) 8 | #define HXXC_NADDS (int [2]){0, 0} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_HXXC_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/hxxf.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_HXXF_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_HXXF_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1] 7 | #define HXXF(I) (hxxf[(I-1)]) 8 | #define HXXF_NADDS (int [2]){0, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_HXXF_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/jdxc.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_JDXC_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_JDXC_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0] 7 | #define JDXC(I) (jdxc[(I-1)]) 8 | #define JDXC_NADDS (int [2]){0, 0} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_JDXC_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/jdxf.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_JDXF_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_JDXF_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1] 7 | #define JDXF(I) (jdxf[(I-1)]) 8 | #define JDXF_NADDS (int [2]){0, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_JDXF_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/xc.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_XC_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_XC_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1] 7 | #define XC(I) (xc[(I )]) 8 | #define XC_NADDS (int [2]){1, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_XC_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/xf.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_XF_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_XF_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1] 7 | #define XF(I) (xf[(I-1)]) 8 | #define XF_NADDS (int [2]){0, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_XF_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/p.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_P_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_P_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [0 : jsize+1] 7 | #define P(I, J) (p[(I ) + (isize+2) * (J )]) 8 | #define P_NADDS (int [NDIMS][2]){ {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_P_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/psi.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_PSI_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_PSI_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [0 : jsize+1] 7 | #define PSI(I, J) (psi[(I ) + (isize+2) * (J )]) 8 | #define PSI_NADDS (int [NDIMS][2]){ {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_PSI_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/srct.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_SRCT_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_SRCT_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [1 : jsize+0] 7 | #define SRCT(I, J) (srct[(I-1) + (isize+0) * (J-1)]) 8 | #define SRCT_NADDS (int [NDIMS][2]){ {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_SRCT_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/srcux.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_SRCUX_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_SRCUX_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [2 : isize+0], [1 : jsize+0] 7 | #define SRCUX(I, J) (srcux[(I-2) + (isize-1) * (J-1)]) 8 | #define SRCUX_NADDS (int [NDIMS][2]){ {-1, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_SRCUX_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/srcuy.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_SRCUY_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_SRCUY_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [1 : jsize+0] 7 | #define SRCUY(I, J) (srcuy[(I-1) + (isize+0) * (J-1)]) 8 | #define SRCUY_NADDS (int [NDIMS][2]){ {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_SRCUY_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/srcuz.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_SRCUZ_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_SRCUZ_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | #endif // INCLUDE_ARRAY_MACROS_FLUID_SRCUZ_H 7 | -------------------------------------------------------------------------------- /include/array_macros/fluid/t.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_T_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_T_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [0 : jsize+1] 7 | #define T(I, J) (t[(I ) + (isize+2) * (J )]) 8 | #define T_NADDS (int [NDIMS][2]){ {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_T_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/ux.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_UX_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_UX_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1] 7 | #define UX(I, J) (ux[(I-1) + (isize+1) * (J )]) 8 | #define UX_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_UX_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/uy.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_UY_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_UY_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [0 : jsize+1] 7 | #define UY(I, J) (uy[(I ) + (isize+2) * (J )]) 8 | #define UY_NADDS (int [NDIMS][2]){ {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_UY_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/uz.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_UZ_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_UZ_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | #endif // INCLUDE_ARRAY_MACROS_FLUID_UZ_H 7 | -------------------------------------------------------------------------------- /include/array_macros/statistics/adv.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_ADV_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_ADV_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [1 : jsize+0] 7 | #define ADV(I, J) (adv[(I-1) + (isize+1) * (J-1)]) 8 | #define ADV_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_ADV_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/dif.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_DIF_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_DIF_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [1 : jsize+0] 7 | #define DIF(I, J) (dif[(I-1) + (isize+1) * (J-1)]) 8 | #define DIF_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_DIF_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/t1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_T1_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_T1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [1 : jsize+0] 7 | #define T1(I, J) (t1[(I ) + (isize+2) * (J-1)]) 8 | #define T1_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_T1_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/t2.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_T2_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_T2_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [1 : jsize+0] 7 | #define T2(I, J) (t2[(I ) + (isize+2) * (J-1)]) 8 | #define T2_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_T2_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/ux1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UX1_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UX1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [1 : jsize+0] 7 | #define UX1(I, J) (ux1[(I-1) + (isize+1) * (J-1)]) 8 | #define UX1_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UX1_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/ux2.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UX2_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UX2_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [1 : jsize+0] 7 | #define UX2(I, J) (ux2[(I-1) + (isize+1) * (J-1)]) 8 | #define UX2_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UX2_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/uy1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UY1_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UY1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [1 : jsize+0] 7 | #define UY1(I, J) (uy1[(I ) + (isize+2) * (J-1)]) 8 | #define UY1_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UY1_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/uy2.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UY2_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UY2_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1], [1 : jsize+0] 7 | #define UY2(I, J) (uy2[(I ) + (isize+2) * (J-1)]) 8 | #define UY2_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UY2_H 11 | -------------------------------------------------------------------------------- /include/array_macros/statistics/uz1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UZ1_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UZ1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UZ1_H 7 | -------------------------------------------------------------------------------- /include/array_macros/statistics/uz2.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_STATISTICS_UZ2_H) 2 | #define INCLUDE_ARRAY_MACROS_STATISTICS_UZ2_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UZ2_H 7 | -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | #if !defined(CONFIG_H) 2 | #define CONFIG_H 3 | 4 | typedef struct { 5 | // getters for a double-precision value 6 | int (* const get_double)( 7 | const char dsetname[], 8 | double * value 9 | ); 10 | } config_t; 11 | 12 | extern const config_t config; 13 | 14 | #endif // CONFIG_H 15 | -------------------------------------------------------------------------------- /include/decide_dt.h: -------------------------------------------------------------------------------- 1 | #if !defined(DECIDE_DT_H) 2 | #define DECIDE_DT_H 3 | 4 | // decide next time step size 5 | extern int decide_dt( 6 | const domain_t * domain, 7 | const fluid_t * fluid, 8 | double * dt 9 | ); 10 | 11 | #endif // DECIDE_DT_H 12 | -------------------------------------------------------------------------------- /include/domain.h: -------------------------------------------------------------------------------- 1 | #if !defined(DOMAIN_H) 2 | #define DOMAIN_H 3 | 4 | #include "sdecomp.h" 5 | 6 | // definition of a structure domain_t 7 | /** 8 | * @struct domain_t 9 | * @brief struct storing parameters relevant to spatial domain 10 | * @var info : MPI domain decomposition 11 | * @var glsizes : global number of grid points in each direction 12 | * @var mysizes : local (my) number of grid points in each direction 13 | * @var offsets : offsets to my starting index in each direction 14 | * @var lengths : domain size in each direction 15 | * @var xf, xc : cell-face and cell-center locations in x direction 16 | * @var hxxf, hxxc : wall-normal scale factors at faces and centers 17 | * @var hy, hz : scale factors in the homogeneous directions 18 | */ 19 | typedef struct { 20 | sdecomp_info_t * info; 21 | size_t glsizes[NDIMS]; 22 | size_t mysizes[NDIMS]; 23 | size_t offsets[NDIMS]; 24 | double lengths[NDIMS]; 25 | double * restrict xf, * restrict xc; 26 | double * restrict hxxf, * restrict hxxc; 27 | double hy; 28 | double * restrict jdxf, * restrict jdxc; 29 | } domain_t; 30 | 31 | // constructor 32 | extern int domain_init( 33 | const char dirname_ic[], 34 | domain_t * domain 35 | ); 36 | 37 | // save members which are necessary to restart 38 | extern int domain_save( 39 | const char dirname[], 40 | const domain_t * domain 41 | ); 42 | 43 | #endif // DOMAIN_H 44 | -------------------------------------------------------------------------------- /include/fileio.h: -------------------------------------------------------------------------------- 1 | #if !defined(FILEIO_H) 2 | #define FILEIO_H 3 | 4 | #include // FILE, size_t 5 | #include // MPI_Datatype 6 | 7 | typedef struct { 8 | // NPY datatypes, which are embedded in NPY files ("dtype" argument) 9 | // they are declared here and defined in src/fileio.c 10 | // NOTE: size (x-byte) may be wrong, depending on the architecture 11 | // 8-byte little-endian unsigned integer 12 | const char * npy_size_t; 13 | // 8-byte little-endian floating point 14 | const char * npy_double; 15 | // initialiser 16 | int (* const init)( 17 | void 18 | ); 19 | // general-purpose file opener 20 | FILE * (* const fopen)( 21 | const char * path, 22 | const char * mode 23 | ); 24 | // general-purpose file closer 25 | int (* const fclose)( 26 | FILE * stream 27 | ); 28 | // prepare directory to be stored 29 | int (* const mkdir)( 30 | const char dirname[] 31 | ); 32 | // NPY serial read (called by one process) 33 | int (* const r_serial)( 34 | const char dirname[], 35 | const char dsetname[], 36 | const size_t ndims, 37 | const size_t * shape, 38 | const char dtype[], 39 | const size_t size, 40 | void * data 41 | ); 42 | // NPY serial write (called by one process) 43 | int (* const w_serial)( 44 | const char dirname[], 45 | const char dsetname[], 46 | const size_t ndims, 47 | const size_t * shape, 48 | const char dtype[], 49 | const size_t size, 50 | const void * data 51 | ); 52 | // NPY parallel read of N-dimensional array (called by all processes) 53 | int (* const r_nd_parallel)( 54 | const MPI_Comm comm, 55 | const char dirname[], 56 | const char dsetname[], 57 | const size_t ndims, 58 | const int * array_of_sizes, 59 | const int * array_of_subsizes, 60 | const int * array_of_starts, 61 | const char dtype[], 62 | const size_t size, 63 | void * data 64 | ); 65 | // NPY parallel write of N-dimensional array (called by all processes) 66 | int (* const w_nd_parallel)( 67 | const MPI_Comm comm, 68 | const char dirname[], 69 | const char dsetname[], 70 | const size_t ndims, 71 | const int * array_of_sizes, 72 | const int * array_of_subsizes, 73 | const int * array_of_starts, 74 | const char dtype[], 75 | const size_t size, 76 | const void * data 77 | ); 78 | } fileio_t; 79 | 80 | extern const fileio_t fileio; 81 | 82 | #endif // FILEIO_H 83 | -------------------------------------------------------------------------------- /include/fluid.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_H) 2 | #define FLUID_H 3 | 4 | #include "array.h" 5 | #include "runge_kutta.h" 6 | #include "domain.h" 7 | 8 | // definition of a structure fluid_t 9 | /** 10 | * @struct fluid_t 11 | * @brief struct storing fluid-related variables 12 | * @var u[x-z] : velocity in each direction 13 | * @var p, psi : pressure, scalar potential 14 | * @var t : temperature 15 | * @var srcu[x-z] : Runge-Kutta source terms for ux, uy, uz 16 | * @var srct : Runge-Kutta source terms for temperature 17 | * @var Ra, Pr : non-dimensional parameters 18 | */ 19 | typedef struct { 20 | array_t ux; 21 | array_t uy; 22 | array_t p; 23 | array_t psi; 24 | array_t t; 25 | rkbuffers_t srcux; 26 | rkbuffers_t srcuy; 27 | rkbuffers_t srct; 28 | double Ra; 29 | double Pr; 30 | } fluid_t; 31 | 32 | // initialiser of fluid_t 33 | extern int fluid_init ( 34 | const char dirname_ic[], 35 | const domain_t * const domain, 36 | fluid_t * const fluid 37 | ); 38 | 39 | // save flow field 40 | extern int fluid_save ( 41 | const char dirname[], 42 | const domain_t * const domain, 43 | const fluid_t * const fluid 44 | ); 45 | 46 | #endif // FLUID_H 47 | -------------------------------------------------------------------------------- /include/fluid_solver.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_SOLVER_H) 2 | #define FLUID_SOLVER_H 3 | 4 | #include "array.h" 5 | #include "domain.h" 6 | #include "fluid.h" 7 | 8 | extern double fluid_compute_momentum_diffusivity ( 9 | const fluid_t * fluid 10 | ); 11 | 12 | extern double fluid_compute_temperature_diffusivity ( 13 | const fluid_t * fluid 14 | ); 15 | 16 | // predict the new velocity field and update the temperature field 17 | extern int fluid_predict_field( 18 | const domain_t * domain, 19 | const size_t rkstep, 20 | const double dt, 21 | fluid_t * fluid 22 | ); 23 | 24 | // compute scalar potential by solving Poisson equation 25 | extern int fluid_compute_potential( 26 | const domain_t * domain, 27 | const size_t rkstep, 28 | const double dt, 29 | fluid_t * fluid 30 | ); 31 | 32 | // correct velocity field using scalar potential to enforce divergence zero 33 | extern int fluid_correct_velocity( 34 | const domain_t * domain, 35 | const size_t rkstep, 36 | const double dt, 37 | fluid_t * fluid 38 | ); 39 | 40 | extern int fluid_update_pressure( 41 | const domain_t * domain, 42 | const size_t rkstep, 43 | const double dt, 44 | fluid_t * fluid 45 | ); 46 | 47 | extern int fluid_update_boundaries_ux( 48 | const domain_t * domain, 49 | array_t * ux 50 | ); 51 | 52 | extern int fluid_update_boundaries_uy( 53 | const domain_t * domain, 54 | array_t * uy 55 | ); 56 | 57 | extern int fluid_update_boundaries_p( 58 | const domain_t * domain, 59 | array_t * p 60 | ); 61 | 62 | extern int fluid_update_boundaries_psi( 63 | const domain_t * domain, 64 | array_t * psi 65 | ); 66 | 67 | extern int fluid_update_boundaries_t( 68 | const domain_t * domain, 69 | array_t * t 70 | ); 71 | 72 | #endif // FLUID_SOLVER_H 73 | -------------------------------------------------------------------------------- /include/halo.h: -------------------------------------------------------------------------------- 1 | #if !defined(HALO_H) 2 | #define HALO_H 3 | 4 | int halo_communicate_in_y( 5 | const domain_t * domain, 6 | MPI_Datatype * dtype, 7 | array_t * array 8 | ); 9 | 10 | #endif // HALO_H 11 | -------------------------------------------------------------------------------- /include/integrate.h: -------------------------------------------------------------------------------- 1 | #if !defined(INTEGRATE_H) 2 | #define INTEGRATE_H 3 | 4 | // main integrator 5 | extern int integrate( 6 | const domain_t * domain, 7 | fluid_t * fluid, 8 | double * dt 9 | ); 10 | 11 | #endif // INTEGRATE_H 12 | -------------------------------------------------------------------------------- /include/linear_system.h: -------------------------------------------------------------------------------- 1 | #if !defined(LINEAR_SYSTEM_H) 2 | #define LINEAR_SYSTEM_H 3 | 4 | #include 5 | #include "sdecomp.h" 6 | #include "domain.h" 7 | #include "tdm.h" 8 | 9 | /** 10 | * @struct linear_system_t 11 | * @brief structure storing buffers and plans to solve tri-diagonal linear systems in each dimension A x = b 12 | * @var is_initialised : flag to check the variable is initialised 13 | * @var implicit : flags whether directions are treated implicitly, 14 | * namely linear systems are to be solved 15 | * @var x1pncl : buffers to store x1-pencil 16 | * @var y1pncl : buffers to store y1-pencil 17 | * @var z2pncl : buffers to store z2-pencil 18 | * @var x1pncl_mysizes : size of (local) x1pencil 19 | * @var y1pncl_mysizes : size of (local) y1pencil 20 | * @var z2pncl_mysizes : size of (local) z2pencil 21 | * @var tdm_[x-z] : thomas algorithm solvers in all directions 22 | * @var transposer_xx_to_xx : plans to transpose between two pencils 23 | */ 24 | typedef struct { 25 | bool is_initialised; 26 | bool implicit[NDIMS]; 27 | double * restrict x1pncl; 28 | double * restrict y1pncl; 29 | size_t x1pncl_mysizes[NDIMS]; 30 | size_t y1pncl_mysizes[NDIMS]; 31 | tdm_info_t * tdm_x; 32 | tdm_info_t * tdm_y; 33 | sdecomp_transpose_plan_t * transposer_x1_to_y1; 34 | sdecomp_transpose_plan_t * transposer_y1_to_x1; 35 | } linear_system_t; 36 | 37 | extern int linear_system_init( 38 | const sdecomp_info_t * info, 39 | const bool implicit[NDIMS], 40 | const size_t glsizes[NDIMS], 41 | linear_system_t * linear_system 42 | ); 43 | 44 | extern int linear_system_finalise( 45 | linear_system_t * linear_system 46 | ); 47 | 48 | #endif // LINEAR_SYSTEM_H 49 | -------------------------------------------------------------------------------- /include/logging.h: -------------------------------------------------------------------------------- 1 | #if !defined(LOGGING_H) 2 | #define LOGGING_H 3 | 4 | #include "domain.h" 5 | #include "fluid.h" 6 | 7 | typedef struct { 8 | // constructor 9 | int (* const init)( 10 | const domain_t * domain, 11 | const double time 12 | ); 13 | // check quantities and dump to log files 14 | void (* const check_and_output)( 15 | const domain_t * domain, 16 | const size_t step, 17 | const double time, 18 | const double dt, 19 | const double wtime, 20 | const fluid_t * fluid 21 | ); 22 | // getter, next timing to call "check_and_output" 23 | double (* const get_next_time)( 24 | void 25 | ); 26 | } logging_t; 27 | 28 | extern const logging_t logging; 29 | 30 | #endif // LOGGING_H 31 | -------------------------------------------------------------------------------- /include/memory.h: -------------------------------------------------------------------------------- 1 | #if !defined(MEMORY_H) 2 | #define MEMORY_H 3 | 4 | #include // size_t 5 | 6 | // general-purpose memory allocator 7 | extern void * memory_calloc( 8 | const size_t count, 9 | const size_t size 10 | ); 11 | 12 | // corresponding memory deallocator 13 | extern void memory_free( 14 | void * ptr 15 | ); 16 | 17 | #endif // MEMORY_H 18 | -------------------------------------------------------------------------------- /include/param.h: -------------------------------------------------------------------------------- 1 | #if !defined(PARAM_H) 2 | #define PARAM_H 3 | 4 | // fixed parameters, which are usually fixed 5 | // but still user can easily control, are declared 6 | // they are defined under src/param/xxx.c 7 | 8 | #include 9 | 10 | /* buoyancy.c */ 11 | // flag to specify whether the buoyancy force is added 12 | // to the RHS of the momentum equation or not 13 | // if not, the temperature behaves as a passive scalar 14 | extern const bool param_add_buoyancy; 15 | 16 | /* implicit.c */ 17 | // flags to specify the diffusive treatment of the momentum equations 18 | extern const bool param_m_implicit_x; 19 | extern const bool param_m_implicit_y; 20 | // flags to specify the diffusive treatment of the temperature equation 21 | extern const bool param_t_implicit_x; 22 | extern const bool param_t_implicit_y; 23 | 24 | /* boundary-condition.c */ 25 | // NOTE: changing values may break the Nusselt balance 26 | // NOTE: impermeable walls and Neumann BC for the pressure are unchangeable 27 | // negative-x-wall velocity in y direction 28 | extern const double param_uy_xm; 29 | // positive-x-wall velocity in y direction 30 | extern const double param_uy_xp; 31 | // negative-x-wall temperature 32 | extern const double param_t_xm; 33 | // positive-x-wall temperature 34 | extern const double param_t_xp; 35 | 36 | #endif // PARAM_H 37 | -------------------------------------------------------------------------------- /include/runge_kutta.h: -------------------------------------------------------------------------------- 1 | #if !defined(RUNGE_KUTTA_H) 2 | #define RUNGE_KUTTA_H 3 | 4 | #include "domain.h" 5 | #include "array.h" 6 | 7 | // Runge-Kutta configurations 8 | // NOTE: only three-step Wray is allowed 9 | #define RKSTEPMAX 3 10 | 11 | // coefficients in front of dt 12 | typedef struct { 13 | double alpha; 14 | double beta; 15 | double gamma; 16 | } rkcoef_t; 17 | extern const rkcoef_t rkcoefs[RKSTEPMAX]; 18 | 19 | // buffers to store 20 | // explicit terms (current: alpha, previous: beta) 21 | // and 22 | // implicit terms (gamma) 23 | typedef struct { 24 | array_t alpha; 25 | array_t beta; 26 | array_t gamma; 27 | } rkbuffers_t; 28 | 29 | extern int rkbuffers_init ( 30 | const domain_t * const domain, 31 | const int nadds[NDIMS][2], 32 | rkbuffers_t * const buffers 33 | ); 34 | 35 | extern int rkbuffers_reset ( 36 | rkbuffers_t * const buffers 37 | ); 38 | 39 | #endif // RUNGE_KUTTA_H 40 | -------------------------------------------------------------------------------- /include/save.h: -------------------------------------------------------------------------------- 1 | #if !defined(SAVE_H) 2 | #define SAVE_H 3 | 4 | #include "domain.h" 5 | #include "fluid.h" 6 | 7 | typedef struct save_t_ { 8 | // constructor 9 | int (* const init)( 10 | const domain_t * domain, 11 | const double time 12 | ); 13 | // save a instantaneous flow field to files 14 | int (* const output)( 15 | const domain_t * domain, 16 | const size_t step, 17 | const double time, 18 | const fluid_t * fluid 19 | ); 20 | // getter, next timing to call "output" 21 | double (* const get_next_time)( 22 | void 23 | ); 24 | } save_t; 25 | 26 | extern const save_t save; 27 | 28 | #endif // SAVE_H 29 | -------------------------------------------------------------------------------- /include/statistics.h: -------------------------------------------------------------------------------- 1 | #if !defined(STATISTICS_H) 2 | #define STATISTICS_H 3 | 4 | #include "domain.h" 5 | #include "fluid.h" 6 | 7 | typedef struct { 8 | // constructor 9 | int (* const init)( 10 | const domain_t * domain, 11 | const double time 12 | ); 13 | // collecting statistics 14 | int (* const collect)( 15 | const domain_t * domain, 16 | const fluid_t * fluid 17 | ); 18 | // save statistics to files 19 | int (* const output)( 20 | const domain_t * domain, 21 | const size_t step 22 | ); 23 | // getter, next timing to call "collect" 24 | double (* const get_next_time)( 25 | void 26 | ); 27 | } statistics_t; 28 | 29 | extern const statistics_t statistics; 30 | 31 | #endif // STATISTICS_H 32 | -------------------------------------------------------------------------------- /include/tdm.h: -------------------------------------------------------------------------------- 1 | #if !defined(TDM_H) 2 | #define TDM_H 3 | 4 | #include 5 | 6 | typedef struct tdm_info_t_ tdm_info_t; 7 | 8 | typedef struct { 9 | int (* const construct)( 10 | const int size, 11 | const int nrhs, 12 | const bool is_periodic, 13 | const bool is_complex, 14 | tdm_info_t ** info 15 | ); 16 | int (* const get_l)( 17 | const tdm_info_t * info, 18 | double * restrict * l 19 | ); 20 | int (* const get_c)( 21 | const tdm_info_t * info, 22 | double * restrict * c 23 | ); 24 | int (* const get_u)( 25 | const tdm_info_t * info, 26 | double * restrict * u 27 | ); 28 | int (* const get_size)( 29 | const tdm_info_t * info, 30 | int * size 31 | ); 32 | int (* const get_nrhs)( 33 | const tdm_info_t * info, 34 | int * nrhs 35 | ); 36 | int (* const solve)( 37 | const tdm_info_t * info, 38 | void * restrict data 39 | ); 40 | int (* const destruct)( 41 | tdm_info_t * info 42 | ); 43 | } tdm_t; 44 | 45 | extern const tdm_t tdm; 46 | 47 | #endif // TDM_H 48 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | #if !defined(TIMER_H) 2 | #define TIMER_H 3 | 4 | // get current time 5 | extern double timer( 6 | void 7 | ); 8 | 9 | #endif // TIMER_H 10 | -------------------------------------------------------------------------------- /initial_condition/Makefile: -------------------------------------------------------------------------------- 1 | help: 2 | @echo "output : make directory to store NPY files" 3 | @echo "datadel : remove NPY files" 4 | @echo "help : show this message" 5 | 6 | output: 7 | @if [ ! -e output ]; then \ 8 | mkdir output; \ 9 | fi 10 | 11 | datadel: 12 | $(RM) output/*.npy 13 | 14 | .PHONY : help output datadel 15 | 16 | -------------------------------------------------------------------------------- /initial_condition/README.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | initial_condition 3 | ################# 4 | 5 | ******** 6 | Overview 7 | ******** 8 | 9 | This directory contains a Python script to initialise the domain and the flow field, which will be simulated by the main solver. 10 | Note that this initialiser is not parallelised for simplicity. 11 | 12 | ************* 13 | Configuration 14 | ************* 15 | 16 | See ``main.py``. 17 | 18 | ***** 19 | Usage 20 | ***** 21 | 22 | .. code-block:: console 23 | 24 | make output 25 | bash exec.sh 26 | 27 | giving several ``NPY`` files under the specified directory (``output`` by default). 28 | 29 | These files will be loaded by the main simulator. 30 | 31 | -------------------------------------------------------------------------------- /initial_condition/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | 5 | 6 | rng = np.random.default_rng() 7 | 8 | 9 | def get_lengths(): 10 | lx = os.environ.get("lx") 11 | ly = os.environ.get("ly") 12 | lz = os.environ.get("lz") 13 | if lz: 14 | lengths = [lx, ly, lz] 15 | else: 16 | lengths = [lx, ly] 17 | return list(map(float, lengths)) 18 | 19 | 20 | def get_glsizes(): 21 | glisize = os.environ.get("glisize") 22 | gljsize = os.environ.get("gljsize") 23 | glksize = os.environ.get("glksize") 24 | if glksize: 25 | glsizes = [glisize, gljsize, glksize] 26 | else: 27 | glsizes = [glisize, gljsize] 28 | return list(map(int, glsizes)) 29 | 30 | 31 | def init_time(dest): 32 | # iterator and time 33 | step = np.array(0, dtype=np.uint64) 34 | time = np.array(0, dtype=np.float64) 35 | np.save(f"{dest}/step.npy", step) 36 | np.save(f"{dest}/time.npy", time) 37 | return 38 | 39 | 40 | def init_domain(lengths, glsizes, dest): 41 | # generate equidistant sequence 42 | # NOTE: cell face has +1 elements 43 | xf = np.arange(0, glsizes[0] + 1, 1) 44 | # stretched grid, clipped Chebyshev just as an example 45 | is_uniform = False 46 | if not is_uniform: 47 | # number of grid points to be clipped at the edges 48 | nclip = 3 49 | # gather close to the boundaries 50 | xf = np.cos(np.pi * (xf + 1. * nclip) / (glsizes[0] + 2. * nclip)) 51 | # make the descending order ascending 52 | xf *= -1. 53 | # normalse to enforce [0 : lx] 54 | xf = lengths[0] * (xf - np.min(xf)) / (np.max(xf) - np.min(xf)) 55 | # cell centers are located at the center 56 | # of the two neighbouring cell faces, 57 | # which are appended by the boundaries 58 | xc = 0. 59 | xc = np.append(xc, 0.5 * xf[:-1] + 0.5 * xf[1:]) 60 | xc = np.append(xc, lengths[0]) 61 | np.save(f"{dest}/xf.npy", np.array(xf, dtype=np.float64)) 62 | np.save(f"{dest}/xc.npy", np.array(xc, dtype=np.float64)) 63 | np.save(f"{dest}/glsizes.npy", np.array(glsizes, dtype=np.uint64)) 64 | np.save(f"{dest}/lengths.npy", np.array(lengths, dtype=np.float64)) 65 | return xf, xc 66 | 67 | 68 | def init_fluid(is_3d, lengths, glsizes, xf, xc, dest): 69 | if is_3d: 70 | ux = np.zeros((glsizes[2], glsizes[1], glsizes[0] + 1), dtype=np.float64) 71 | uy = np.zeros((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 72 | uz = np.zeros((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 73 | p = np.zeros((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 74 | t = rng.random((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 75 | t -= 0.5 76 | np.save(f"{dest}/ux.npy", ux) 77 | np.save(f"{dest}/uy.npy", uy) 78 | np.save(f"{dest}/uz.npy", uz) 79 | np.save(f"{dest}/p.npy", p) 80 | np.save(f"{dest}/t.npy", t) 81 | else: 82 | ux = np.zeros((glsizes[1], glsizes[0] + 1), dtype=np.float64) 83 | uy = np.zeros((glsizes[1], glsizes[0] + 2), dtype=np.float64) 84 | p = np.zeros((glsizes[1], glsizes[0] + 2), dtype=np.float64) 85 | t = rng.random((glsizes[1], glsizes[0] + 2), dtype=np.float64) 86 | t -= 0.5 87 | np.save(f"{dest}/ux.npy", ux) 88 | np.save(f"{dest}/uy.npy", uy) 89 | np.save(f"{dest}/p.npy", p) 90 | np.save(f"{dest}/t.npy", t) 91 | 92 | 93 | def main(): 94 | lengths = get_lengths() 95 | glsizes = get_glsizes() 96 | assert len(lengths) == len(glsizes) 97 | dest = sys.argv[1] 98 | is_3d = 3 == len(lengths) 99 | if is_3d: 100 | print("A 3D field is initialised") 101 | else: 102 | print("A 2D field is initialised") 103 | # init and save 104 | init_time(dest) 105 | xf, xc = init_domain(lengths, glsizes, dest) 106 | init_fluid(is_3d, lengths, glsizes, xf, xc, dest) 107 | 108 | 109 | main() 110 | -------------------------------------------------------------------------------- /initial_condition/main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## domain 4 | # domain lengths 5 | export lx=1.0e+0 6 | export ly=2.0e+0 7 | # number of cell centers 8 | export glisize=128 9 | export gljsize=256 10 | 11 | ## where to write resulting NPY files 12 | dirname="output" 13 | 14 | python3 main.py ${dirname} 15 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "config.h" 7 | 8 | /** 9 | * @brief load environment variable and interpret it as an double-precision value 10 | * @param[in] dsetname : name of the environment variable 11 | * @param[out] value : resulting value 12 | * @return : error code 13 | */ 14 | static int get_double( 15 | const char dsetname[], 16 | double * value 17 | ){ 18 | // error code 19 | int retval = 0; 20 | // try to load, may fail if the variable is not defined 21 | char * string = getenv(dsetname); 22 | if(NULL == string){ 23 | retval = 1; 24 | } 25 | MPI_Allreduce(MPI_IN_PLACE, &retval, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); 26 | if(0 != retval){ 27 | printf("%s not found\n", dsetname); 28 | return 1; 29 | } 30 | // try to convert a string to a double-precision value 31 | errno = 0; 32 | *value = strtod(string, NULL); 33 | if(0 != errno){ 34 | retval = 1; 35 | } 36 | MPI_Allreduce(MPI_IN_PLACE, &retval, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); 37 | if(0 != retval){ 38 | printf("%s: invalid value as double\n", dsetname); 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | 44 | const config_t config = { 45 | .get_double = get_double, 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /src/fluid/boundary/p.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid_solver.h" 5 | #include "array_macros/fluid/p.h" 6 | 7 | static int assign_boundary_conditions_in_x( 8 | const domain_t * domain, 9 | double * p 10 | ){ 11 | const int isize = domain->mysizes[0]; 12 | const int jsize = domain->mysizes[1]; 13 | // set boundary values 14 | for(int j = 1; j <= jsize; j++){ 15 | P( 0, j) = P( 1, j); // Neumann 16 | P(isize+1, j) = P(isize, j); // Neumann 17 | } 18 | return 0; 19 | } 20 | 21 | /** 22 | * @brief update boundary values of the pressure 23 | * @param[in] domain : information about domain decomposition and size 24 | * @param[in,out] p : pressure 25 | * @return : error code 26 | */ 27 | int fluid_update_boundaries_p( 28 | const domain_t * domain, 29 | array_t * p 30 | ){ 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | }; 34 | if(0 != halo_communicate_in_y(domain, dtypes + 0, p)){ 35 | return 1; 36 | } 37 | assign_boundary_conditions_in_x(domain, p->data); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/fluid/boundary/psi.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid_solver.h" 5 | #include "array_macros/fluid/psi.h" 6 | 7 | static int assign_boundary_conditions_in_x( 8 | const domain_t * domain, 9 | double * psi 10 | ){ 11 | const int isize = domain->mysizes[0]; 12 | const int jsize = domain->mysizes[1]; 13 | // set boundary values 14 | for(int j = 1; j <= jsize; j++){ 15 | PSI( 0, j) = PSI( 1, j); // Neumann 16 | PSI(isize+1, j) = PSI(isize, j); // Neumann 17 | } 18 | return 0; 19 | } 20 | 21 | /** 22 | * @brief update boundary values of the scalar potential 23 | * @param[in] domain : information about domain decomposition and size 24 | * @param[in,out] p : pressure 25 | * @return : error code 26 | */ 27 | int fluid_update_boundaries_psi( 28 | const domain_t * domain, 29 | array_t * psi 30 | ){ 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | }; 34 | if(0 != halo_communicate_in_y(domain, dtypes + 0, psi)){ 35 | return 1; 36 | } 37 | assign_boundary_conditions_in_x(domain, psi->data); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/fluid/boundary/t.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | #include "array.h" 3 | #include "domain.h" 4 | #include "halo.h" 5 | #include "fluid_solver.h" 6 | #include "array_macros/fluid/t.h" 7 | 8 | static int assign_boundary_conditions_in_x( 9 | const domain_t * domain, 10 | double * t 11 | ){ 12 | const int isize = domain->mysizes[0]; 13 | const int jsize = domain->mysizes[1]; 14 | // set boundary values 15 | for(int j = 1; j <= jsize; j++){ 16 | T( 0, j) = param_t_xm; 17 | T(isize+1, j) = param_t_xp; 18 | } 19 | return 0; 20 | } 21 | 22 | /** 23 | * @brief update boundary values of temperature 24 | * @param[in] domain : information about domain decomposition and size 25 | * @param[in,out] t : temperature 26 | * @return : error code 27 | */ 28 | int fluid_update_boundaries_t( 29 | const domain_t * domain, 30 | array_t * t 31 | ){ 32 | static MPI_Datatype dtypes[NDIMS - 1] = { 33 | MPI_DOUBLE, 34 | }; 35 | if(0 != halo_communicate_in_y(domain, dtypes + 0, t)){ 36 | return 1; 37 | } 38 | assign_boundary_conditions_in_x(domain, t->data); 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/fluid/boundary/ux.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid_solver.h" 5 | #include "array_macros/fluid/ux.h" 6 | 7 | static int assign_boundary_conditions_in_x( 8 | const domain_t * domain, 9 | double * ux 10 | ){ 11 | const int isize = domain->mysizes[0]; 12 | const int jsize = domain->mysizes[1]; 13 | // set boundary values 14 | for(int j = 1; j <= jsize; j++){ 15 | UX( 1, j) = 0.; // impermeable 16 | UX(isize+1, j) = 0.; // impermeable 17 | } 18 | return 0; 19 | } 20 | 21 | /** 22 | * @brief update boundary values of x velocity 23 | * @param[in] domain : information about domain decomposition and size 24 | * @param[in,out] ux : x velocity 25 | * @return : error code 26 | */ 27 | int fluid_update_boundaries_ux( 28 | const domain_t * domain, 29 | array_t * ux 30 | ){ 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | }; 34 | if(0 != halo_communicate_in_y(domain, dtypes + 0, ux)){ 35 | return 1; 36 | } 37 | assign_boundary_conditions_in_x(domain, ux->data); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/fluid/boundary/uy.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | #include "array.h" 3 | #include "domain.h" 4 | #include "halo.h" 5 | #include "fluid_solver.h" 6 | #include "array_macros/fluid/uy.h" 7 | 8 | static int assign_boundary_conditions_in_x( 9 | const domain_t * domain, 10 | double * uy 11 | ){ 12 | const int isize = domain->mysizes[0]; 13 | const int jsize = domain->mysizes[1]; 14 | // set boundary values 15 | for(int j = 1; j <= jsize; j++){ 16 | UY( 0, j) = param_uy_xm; // no-slip 17 | UY(isize+1, j) = param_uy_xp; // no-slip 18 | } 19 | return 0; 20 | } 21 | 22 | /** 23 | * @brief update boundary values of y velocity 24 | * @param[in] domain : information about domain decomposition and size 25 | * @param[in,out] uy : y velocity 26 | * @return : error code 27 | */ 28 | int fluid_update_boundaries_uy( 29 | const domain_t * domain, 30 | array_t * uy 31 | ){ 32 | static MPI_Datatype dtypes[NDIMS - 1] = { 33 | MPI_DOUBLE, 34 | }; 35 | if(0 != halo_communicate_in_y(domain, dtypes + 0, uy)){ 36 | return 1; 37 | } 38 | assign_boundary_conditions_in_x(domain, uy->data); 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/fluid/compute_diffusivity.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fluid.h" 3 | 4 | double fluid_compute_momentum_diffusivity ( 5 | const fluid_t * fluid 6 | ) { 7 | return sqrt(fluid->Pr) / sqrt(fluid->Ra); 8 | } 9 | 10 | double fluid_compute_temperature_diffusivity ( 11 | const fluid_t * fluid 12 | ) { 13 | return 1. / sqrt(fluid->Pr) / sqrt(fluid->Ra); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/fluid/correct/internal.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_CORRECT_VELOCITY_INTERNAL_H) 2 | #define FLUID_CORRECT_VELOCITY_INTERNAL_H 3 | 4 | extern int fluid_correct_velocity_ux( 5 | const domain_t * domain, 6 | const double prefactor, 7 | fluid_t * fluid 8 | ); 9 | 10 | extern int fluid_correct_velocity_uy( 11 | const domain_t * domain, 12 | const double prefactor, 13 | fluid_t * fluid 14 | ); 15 | 16 | #endif // FLUID_CORRECT_VELOCITY_INTERNAL_H 17 | -------------------------------------------------------------------------------- /src/fluid/correct/main.c: -------------------------------------------------------------------------------- 1 | #include "runge_kutta.h" 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "fluid_solver.h" 5 | #include "internal.h" 6 | 7 | /** 8 | * @brief correct non-solenoidal velocity using scalar potential psi 9 | * @param[in] domain : information about domain decomposition and size 10 | * @param[in] rkstep : Runge-Kutta step 11 | * @param[in] dt : time step size 12 | * @param[in,out] fluid : scalar potential (in), velocity (out) 13 | * @return : error code 14 | */ 15 | int fluid_correct_velocity( 16 | const domain_t * domain, 17 | const size_t rkstep, 18 | const double dt, 19 | fluid_t * fluid 20 | ){ 21 | // compute prefactor gamma dt 22 | const double gamma = rkcoefs[rkstep].gamma; 23 | const double prefactor = gamma * dt; 24 | if(0 != fluid_correct_velocity_ux(domain, prefactor, fluid)) return 1; 25 | if(0 != fluid_correct_velocity_uy(domain, prefactor, fluid)) return 1; 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/fluid/correct/ux.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "fluid_solver.h" 4 | #include "internal.h" 5 | #include "array_macros/domain/hxxf.h" 6 | #include "array_macros/fluid/ux.h" 7 | #include "array_macros/fluid/psi.h" 8 | 9 | #define BEGIN \ 10 | for (int j = 1; j <= jsize; j++) { \ 11 | for (int i = 2; i <= isize; i++) { 12 | #define END \ 13 | } \ 14 | } 15 | 16 | // correct x velocity 17 | int fluid_correct_velocity_ux ( 18 | const domain_t * domain, 19 | const double prefactor, 20 | fluid_t * fluid 21 | ) { 22 | const int isize = domain->mysizes[0]; 23 | const int jsize = domain->mysizes[1]; 24 | const double * restrict hxxf = domain->hxxf; 25 | const double * restrict psi = fluid->psi.data; 26 | double * restrict ux = fluid->ux.data; 27 | BEGIN 28 | const double hx = HXXF(i ); 29 | const double psi_xm = PSI(i-1, j ); 30 | const double psi_xp = PSI(i , j ); 31 | double * vel = &UX(i, j); 32 | *vel -= prefactor / hx * ( 33 | - psi_xm 34 | + psi_xp 35 | ); 36 | END 37 | // update boundary and halo cells 38 | if (0 != fluid_update_boundaries_ux(domain, &fluid->ux)) { 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/fluid/correct/uy.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "fluid_solver.h" 4 | #include "internal.h" 5 | #include "array_macros/fluid/uy.h" 6 | #include "array_macros/fluid/psi.h" 7 | 8 | #define BEGIN \ 9 | for (int j = 1; j <= jsize; j++) { \ 10 | for (int i = 1; i <= isize; i++) { 11 | #define END \ 12 | } \ 13 | } 14 | 15 | // correct y velocity 16 | int fluid_correct_velocity_uy ( 17 | const domain_t * domain, 18 | const double prefactor, 19 | fluid_t * fluid 20 | ) { 21 | const int isize = domain->mysizes[0]; 22 | const int jsize = domain->mysizes[1]; 23 | const double hy = domain->hy; 24 | const double * restrict psi = fluid->psi.data; 25 | double * restrict uy = fluid->uy.data; 26 | BEGIN 27 | const double psi_ym = PSI(i , j-1); 28 | const double psi_yp = PSI(i , j ); 29 | double * vel = &UY(i, j); 30 | *vel -= prefactor / hy * ( 31 | - psi_ym 32 | + psi_yp 33 | ); 34 | END 35 | // update boundary and halo cells 36 | if (0 != fluid_update_boundaries_uy(domain, &fluid->uy)) { 37 | return 1; 38 | } 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/fluid/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "param.h" 3 | #include "runge_kutta.h" 4 | #include "memory.h" 5 | #include "config.h" 6 | #include "domain.h" 7 | #include "fluid.h" 8 | #include "fluid_solver.h" 9 | #include "fileio.h" 10 | #include "array_macros/fluid/ux.h" 11 | #include "array_macros/fluid/uy.h" 12 | #include "array_macros/fluid/p.h" 13 | #include "array_macros/fluid/t.h" 14 | #include "array_macros/fluid/psi.h" 15 | #include "array_macros/fluid/srcux.h" 16 | #include "array_macros/fluid/srcuy.h" 17 | #include "array_macros/fluid/srct.h" 18 | 19 | static int allocate ( 20 | const domain_t * domain, 21 | fluid_t * fluid 22 | ) { 23 | // velocity 24 | if (0 != array.create(domain, UX_NADDS, sizeof(double), &fluid->ux )) return 1; 25 | if (0 != array.create(domain, UY_NADDS, sizeof(double), &fluid->uy )) return 1; 26 | // pressure and scalar potential 27 | if (0 != array.create(domain, P_NADDS, sizeof(double), &fluid->p )) return 1; 28 | if (0 != array.create(domain, PSI_NADDS, sizeof(double), &fluid->psi)) return 1; 29 | // temperature 30 | if (0 != array.create(domain, T_NADDS, sizeof(double), &fluid->t)) return 1; 31 | // Runge-Kutta source terms 32 | if (0 != rkbuffers_init(domain, SRCUX_NADDS, &fluid->srcux)) return 1; 33 | if (0 != rkbuffers_init(domain, SRCUY_NADDS, &fluid->srcuy)) return 1; 34 | if (0 != rkbuffers_init(domain, SRCT_NADDS, &fluid->srct )) return 1; 35 | return 0; 36 | } 37 | 38 | static int report ( 39 | const sdecomp_info_t * info, 40 | const fluid_t * fluid 41 | ) { 42 | const int root = 0; 43 | int myrank = root; 44 | sdecomp.get_comm_rank(info, &myrank); 45 | if (root == myrank) { 46 | printf("FLUID\n"); 47 | printf("\tRa: % .7e\n", fluid->Ra); 48 | printf("\tPr: % .7e\n", fluid->Pr); 49 | printf("\tdiffusive treatment in x: %s\n", param_m_implicit_x ? "implicit" : "explicit"); 50 | printf("\tdiffusive treatment in y: %s\n", param_m_implicit_y ? "implicit" : "explicit"); 51 | fflush(stdout); 52 | } 53 | return 0; 54 | } 55 | 56 | /** 57 | * @brief constructor of the structure 58 | * @param[in] dirname_ic : name of directory in which initial flow fields are stored 59 | * @param[in] domain : information about domain decomposition and size 60 | * @param[out] : structure being allocated and initalised 61 | * @return : (success) 0 62 | * (failure) non-zero value 63 | */ 64 | int fluid_init( 65 | const char dirname_ic[], 66 | const domain_t * domain, 67 | fluid_t * fluid 68 | ) { 69 | // allocate arrays 70 | if (0 != allocate(domain, fluid)) return 1; 71 | // load flow fields 72 | if (0 != array.load(domain, dirname_ic, "ux", fileio.npy_double, &fluid->ux)) return 1; 73 | if (0 != array.load(domain, dirname_ic, "uy", fileio.npy_double, &fluid->uy)) return 1; 74 | if (0 != array.load(domain, dirname_ic, "p", fileio.npy_double, &fluid-> p)) return 1; 75 | if (0 != array.load(domain, dirname_ic, "t", fileio.npy_double, &fluid-> t)) return 1; 76 | // impose boundary conditions and communicate halo cells 77 | if (0 != fluid_update_boundaries_ux(domain, &fluid->ux)) return 1; 78 | if (0 != fluid_update_boundaries_uy(domain, &fluid->uy)) return 1; 79 | if (0 != fluid_update_boundaries_p(domain, &fluid->p)) return 1; 80 | if (0 != fluid_update_boundaries_t(domain, &fluid->t)) return 1; 81 | // load diffusivities 82 | if (0 != config.get_double("Pr", &fluid->Pr)) return 1; 83 | if (0 != config.get_double("Ra", &fluid->Ra)) return 1; 84 | report(domain->info, fluid); 85 | return 0; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/fluid/predict/internal.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_PREDICT_INTERNAL) 2 | #define FLUID_PREDICT_INTERNAL 3 | 4 | #include 5 | 6 | // store approximation of laplacian 7 | typedef struct { 8 | double l; 9 | double c; 10 | double u; 11 | } laplacian_t; 12 | 13 | // store Laplacian for each directoin 14 | typedef struct { 15 | bool is_initialised; 16 | laplacian_t * lapx; 17 | laplacian_t lapy; 18 | } laplacians_t; 19 | 20 | extern int compute_rhs_ux ( 21 | const domain_t * domain, 22 | fluid_t * fluid 23 | ); 24 | 25 | extern int compute_rhs_uy ( 26 | const domain_t * domain, 27 | fluid_t * fluid 28 | ); 29 | 30 | extern int compute_rhs_t ( 31 | const domain_t * domain, 32 | fluid_t * fluid 33 | ); 34 | 35 | extern int update_ux ( 36 | const domain_t * domain, 37 | const size_t rkstep, 38 | const double dt, 39 | fluid_t * fluid 40 | ); 41 | 42 | extern int update_uy ( 43 | const domain_t * domain, 44 | const size_t rkstep, 45 | const double dt, 46 | fluid_t * fluid 47 | ); 48 | 49 | extern int update_t ( 50 | const domain_t * domain, 51 | const size_t rkstep, 52 | const double dt, 53 | fluid_t * fluid 54 | ); 55 | 56 | #endif // FLUID_PREDICT_INTERNAL 57 | -------------------------------------------------------------------------------- /src/fluid/predict/main.c: -------------------------------------------------------------------------------- 1 | #include "runge_kutta.h" 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "fluid_solver.h" 5 | #include "internal.h" 6 | 7 | /** 8 | * @brief update fields using the previously-computed RK source terms 9 | * @param[in] domain : information related to MPI domain decomposition 10 | * @param[in] rkstep : Runge-Kutta step 11 | * @param[in] dt : time step size 12 | * @param[in,out] fluid : RK source terms (in), flow field (out) 13 | * @return : error code 14 | */ 15 | int fluid_predict_field( 16 | const domain_t * domain, 17 | const size_t rkstep, 18 | const double dt, 19 | fluid_t * fluid 20 | ){ 21 | // reset buffers 22 | // copy previous k-step source term and reset 23 | if (0 != rkbuffers_reset(&fluid->srcux)) { 24 | return 1; 25 | } 26 | if (0 != rkbuffers_reset(&fluid->srcuy)) { 27 | return 1; 28 | } 29 | if (0 != rkbuffers_reset(&fluid->srct)) { 30 | return 1; 31 | } 32 | // compute right-hand-side terms and store them to the corresponding buffers 33 | if(0 != compute_rhs_ux(domain, fluid)){ 34 | return 1; 35 | } 36 | if(0 != compute_rhs_uy(domain, fluid)){ 37 | return 1; 38 | } 39 | if(0 != compute_rhs_t (domain, fluid)){ 40 | return 1; 41 | } 42 | // update flow field 43 | if(0 != update_ux(domain, rkstep, dt, fluid)){ 44 | return 1; 45 | } 46 | if(0 != update_uy(domain, rkstep, dt, fluid)){ 47 | return 1; 48 | } 49 | if(0 != update_t (domain, rkstep, dt, fluid)){ 50 | return 1; 51 | } 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/fluid/save.c: -------------------------------------------------------------------------------- 1 | #include "sdecomp.h" 2 | #include "array.h" 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fluid_solver.h" 6 | #include "fileio.h" 7 | 8 | int fluid_save( 9 | const char dirname[], 10 | const domain_t * domain, 11 | const fluid_t * fluid 12 | ){ 13 | // serial 14 | const int root = 0; 15 | int myrank = root; 16 | sdecomp.get_comm_rank(domain->info, &myrank); 17 | if(root == myrank){ 18 | fileio.w_serial(dirname, "Ra", 0, NULL, fileio.npy_double, sizeof(double), &fluid->Ra); 19 | fileio.w_serial(dirname, "Pr", 0, NULL, fileio.npy_double, sizeof(double), &fluid->Pr); 20 | } 21 | // collective 22 | array.dump(domain, dirname, "ux", fileio.npy_double, &fluid->ux); 23 | array.dump(domain, dirname, "uy", fileio.npy_double, &fluid->uy); 24 | array.dump(domain, dirname, "p", fileio.npy_double, &fluid-> p); 25 | array.dump(domain, dirname, "t", fileio.npy_double, &fluid-> t); 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/fluid/update_pressure.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | #include "runge_kutta.h" 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fluid_solver.h" 6 | #include "array_macros/domain/hxxf.h" 7 | #include "array_macros/domain/jdxf.h" 8 | #include "array_macros/domain/jdxc.h" 9 | #include "array_macros/fluid/p.h" 10 | #include "array_macros/fluid/psi.h" 11 | 12 | #define BEGIN \ 13 | for (int j = 1; j <= jsize; j++) { \ 14 | for (int i = 1; i <= isize; i++) { 15 | #define END \ 16 | } \ 17 | } 18 | 19 | // explicit contribution 20 | static int explicit_contribution ( 21 | const domain_t * domain, 22 | const fluid_t * fluid 23 | ) { 24 | const int isize = domain->mysizes[0]; 25 | const int jsize = domain->mysizes[1]; 26 | const double * restrict psi = fluid->psi.data; 27 | double * restrict p = fluid->p.data; 28 | BEGIN 29 | P(i, j) += PSI(i, j); 30 | END 31 | return 0; 32 | } 33 | 34 | // x implicit contribution 35 | static int implicit_x_contribution ( 36 | const domain_t * domain, 37 | const double prefactor, 38 | fluid_t * fluid 39 | ) { 40 | const int isize = domain->mysizes[0]; 41 | const int jsize = domain->mysizes[1]; 42 | const double * restrict hxxf = domain->hxxf; 43 | const double * restrict jdxf = domain->jdxf; 44 | const double * restrict jdxc = domain->jdxc; 45 | const double * restrict psi = fluid->psi.data; 46 | double * restrict p = fluid->p.data; 47 | BEGIN 48 | const double hx_xm = HXXF(i ); 49 | const double hx_xp = HXXF(i+1); 50 | const double jd_xm = JDXF(i ); 51 | const double jd_x0 = JDXC(i ); 52 | const double jd_xp = JDXF(i+1); 53 | const double l = 1. / jd_x0 * jd_xm / hx_xm / hx_xm; 54 | const double u = 1. / jd_x0 * jd_xp / hx_xp / hx_xp; 55 | const double c = - l - u; 56 | const double psi_xm = PSI(i-1, j ); 57 | const double psi_x0 = PSI(i , j ); 58 | const double psi_xp = PSI(i+1, j ); 59 | double * pre = &P(i, j); 60 | *pre -= prefactor * ( 61 | + l * psi_xm 62 | + c * psi_x0 63 | + u * psi_xp 64 | ); 65 | END 66 | return 0; 67 | } 68 | 69 | // y implicit contribution 70 | static int implicit_y_contribution ( 71 | const domain_t * domain, 72 | const double prefactor, 73 | fluid_t * fluid 74 | ) { 75 | const int isize = domain->mysizes[0]; 76 | const int jsize = domain->mysizes[1]; 77 | const double hy = domain->hy; 78 | const double * restrict psi = fluid->psi.data; 79 | double * restrict p = fluid->p.data; 80 | BEGIN 81 | const double l = 1. / hy / hy; 82 | const double u = 1. / hy / hy; 83 | const double c = - l - u; 84 | const double psi_ym = PSI(i , j-1); 85 | const double psi_y0 = PSI(i , j ); 86 | const double psi_yp = PSI(i , j+1); 87 | double * pre = &P(i, j); 88 | *pre -= prefactor * ( 89 | + l * psi_ym 90 | + c * psi_y0 91 | + u * psi_yp 92 | ); 93 | END 94 | return 0; 95 | } 96 | 97 | // update pressure field using scalar potential 98 | int fluid_update_pressure ( 99 | const domain_t * domain, 100 | const size_t rkstep, 101 | const double dt, 102 | fluid_t * fluid 103 | ) { 104 | // explicit contribution, always present 105 | explicit_contribution(domain, fluid); 106 | const double prefactor = 107 | 0.5 * rkcoefs[rkstep].gamma * dt * fluid_compute_momentum_diffusivity(fluid); 108 | // additional terms if diffusive terms in the direction is treated implicitly 109 | if (param_m_implicit_x) { 110 | implicit_x_contribution(domain, prefactor, fluid); 111 | } 112 | if (param_m_implicit_y) { 113 | implicit_y_contribution(domain, prefactor, fluid); 114 | } 115 | // impose boundary conditions and communicate halo cells 116 | if (0 != fluid_update_boundaries_p(domain, &fluid->p)) { 117 | return 1; 118 | } 119 | return 0; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/halo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "array.h" 4 | #include "domain.h" 5 | #include "halo.h" 6 | 7 | // fixed parameters 8 | // since data type is defined, number of items is 1 9 | static const int nitems = 1; 10 | // same tag can be used since I use blocking communication 11 | static const int tag = 0; 12 | 13 | // assume the given data type has not been initialised yet 14 | static const MPI_Datatype dtype_default = MPI_DOUBLE; 15 | 16 | // communicate halo cells with the y-neighbour processes 17 | // NOTE: send boundary cells for simplicity 18 | int halo_communicate_in_y( 19 | const domain_t * domain, 20 | MPI_Datatype * dtype, 21 | array_t * array 22 | ){ 23 | // extract communicator 24 | const sdecomp_info_t * info = domain->info; 25 | MPI_Comm comm_cart = MPI_COMM_NULL; 26 | sdecomp.get_comm_cart(info, &comm_cart); 27 | // check negative / positive neighbour ranks 28 | int neighbours[2] = {MPI_PROC_NULL, MPI_PROC_NULL}; 29 | sdecomp.get_neighbours(info, SDECOMP_X1PENCIL, SDECOMP_YDIR, neighbours); 30 | // array size (with halo and boundary cells) 31 | const int isize_ = domain->mysizes[0] + array->nadds[0][0] + array->nadds[0][1]; 32 | const int jsize_ = domain->mysizes[1] + array->nadds[1][0] + array->nadds[1][1]; 33 | // number of halo cells 34 | // this function assumes same number of halo cells 35 | // in the negative / positive directions 36 | if(array->nadds[1][0] != array->nadds[1][1]){ 37 | printf("%s: number of halo cells in y (%d and %d) mismatch\n", 38 | __func__, array->nadds[1][0], array->nadds[1][1]); 39 | return 1; 40 | } 41 | const int nhalos_y = array->nadds[1][0]; 42 | // define datatype in y 43 | if(dtype_default == *dtype){ 44 | MPI_Type_contiguous( 45 | isize_ * nhalos_y, 46 | *dtype, 47 | dtype 48 | ); 49 | MPI_Type_commit(dtype); 50 | } 51 | // send to positive, receive from negative 52 | { 53 | const int sindices[NDIMS] = {0, jsize_ - 2 * nhalos_y}; 54 | const int rindices[NDIMS] = {0, 0 * nhalos_y}; 55 | const size_t soffset = sindices[0] + isize_ * sindices[1]; 56 | const size_t roffset = rindices[0] + isize_ * rindices[1]; 57 | MPI_Sendrecv( 58 | (char *)array->data + array->size * soffset, nitems, *dtype, neighbours[1], tag, 59 | (char *)array->data + array->size * roffset, nitems, *dtype, neighbours[0], tag, 60 | comm_cart, MPI_STATUS_IGNORE 61 | ); 62 | } 63 | // send to negative, receive from positive 64 | { 65 | const int sindices[NDIMS] = {0, 1 * nhalos_y}; 66 | const int rindices[NDIMS] = {0, jsize_ - 1 * nhalos_y}; 67 | const size_t soffset = sindices[0] + isize_ * sindices[1]; 68 | const size_t roffset = rindices[0] + isize_ * rindices[1]; 69 | MPI_Sendrecv( 70 | (char *)array->data + array->size * soffset, nitems, *dtype, neighbours[0], tag, 71 | (char *)array->data + array->size * roffset, nitems, *dtype, neighbours[1], tag, 72 | comm_cart, MPI_STATUS_IGNORE 73 | ); 74 | } 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/integrate.c: -------------------------------------------------------------------------------- 1 | #include "runge_kutta.h" 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "fluid_solver.h" 5 | #include "integrate.h" 6 | #include "decide_dt.h" 7 | 8 | // integrate the equations for one time step 9 | int integrate( 10 | const domain_t * domain, 11 | fluid_t * fluid, 12 | double * dt 13 | ){ 14 | // decide time step size 15 | if(0 != decide_dt(domain, fluid, dt)){ 16 | return 1; 17 | } 18 | // Runge-Kutta iterations 19 | // max iteration, should be three 20 | for(size_t rkstep = 0; rkstep < RKSTEPMAX; rkstep++){ 21 | // predict flow field 22 | // NOTE: while the temperature is fully updated here, 23 | // the velocity field is still non-solenoidal 24 | if(0 != fluid_predict_field(domain, rkstep, *dt, fluid)){ 25 | return 1; 26 | } 27 | // compute scalar potential 28 | // now the temperature field has been updated, 29 | // while the velocity field is not divergence free 30 | // and thus the following correction step is needed 31 | if(0 != fluid_compute_potential(domain, rkstep, *dt, fluid)){ 32 | return 1; 33 | } 34 | // correct velocity field to satisfy mass conservation 35 | if(0 != fluid_correct_velocity(domain, rkstep, *dt, fluid)){ 36 | return 1; 37 | } 38 | // update pressure 39 | if(0 != fluid_update_pressure(domain, rkstep, *dt, fluid)){ 40 | return 1; 41 | } 42 | } 43 | return 0; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/logging/dissipated_squared_temperature.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "fluid_solver.h" 5 | #include "array_macros/domain/hxxf.h" 6 | #include "array_macros/domain/jdxf.h" 7 | #include "array_macros/domain/jdxc.h" 8 | #include "array_macros/fluid/t.h" 9 | #include "internal.h" 10 | 11 | // dtdx component 12 | static int get_dtdx ( 13 | const domain_t * domain, 14 | const fluid_t * fluid, 15 | double * quantity 16 | ) { 17 | const int isize = domain->mysizes[0]; 18 | const int jsize = domain->mysizes[1]; 19 | const double * restrict hxxf = domain->hxxf; 20 | const double * restrict jdxf = domain->jdxf; 21 | const double * restrict t = fluid->t.data; 22 | const double diffusivity = fluid_compute_temperature_diffusivity(fluid); 23 | for (int j = 1; j <= jsize; j++) { 24 | for (int i = 1; i <= isize + 1; i++) { 25 | const double hx = HXXF(i); 26 | const double jd = JDXF(i); 27 | const double dt = 28 | - T(i-1, j ) 29 | + T(i , j ); 30 | *quantity += diffusivity * jd * pow(1. / hx * dt, 2.); 31 | } 32 | } 33 | return 0; 34 | } 35 | 36 | // dtdy component 37 | static int get_dtdy ( 38 | const domain_t * domain, 39 | const fluid_t * fluid, 40 | double * quantity 41 | ) { 42 | const int isize = domain->mysizes[0]; 43 | const int jsize = domain->mysizes[1]; 44 | const double hy = domain->hy; 45 | const double * restrict jdxc = domain->jdxc; 46 | const double * restrict t = fluid->t.data; 47 | const double diffusivity = fluid_compute_temperature_diffusivity(fluid); 48 | for (int j = 1; j <= jsize; j++) { 49 | for (int i = 1; i <= isize; i++) { 50 | const double jd = JDXC(i); 51 | const double dt = 52 | - T(i , j-1) 53 | + T(i , j ); 54 | *quantity += diffusivity * jd * pow(1. / hy * dt, 2.); 55 | } 56 | } 57 | return 0; 58 | } 59 | 60 | /** 61 | * @brief compute dissipation of squared temperature 62 | * @param[in] fname : file name to which the log is written 63 | * @param[in] domain : information related to MPI domain decomposition 64 | * @param[in] time : current simulation time 65 | * @param[in] fluid : diffusivity and temperature field 66 | * @return : error code 67 | */ 68 | int logging_check_dissipated_squared_temperature ( 69 | const char fname[], 70 | const domain_t * domain, 71 | const double time, 72 | const fluid_t * fluid 73 | ) { 74 | const int root = 0; 75 | int myrank = root; 76 | MPI_Comm comm_cart = MPI_COMM_NULL; 77 | sdecomp.get_comm_rank(domain->info, &myrank); 78 | sdecomp.get_comm_cart(domain->info, &comm_cart); 79 | double quantity = 0.; 80 | get_dtdx(domain, fluid, &quantity); 81 | get_dtdy(domain, fluid, &quantity); 82 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : &quantity; 83 | void * recvbuf = &quantity; 84 | MPI_Reduce(sendbuf, recvbuf, 1, MPI_DOUBLE, MPI_SUM, root, comm_cart); 85 | logging_internal_output( 86 | fname, 87 | domain, 88 | time, 89 | 1, 90 | &quantity 91 | ); 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/logging/heat_transfer.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "fluid_solver.h" 4 | #include "array_macros/domain/hxxf.h" 5 | #include "array_macros/domain/jdxf.h" 6 | #include "array_macros/fluid/t.h" 7 | #include "internal.h" 8 | 9 | #define BEGIN \ 10 | for (int j = 1; j <= jsize; j++) { 11 | #define END \ 12 | } 13 | 14 | /** 15 | * @brief compute net heat transfer on the walls 16 | * @param[in] fname : file name to which the log is written 17 | * @param[in] domain : information related to MPI domain decomposition 18 | * @param[in] time : current simulation time 19 | * @param[in] fluid : diffusivity and temperature field 20 | * @return : error code 21 | */ 22 | int logging_check_heat_transfer ( 23 | const char fname[], 24 | const domain_t * domain, 25 | const double time, 26 | const fluid_t * fluid 27 | ) { 28 | const int root = 0; 29 | int myrank = root; 30 | MPI_Comm comm_cart = MPI_COMM_NULL; 31 | sdecomp.get_comm_rank(domain->info, &myrank); 32 | sdecomp.get_comm_cart(domain->info, &comm_cart); 33 | const int isize = domain->mysizes[0]; 34 | const int jsize = domain->mysizes[1]; 35 | const double * restrict hxxf = domain->hxxf; 36 | const double * restrict jdxf = domain->jdxf; 37 | const double * restrict t = fluid->t.data; 38 | // compute heat transfer on the walls 39 | const double diffusivity = fluid_compute_temperature_diffusivity(fluid); 40 | // on the bottom and top walls 41 | double energies[2] = {0., 0.}; 42 | BEGIN 43 | const double hx_xm = HXXF( 1); 44 | const double hx_xp = HXXF(isize + 1); 45 | const double jd_xm = JDXF( 1); 46 | const double jd_xp = JDXF(isize + 1); 47 | const double dt_xm = - T( 0, j) + T( 1, j); 48 | const double dt_xp = - T(isize, j) + T(isize + 1, j); 49 | energies[0] -= diffusivity * jd_xm / hx_xm / hx_xm * dt_xm; 50 | energies[1] -= diffusivity * jd_xp / hx_xp / hx_xp * dt_xp; 51 | END 52 | const size_t nitems = sizeof(energies) / sizeof(energies[0]); 53 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : energies; 54 | void * recvbuf = energies; 55 | MPI_Reduce(sendbuf, recvbuf, nitems, MPI_DOUBLE, MPI_SUM, root, comm_cart); 56 | logging_internal_output( 57 | fname, 58 | domain, 59 | time, 60 | nitems, 61 | energies 62 | ); 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/logging/injected_squared_velocity.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "array_macros/domain/jdxf.h" 4 | #include "array_macros/fluid/ux.h" 5 | #include "array_macros/fluid/t.h" 6 | #include "internal.h" 7 | 8 | #define BEGIN \ 9 | for (int j = 1; j <= jsize; j++) { \ 10 | for (int i = 2; i <= isize; i++) { 11 | #define END \ 12 | } \ 13 | } 14 | 15 | /** 16 | * @brief compute injected squared velocity 17 | * @param[in] fname : file name to which the log is written 18 | * @param[in] domain : information related to MPI domain decomposition 19 | * @param[in] time : current simulation time 20 | * @param[in] fluid : velocity and temperature field 21 | * @return : error code 22 | */ 23 | int logging_check_injected_squared_velocity ( 24 | const char fname[], 25 | const domain_t * domain, 26 | const double time, 27 | const fluid_t * fluid 28 | ) { 29 | const int root = 0; 30 | int myrank = root; 31 | MPI_Comm comm_cart = MPI_COMM_NULL; 32 | sdecomp.get_comm_rank(domain->info, &myrank); 33 | sdecomp.get_comm_cart(domain->info, &comm_cart); 34 | const int isize = domain->mysizes[0]; 35 | const int jsize = domain->mysizes[1]; 36 | const double * restrict jdxf = domain->jdxf; 37 | const double * restrict ux = fluid->ux.data; 38 | const double * restrict t = fluid-> t.data; 39 | // compute injected squared velocity 40 | double quantity = 0.; 41 | BEGIN 42 | const double jd_x0 = JDXF(i); 43 | const double ux_x0 = UX(i, j); 44 | const double t_x0 = 45 | + 0.5 * T(i-1, j ) 46 | + 0.5 * T(i , j ); 47 | quantity += jd_x0 * ux_x0 * t_x0; 48 | END 49 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : &quantity; 50 | void * recvbuf = &quantity; 51 | MPI_Reduce(sendbuf, recvbuf, 1, MPI_DOUBLE, MPI_SUM, root, comm_cart); 52 | logging_internal_output( 53 | fname, 54 | domain, 55 | time, 56 | 1, 57 | &quantity 58 | ); 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/logging/internal.h: -------------------------------------------------------------------------------- 1 | #if !defined(LOGGING_INTERNAL_H) 2 | #define LOGGING_INTERNAL_H 3 | 4 | extern int logging_internal_output ( 5 | const char fname[], 6 | const domain_t * domain, 7 | const double time, 8 | const size_t nitems, 9 | const double * items 10 | ); 11 | 12 | extern int logging_check_max_divergence ( 13 | const char fname[], 14 | const domain_t * domain, 15 | const double time, 16 | const fluid_t * fluid 17 | ); 18 | 19 | extern int logging_check_total_momentum ( 20 | const char fname[], 21 | const domain_t * domain, 22 | const double time, 23 | const fluid_t * fluid 24 | ); 25 | 26 | extern int logging_check_total_energy ( 27 | const char fname[], 28 | const domain_t * domain, 29 | const double time, 30 | const fluid_t * fluid 31 | ); 32 | 33 | extern int logging_check_heat_transfer ( 34 | const char fname[], 35 | const domain_t * domain, 36 | const double time, 37 | const fluid_t * fluid 38 | ); 39 | 40 | extern int logging_check_injected_squared_velocity ( 41 | const char fname[], 42 | const domain_t * domain, 43 | const double time, 44 | const fluid_t * fluid 45 | ); 46 | 47 | int logging_check_dissipated_squared_velocity ( 48 | const char fname[], 49 | const domain_t * domain, 50 | const double time, 51 | const fluid_t * fluid 52 | ); 53 | 54 | int logging_check_dissipated_squared_temperature ( 55 | const char fname[], 56 | const domain_t * domain, 57 | const double time, 58 | const fluid_t * fluid 59 | ); 60 | 61 | #endif // LOGGING_INTERNAL_H 62 | -------------------------------------------------------------------------------- /src/logging/max_divergence.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "array_macros/domain/hxxf.h" 5 | #include "array_macros/domain/jdxf.h" 6 | #include "array_macros/domain/jdxc.h" 7 | #include "array_macros/fluid/ux.h" 8 | #include "array_macros/fluid/uy.h" 9 | #include "internal.h" 10 | 11 | #define BEGIN \ 12 | for (int cnt = 0, j = 1; j <= jsize; j++) { \ 13 | for (int i = 1; i <= isize; i++, cnt++) { 14 | #define END \ 15 | } \ 16 | } 17 | 18 | /** 19 | * @brief check maximum divergence and write it to a file 20 | * @param[in] fname : file name to which the log is written 21 | * @param[in] domain : domain information 22 | * @param[in] time : current simulation time 23 | * @param[in] fluid : velocity 24 | * @return : error code 25 | */ 26 | int logging_check_max_divergence ( 27 | const char fname[], 28 | const domain_t * domain, 29 | const double time, 30 | const fluid_t * fluid 31 | ) { 32 | const int root = 0; 33 | int myrank = root; 34 | MPI_Comm comm_cart = MPI_COMM_NULL; 35 | sdecomp.get_comm_rank(domain->info, &myrank); 36 | sdecomp.get_comm_cart(domain->info, &comm_cart); 37 | const int isize = domain->mysizes[0]; 38 | const int jsize = domain->mysizes[1]; 39 | const double * restrict hxxf = domain->hxxf; 40 | const double hy = domain->hy; 41 | const double * restrict jdxf = domain->jdxf; 42 | const double * restrict jdxc = domain->jdxc; 43 | const double * restrict ux = fluid->ux.data; 44 | const double * restrict uy = fluid->uy.data; 45 | // check max local divergence 46 | double divmax = 0.; 47 | BEGIN 48 | const double hx_xm = HXXF(i ); 49 | const double hx_xp = HXXF(i+1); 50 | const double jd_xm = JDXF(i ); 51 | const double jd_x0 = JDXC(i ); 52 | const double jd_xp = JDXF(i+1); 53 | const double ux_xm = UX(i , j ); 54 | const double ux_xp = UX(i+1, j ); 55 | const double uy_ym = UY(i , j ); 56 | const double uy_yp = UY(i , j+1); 57 | const double div = 1. / jd_x0 * ( 58 | - jd_xm / hx_xm * ux_xm + jd_xp / hx_xp * ux_xp 59 | - jd_x0 / hy * uy_ym + jd_x0 / hy * uy_yp 60 | ); 61 | // check maximum 62 | divmax = fmax(divmax, fabs(div)); 63 | END 64 | // collect information among all processes 65 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : &divmax; 66 | void * recvbuf = &divmax; 67 | MPI_Reduce(sendbuf, recvbuf, 1, MPI_DOUBLE, MPI_MAX, root, comm_cart); 68 | logging_internal_output( 69 | fname, 70 | domain, 71 | time, 72 | 1, 73 | &divmax 74 | ); 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/logging/total_energy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "domain.h" 3 | #include "fluid.h" 4 | #include "array_macros/domain/jdxf.h" 5 | #include "array_macros/domain/jdxc.h" 6 | #include "array_macros/fluid/ux.h" 7 | #include "array_macros/fluid/uy.h" 8 | #include "array_macros/fluid/t.h" 9 | #include "internal.h" 10 | 11 | /** 12 | * @brief compute total quadratic quantities 13 | * @param[in] fname : file name to which the log is written 14 | * @param[in] domain : information related to MPI domain decomposition 15 | * @param[in] time : current simulation time 16 | * @param[in] fluid : velocity 17 | * @return : error code 18 | */ 19 | int logging_check_total_energy( 20 | const char fname[], 21 | const domain_t * domain, 22 | const double time, 23 | const fluid_t * fluid 24 | ) { 25 | const int root = 0; 26 | int myrank = root; 27 | MPI_Comm comm_cart = MPI_COMM_NULL; 28 | sdecomp.get_comm_rank(domain->info, &myrank); 29 | sdecomp.get_comm_cart(domain->info, &comm_cart); 30 | const int isize = domain->mysizes[0]; 31 | const int jsize = domain->mysizes[1]; 32 | const double * restrict jdxf = domain->jdxf; 33 | const double * restrict jdxc = domain->jdxc; 34 | const double * restrict ux = fluid->ux.data; 35 | const double * restrict uy = fluid->uy.data; 36 | const double * restrict t = fluid->t.data; 37 | // velocity for each dimension and scalar 38 | double quantities[NDIMS + 1] = {0.}; 39 | // compute quadratic quantity in x direction 40 | for (int j = 1; j <= jsize; j++) { 41 | for (int i = 2; i <= isize; i++) { 42 | quantities[0] += JDXF(i ) * 0.5 * pow(UX(i, j), 2.); 43 | } 44 | } 45 | // compute quadratic quantity in y direction 46 | for (int j = 1; j <= jsize; j++) { 47 | for (int i = 1; i <= isize; i++) { 48 | quantities[1] += JDXC(i ) * 0.5 * pow(UY(i, j), 2.); 49 | } 50 | } 51 | // compute quadratic quantity of scalar 52 | for (int j = 1; j <= jsize; j++) { 53 | for (int i = 1; i <= isize; i++) { 54 | quantities[NDIMS] += JDXC(i ) * 0.5 * pow(T(i, j), 2.); 55 | } 56 | } 57 | // output information 58 | const size_t nitems = sizeof(quantities) / sizeof(quantities[0]); 59 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : quantities; 60 | void * recvbuf = quantities; 61 | MPI_Reduce(sendbuf, recvbuf, nitems, MPI_DOUBLE, MPI_SUM, root, comm_cart); 62 | logging_internal_output( 63 | fname, 64 | domain, 65 | time, 66 | nitems, 67 | quantities 68 | ); 69 | return 0; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/logging/total_momentum.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "array_macros/domain/jdxf.h" 4 | #include "array_macros/domain/jdxc.h" 5 | #include "array_macros/fluid/ux.h" 6 | #include "array_macros/fluid/uy.h" 7 | #include "internal.h" 8 | 9 | /** 10 | * @brief compute total momenta 11 | * @param[in] fname : file name to which the log is written 12 | * @param[in] domain : information about domain decomposition and size 13 | * @param[in] time : current simulation time 14 | * @param[in] fluid : velocity 15 | * @return : error code 16 | */ 17 | int logging_check_total_momentum ( 18 | const char fname[], 19 | const domain_t * domain, 20 | const double time, 21 | const fluid_t * fluid 22 | ) { 23 | const int root = 0; 24 | int myrank = root; 25 | MPI_Comm comm_cart = MPI_COMM_NULL; 26 | sdecomp.get_comm_rank(domain->info, &myrank); 27 | sdecomp.get_comm_cart(domain->info, &comm_cart); 28 | const int isize = domain->mysizes[0]; 29 | const int jsize = domain->mysizes[1]; 30 | const double * restrict jdxf = domain->jdxf; 31 | const double * restrict jdxc = domain->jdxc; 32 | const double * restrict ux = fluid->ux.data; 33 | const double * restrict uy = fluid->uy.data; 34 | double momenta[NDIMS] = {0.}; 35 | // compute total x-momentum 36 | for (int j = 1; j <= jsize; j++) { 37 | for (int i = 2; i <= isize; i++) { 38 | momenta[0] += JDXF(i) * UX(i, j); 39 | } 40 | } 41 | // compute total y-momentum 42 | for (int j = 1; j <= jsize; j++) { 43 | for (int i = 1; i <= isize; i++) { 44 | momenta[1] += JDXC(i) * UY(i, j); 45 | } 46 | } 47 | const size_t nitems = sizeof(momenta) / sizeof(momenta[0]); 48 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : momenta; 49 | void * recvbuf = momenta; 50 | MPI_Reduce(sendbuf, recvbuf, nitems, MPI_DOUBLE, MPI_SUM, root, comm_cart); 51 | logging_internal_output( 52 | fname, 53 | domain, 54 | time, 55 | nitems, 56 | momenta 57 | ); 58 | return 0; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "memory.h" 4 | #include "timer.h" 5 | #include "domain.h" 6 | #include "fluid.h" 7 | #include "fluid_solver.h" 8 | #include "integrate.h" 9 | #include "statistics.h" 10 | #include "save.h" 11 | #include "logging.h" 12 | #include "config.h" 13 | #include "fileio.h" 14 | 15 | /** 16 | * @brief main function 17 | * @param[in] argc : number of arguments (expect 2) 18 | * @param[in] argv : name of the directory 19 | * where a set of initial condition is contained 20 | * @return : error code 21 | */ 22 | int main ( 23 | int argc, 24 | char * argv[] 25 | ) { 26 | // launch MPI, start timer 27 | MPI_Init(NULL, NULL); 28 | const int root = 0; 29 | int myrank = root; 30 | MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 31 | const double tic = timer(); 32 | // find name of directory where IC is stored 33 | if (2 != argc) { 34 | if (root == myrank) { 35 | printf("directory name should be given as input\n"); 36 | } 37 | goto abort; 38 | } 39 | const char * dirname_ic = argv[1]; 40 | // initialise fileio object 41 | if (0 != fileio.init()) { 42 | goto abort; 43 | } 44 | // initialise time step and time units 45 | size_t step = 0; 46 | if (0 != fileio.r_serial(dirname_ic, "step", 0, NULL, fileio.npy_size_t, sizeof(size_t), &step)) { 47 | goto abort; 48 | } 49 | double time = 0.; 50 | if (0 != fileio.r_serial(dirname_ic, "time", 0, NULL, fileio.npy_double, sizeof(double), &time)) { 51 | goto abort; 52 | } 53 | // initialise structures 54 | domain_t domain = {0}; 55 | if (0 != domain_init(dirname_ic, &domain)) { 56 | goto abort; 57 | } 58 | fluid_t fluid = {0}; 59 | if (0 != fluid_init(dirname_ic, &domain, &fluid)) { 60 | goto abort; 61 | } 62 | // initialise auxiliary objects 63 | if (0 != logging.init(&domain, time)) { 64 | goto abort; 65 | } 66 | if (0 != save.init(&domain, time)) { 67 | goto abort; 68 | } 69 | if (0 != statistics.init(&domain, time)) { 70 | goto abort; 71 | } 72 | // check termination conditions 73 | double timemax = 0.; 74 | if (0 != config.get_double("timemax", &timemax)) { 75 | goto abort; 76 | } 77 | double wtimemax = 0.; 78 | if (0 != config.get_double("wtimemax", &wtimemax)) { 79 | goto abort; 80 | } 81 | // report 82 | if (root == myrank) { 83 | printf("step: %zu, time: % .7e\n", step, time); 84 | printf("timemax: % .7e, wtimemax: % .7e\n", timemax, wtimemax); 85 | } 86 | // main loop 87 | for (;;) { 88 | // proceed for one step 89 | double dt = 0.; 90 | if (0 != integrate(&domain, &fluid, &dt)) { 91 | goto abort; 92 | } 93 | // update step and simulation / wall time 94 | step += 1; 95 | time += dt; 96 | const double toc = timer(); 97 | // terminate if one of the following conditions is met 98 | // the simulation is finished 99 | if (timemax < time) { 100 | break; 101 | } 102 | // wall time limit is reached 103 | if (wtimemax < toc - tic) { 104 | break; 105 | } 106 | // compute and output log regularly 107 | if (logging.get_next_time() < time) { 108 | logging.check_and_output(&domain, step, time, dt, toc - tic, &fluid); 109 | } 110 | // save flow fields regularly 111 | if (save.get_next_time() < time) { 112 | save.output(&domain, step, time, &fluid); 113 | } 114 | // collect statistics regularly 115 | if (statistics.get_next_time() < time) { 116 | statistics.collect(&domain, &fluid); 117 | } 118 | } 119 | // finalisation 120 | // save final flow fields 121 | save.output(&domain, step, time, &fluid); 122 | // save collected statistics 123 | statistics.output(&domain, step); 124 | // finalise MPI 125 | abort: 126 | MPI_Finalize(); 127 | return 0; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "memory.h" 5 | 6 | /** 7 | * @brief general-purpose memory allocator 8 | * @param[in] count : number of elements to be allocated 9 | * @param[in] size : size of each element 10 | * @return : pointer to the allocated buffer 11 | */ 12 | void * memory_calloc( 13 | const size_t count, 14 | const size_t size 15 | ){ 16 | // try to allocate 17 | void * ptr = calloc(count, size); 18 | if(NULL == ptr){ 19 | // failed to allocate 20 | FILE * stream = stderr; 21 | fprintf(stream, "memory allocation error: calloc(%zu, %zu)\n", count, size); 22 | fflush(stream); 23 | // since memory errors are fatal, I abort the program 24 | MPI_Barrier(MPI_COMM_WORLD); 25 | MPI_Abort(MPI_COMM_WORLD, 0); 26 | } 27 | return ptr; 28 | } 29 | 30 | /** 31 | * @brief corresponding memory deallocator 32 | * @param[in] ptr : pointer to the allocated buffer 33 | */ 34 | void memory_free( 35 | void * ptr 36 | ){ 37 | // for now just wrap free 38 | free(ptr); 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/param/boundary-condition.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | 3 | const double param_uy_xm = 0.; 4 | const double param_uy_xp = 0.; 5 | const double param_t_xm = + 0.5; 6 | const double param_t_xp = - 0.5; 7 | 8 | -------------------------------------------------------------------------------- /src/param/buoyancy.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | 3 | const bool param_add_buoyancy = true; 4 | 5 | -------------------------------------------------------------------------------- /src/param/implicit.c: -------------------------------------------------------------------------------- 1 | #include "param.h" 2 | 3 | const bool param_m_implicit_x = true; 4 | const bool param_m_implicit_y = false; 5 | 6 | const bool param_t_implicit_x = true; 7 | const bool param_t_implicit_y = false; 8 | 9 | -------------------------------------------------------------------------------- /src/runge_kutta.c: -------------------------------------------------------------------------------- 1 | #include // memset 2 | #include "array.h" 3 | #include "runge_kutta.h" 4 | 5 | // coefficients of three-stage Runge-Kutta scheme 6 | static const double a0 = + 32. / 60., b0 = 0. / 60.; 7 | static const double a1 = + 25. / 60., b1 = - 17. / 60.; 8 | static const double a2 = + 45. / 60., b2 = - 25. / 60.; 9 | const rkcoef_t rkcoefs[RKSTEPMAX] = { 10 | {.alpha = a0, .beta = b0, .gamma = a0 + b0}, 11 | {.alpha = a1, .beta = b1, .gamma = a1 + b1}, 12 | {.alpha = a2, .beta = b2, .gamma = a2 + b2}, 13 | }; 14 | 15 | int rkbuffers_init ( 16 | const domain_t * const domain, 17 | const int nadds[NDIMS][2], 18 | rkbuffers_t * const buffers 19 | ) { 20 | if (0 != array.create(domain, nadds, sizeof(double), &buffers->alpha)) { 21 | return 1; 22 | } 23 | if (0 != array.create(domain, nadds, sizeof(double), &buffers->beta )) { 24 | return 1; 25 | } 26 | if (0 != array.create(domain, nadds, sizeof(double), &buffers->gamma)) { 27 | return 1; 28 | } 29 | return 0; 30 | } 31 | 32 | int rkbuffers_reset ( 33 | rkbuffers_t * const buffers 34 | ) { 35 | array_t * const restrict alpha = &buffers->alpha; 36 | array_t * const restrict beta = &buffers->beta ; 37 | array_t * const restrict gamma = &buffers->gamma; 38 | // stash previous RK source term, 39 | // which is achieved by swapping 40 | // the pointers to "data" 41 | double * const tmp = alpha->data; 42 | alpha->data = beta ->data; 43 | beta ->data = tmp; 44 | // zero-clear current RK source terms (exp/imp) 45 | // NOTE: when 0 == rkstep, rkcoef for "beta" is zero 46 | // and thus zero-clearing"beta" buffers is not needed 47 | memset(alpha->data, 0, alpha->datasize); 48 | memset(gamma->data, 0, gamma->datasize); 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/save.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "sdecomp.h" 6 | #include "memory.h" 7 | #include "domain.h" 8 | #include "fluid.h" 9 | #include "save.h" 10 | #include "fileio.h" 11 | #include "config.h" 12 | 13 | // parameters to specify directory name 14 | static const char g_dirname_prefix[] = {"output/save/step"}; 15 | static const int g_dirname_ndigits = 10; 16 | 17 | // name of directory 18 | static char * g_dirname = NULL; 19 | static size_t g_dirname_nchars = 0; 20 | 21 | // scheduler 22 | static double g_rate = 0.; 23 | static double g_next = 0.; 24 | 25 | /** 26 | * @brief constructor - schedule saving flow fields 27 | * @param[in] domain : MPI communicator 28 | * @param[in] time : current time (hereafter in free-fall time units) 29 | */ 30 | static int init ( 31 | const domain_t * domain, 32 | const double time 33 | ) { 34 | // fetch timings 35 | if (0 != config.get_double("save_rate", &g_rate)) { 36 | return 1; 37 | } 38 | double after = 0.; 39 | if (0 != config.get_double("save_after", &after)) { 40 | return 1; 41 | } 42 | // schedule next event 43 | g_next = g_rate * ceil( 44 | fmax(DBL_EPSILON, fmax(time, after)) / g_rate 45 | ); 46 | // allocate directory name 47 | g_dirname_nchars = 48 | + strlen(g_dirname_prefix) 49 | + g_dirname_ndigits; 50 | g_dirname = memory_calloc(g_dirname_nchars + 2, sizeof(char)); 51 | // report 52 | const int root = 0; 53 | int myrank = root; 54 | sdecomp.get_comm_rank(domain->info, &myrank); 55 | if (root == myrank) { 56 | FILE * stream = stdout; 57 | fprintf(stream, "SAVE\n"); 58 | fprintf(stream, "\tdest: %s\n", g_dirname_prefix); 59 | fprintf(stream, "\tnext: % .3e\n", g_next); 60 | fprintf(stream, "\trate: % .3e\n", g_rate); 61 | fflush(stream); 62 | } 63 | return 0; 64 | } 65 | 66 | /** 67 | * @brief output an instantaneous flow field 68 | * @param[in] domain : information related to MPI domain decomposition 69 | * @param[in] step : time step 70 | * @param[in] time : current simulation time 71 | * @param[in] fluid : flow field 72 | */ 73 | static int output ( 74 | const domain_t * domain, 75 | const size_t step, 76 | const double time, 77 | const fluid_t * fluid 78 | ) { 79 | // set directory name 80 | snprintf( 81 | g_dirname, 82 | g_dirname_nchars + 1, 83 | "%s%0*zu", 84 | g_dirname_prefix, 85 | g_dirname_ndigits, 86 | step 87 | ); 88 | // get communicator to identify the main process 89 | const int root = 0; 90 | int myrank = root; 91 | sdecomp.get_comm_rank(domain->info, &myrank); 92 | // create directory 93 | if (root == myrank) { 94 | // although it may fail, anyway continue, which is designed to be safe 95 | fileio.mkdir(g_dirname); 96 | } 97 | // wait for the main process to complete making directory 98 | MPI_Barrier(MPI_COMM_WORLD); 99 | // save quantities 100 | if (root == myrank) { 101 | fileio.w_serial(g_dirname, "step", 0, NULL, fileio.npy_size_t, sizeof(size_t), &step); 102 | fileio.w_serial(g_dirname, "time", 0, NULL, fileio.npy_double, sizeof(double), &time); 103 | } 104 | domain_save(g_dirname, domain); 105 | fluid_save(g_dirname, domain, fluid); 106 | // schedule next saving event 107 | g_next += g_rate; 108 | return 0; 109 | } 110 | 111 | /** 112 | * @brief getter of a member: g_next 113 | * @return : g_next 114 | */ 115 | static double get_next_time ( 116 | void 117 | ) { 118 | return g_next; 119 | } 120 | 121 | const save_t save = { 122 | .init = init, 123 | .output = output, 124 | .get_next_time = get_next_time, 125 | }; 126 | 127 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "timer.h" 3 | 4 | /** 5 | * @brief get current time 6 | * @return : current time 7 | */ 8 | double timer( 9 | void 10 | ){ 11 | const int root = 0; 12 | // although this is called by all processes, 13 | double time = MPI_Wtime(); 14 | // use the result of the main process 15 | MPI_Bcast(&time, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); 16 | return time; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tools/README.rst: -------------------------------------------------------------------------------- 1 | ###### 2 | tools/ 3 | ###### 4 | 5 | **** 6 | Note 7 | **** 8 | 9 | Normally you do not have to pay attention to the files here. 10 | 11 | ***** 12 | Files 13 | ***** 14 | 15 | #. ``define_arrays.py`` 16 | 17 | This script defines macros to enable ``UX(i, j, k)`` notations in C. 18 | Since macros have already been included in the package, you do not have to regenerate them. 19 | 20 | --------------------------------------------------------------------------------