├── .github └── workflows │ ├── ci.yml │ ├── doc.yml │ └── extract_nd.py ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── docs ├── Makefile └── source │ ├── _static │ ├── alabaster.css_t │ └── custom.css │ ├── conf.py │ ├── conf_params │ ├── alabaster_params.py │ ├── mathjax_macro │ │ ├── discrete.py │ │ ├── general.py │ │ ├── momentum.py │ │ └── scalar.py │ ├── mathjax_params.py │ └── pstyle.py │ ├── discretisation │ ├── main.rst │ ├── spatial │ │ ├── incompressibility.rst │ │ ├── main.rst │ │ ├── momentum │ │ │ ├── main.rst │ │ │ ├── x │ │ │ │ ├── advection.rst │ │ │ │ ├── diffusion.rst │ │ │ │ ├── main.rst │ │ │ │ └── pressure.rst │ │ │ ├── y │ │ │ │ ├── advection.rst │ │ │ │ ├── diffusion.rst │ │ │ │ ├── main.rst │ │ │ │ └── pressure.rst │ │ │ └── z │ │ │ │ ├── advection.rst │ │ │ │ ├── diffusion.rst │ │ │ │ ├── main.rst │ │ │ │ └── pressure.rst │ │ ├── prerequisite │ │ │ ├── main.rst │ │ │ ├── scalar.rst │ │ │ ├── x.rst │ │ │ ├── y.rst │ │ │ └── z.rst │ │ ├── quad │ │ │ ├── advection.rst │ │ │ ├── diffusion.rst │ │ │ ├── main.rst │ │ │ └── pressure.rst │ │ ├── scalar.rst │ │ ├── symbol │ │ │ ├── average.rst │ │ │ ├── differentiation.rst │ │ │ ├── main.rst │ │ │ ├── scale_factor.rst │ │ │ └── summation.rst │ │ └── velocity_gradient_tensor.rst │ └── temporal │ │ ├── correction.rst │ │ └── main.rst │ ├── equation │ ├── figures │ │ ├── plot.gp │ │ └── result.png │ └── main.rst │ ├── example │ ├── energy │ │ ├── data │ │ │ ├── energy.py │ │ │ └── exec.sh │ │ └── main.rst │ ├── main.rst │ └── typical │ │ ├── data │ │ ├── balance_dif.py │ │ ├── balance_main.py │ │ ├── divergence.py │ │ ├── exec.sh │ │ └── snapshot.py │ │ └── main.rst │ ├── ext │ ├── mydetails.py │ └── myliteralinclude.py │ ├── index.rst │ ├── reference │ ├── main.rst │ └── reference.txt │ └── thumbnail.png ├── exec.sh ├── include ├── array.h ├── array_macros │ ├── domain │ │ ├── hxxc.h │ │ ├── hxxf.h │ │ ├── hyxc.h │ │ ├── hyxf.h │ │ ├── jdxc.h │ │ ├── jdxf.h │ │ ├── xc.h │ │ └── xf.h │ ├── fluid │ │ ├── lxx.h │ │ ├── lxy.h │ │ ├── lxz.h │ │ ├── lyx0.h │ │ ├── lyx1.h │ │ ├── lyy0.h │ │ ├── lyy1.h │ │ ├── lyz.h │ │ ├── lzx.h │ │ ├── lzy.h │ │ ├── lzz.h │ │ ├── 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 │ │ ├── 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 ├── 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 │ │ └── uz.c │ ├── compute_diffusivity.c │ ├── compute_potential.c │ ├── correct │ │ ├── internal.h │ │ ├── main.c │ │ ├── ux.c │ │ ├── uy.c │ │ └── uz.c │ ├── init.c │ ├── predict │ │ ├── internal.h │ │ ├── linear_system.c │ │ ├── lxx.c │ │ ├── lxy.c │ │ ├── lxz.c │ │ ├── lyx.c │ │ ├── lyy.c │ │ ├── lyz.c │ │ ├── lzx.c │ │ ├── lzy.c │ │ ├── lzz.c │ │ ├── main.c │ │ ├── t.c │ │ ├── ux.c │ │ ├── uy.c │ │ └── uz.c │ ├── save.c │ └── update_pressure.c ├── halo.c ├── integrate.c ├── linear_system.c ├── logging │ ├── dissipation.c │ ├── divergence.c │ ├── injection.c │ ├── internal.h │ ├── main.c │ └── total_energy.c ├── main.c ├── memory.c ├── param │ ├── boundary-condition.c │ └── implicit.c ├── runge_kutta.c ├── save.c ├── statistics.c ├── tdm.c └── timer.c └── tools ├── README.rst └── define_arrays.py /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - src/** 10 | - include/** 11 | - docs/source/example/typical/data/** 12 | - docs/source/example/energy/data/** 13 | workflow_dispatch: 14 | 15 | jobs: 16 | 17 | extract-nd: 18 | name: Create branch 2D and 3D which only contains the dimension and compile each 19 | permissions: 20 | contents: write 21 | strategy: 22 | matrix: 23 | dimension: [2, 3] 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@main 28 | with: 29 | repository: "NaokiHori/SimpleTCSolver" 30 | ref: "main" 31 | submodules: "recursive" 32 | - name: Install dependencies 33 | run: | 34 | sudo apt-get -y update && \ 35 | sudo apt-get -y install make libopenmpi-dev libfftw3-dev 36 | - name: Remove another dimension 37 | run: | 38 | set -x 39 | set -e 40 | python .github/workflows/extract_nd.py ${{ matrix.dimension }} 41 | - name: Modify Makefile 42 | run: | 43 | set -x 44 | set -e 45 | sed -i "s/DNDIMS=2/DNDIMS=${{ matrix.dimension }}/g" Makefile 46 | - name: Compile 47 | run: | 48 | make all 49 | - name: Commit and push change 50 | run: | 51 | set -x 52 | set -e 53 | git switch -c ${{ matrix.dimension }}d 54 | git config --local user.email "36466440+NaokiHori@users.noreply.github.com" 55 | git config --local user.name "NaokiHori" 56 | # add, commit, and push 57 | git add Makefile 58 | git add src 59 | git add include 60 | git commit -m "Extract ${{ matrix.dimension }}d sources" -a || true 61 | git push -f origin ${{ matrix.dimension }}d 62 | 63 | example-typical: 64 | name: Build library and try example - typical 65 | runs-on: ubuntu-latest 66 | needs: [extract-nd] 67 | steps: 68 | - name: Checkout repository 69 | uses: actions/checkout@main 70 | with: 71 | repository: 'NaokiHori/SimpleTCSolver' 72 | ref: '3d' 73 | submodules: "recursive" 74 | - name: Install dependencies 75 | run: | 76 | sudo apt-get -y update && \ 77 | sudo apt-get -y install make libopenmpi-dev libfftw3-dev 78 | - name: Install python dependencies for post-processings 79 | run: | 80 | python -m pip install --upgrade pip 81 | pip install numpy matplotlib 82 | - name: Pre-process, execute, and post-process 83 | run: | 84 | bash docs/source/example/typical/data/exec.sh 85 | - name: Upload artifacts 86 | uses: actions/upload-artifact@main 87 | with: 88 | name: typical 89 | path: artifacts 90 | 91 | example-energy: 92 | name: Build library and try example - energy 93 | runs-on: ubuntu-latest 94 | needs: [extract-nd] 95 | steps: 96 | - name: Checkout repository 97 | uses: actions/checkout@main 98 | with: 99 | repository: 'NaokiHori/SimpleTCSolver' 100 | ref: '3d' 101 | submodules: "recursive" 102 | - name: Install dependencies 103 | run: | 104 | sudo apt-get -y update && \ 105 | sudo apt-get -y install make libopenmpi-dev libfftw3-dev 106 | - name: Install python dependencies for post-processings 107 | run: | 108 | python -m pip install --upgrade pip 109 | pip install numpy matplotlib 110 | - name: Pre-process, execute, and post-process 111 | run: | 112 | bash docs/source/example/energy/data/exec.sh 113 | - name: Upload artifacts 114 | uses: actions/upload-artifact@main 115 | with: 116 | name: energy 117 | path: artifacts 118 | 119 | unify-and-push-artifacts: 120 | name: Gather artifacts and push them to a branch 121 | permissions: 122 | contents: write 123 | runs-on: ubuntu-latest 124 | needs: [example-energy, example-typical] 125 | env: 126 | BRANCH_NAME: artifacts 127 | DIRECTORY_NAME: artifacts 128 | steps: 129 | - name: Checkout repository 130 | uses: actions/checkout@main 131 | with: 132 | repository: 'NaokiHori/SimpleTCSolver' 133 | ref: ${{ github.ref_name }} 134 | - name: Download artifacts 135 | uses: actions/download-artifact@main 136 | with: 137 | path: ${{ env.DIRECTORY_NAME }} 138 | - name: Check artifacts 139 | run: | 140 | ls -R ${{ env.DIRECTORY_NAME }} 141 | - name: Push artifacts 142 | run: | 143 | set -x 144 | set -e 145 | git config --local user.email "36466440+NaokiHori@users.noreply.github.com" 146 | git config --local user.name "NaokiHori" 147 | git switch -c ${{ env.BRANCH_NAME }} 148 | git add ${{ env.DIRECTORY_NAME }} 149 | git commit -m "Update artifacts" -a || true 150 | git push -f origin ${{ env.BRANCH_NAME }} 151 | 152 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - docs/** 10 | workflow_dispatch: 11 | 12 | jobs: 13 | 14 | build-and-deploy-doc: 15 | name: Build and deploy documentation 16 | permissions: 17 | contents: read 18 | pages: write 19 | id-token: write 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: true 23 | environment: 24 | name: github-pages 25 | url: ${{ steps.deployment.outputs.page_url }} 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@main 30 | with: 31 | repository: 'NaokiHori/SimpleTCSolver' 32 | ref: ${{ github.ref_name }} 33 | - name: Build documentation using Sphinx 34 | run: | 35 | docker run \ 36 | --rm \ 37 | --volume ${PWD}:/project \ 38 | --workdir /project \ 39 | sphinxdoc/sphinx:latest \ 40 | sphinx-build docs/source docs/build 41 | - name: Setup GitHub Pages 42 | uses: actions/configure-pages@main 43 | - name: Upload HTML 44 | uses: actions/upload-pages-artifact@main 45 | with: 46 | path: docs/build 47 | - name: Deploy to GitHub Pages 48 | id: deployment 49 | uses: actions/deploy-pages@main 50 | 51 | -------------------------------------------------------------------------------- /.github/workflows/extract_nd.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import glob 4 | import enum 5 | 6 | 7 | def get_filenames(root): 8 | results = glob.glob(f"{root}/**", recursive=True) 9 | retvals = list() 10 | for result in results: 11 | if result.endswith(".c") or result.endswith(".h"): 12 | retvals.append(result) 13 | return retvals 14 | 15 | 16 | class NdimsType(enum.Enum): 17 | IN_2D = enum.auto() 18 | IN_3D = enum.auto() 19 | OTHER = enum.auto() 20 | 21 | 22 | def extract_given_dim(ndims, lines): 23 | state = NdimsType.OTHER 24 | if_level = 0 25 | if_level_ndims = 0 26 | newlines = list() 27 | for line in lines: 28 | is_on_ndims_macro = False 29 | if "#if" in line: 30 | # found "if", increase nest counter 31 | if_level += 1 32 | if " NDIMS" in line: 33 | if "NDIMS==2" in line.replace(" ", ""): 34 | is_on_ndims_macro = True 35 | # now in 2D condition 36 | state = NdimsType.IN_2D 37 | if_level_ndims = if_level 38 | if "NDIMS==3" in line.replace(" ", ""): 39 | is_on_ndims_macro = True 40 | # now in 3D condition 41 | state = NdimsType.IN_3D 42 | if_level_ndims = if_level 43 | elif "#else" in line: 44 | # check this "else" is for ndims 45 | if if_level == if_level_ndims: 46 | is_on_ndims_macro = True 47 | # if it is, swap state (3d if now 2d, vice versa) 48 | if state == NdimsType.IN_2D: 49 | state = NdimsType.IN_3D 50 | elif state == NdimsType.IN_3D: 51 | state = NdimsType.IN_2D 52 | else: 53 | print("else found but if not found beforehand") 54 | sys.exit() 55 | elif "#endif" in line: 56 | if if_level == if_level_ndims: 57 | is_on_ndims_macro = True 58 | state = NdimsType.OTHER 59 | # found "endif", reduce nest counter 60 | if_level -= 1 61 | if not is_on_ndims_macro: 62 | # we do not include macro about ndims 63 | if ndims == 2 and state != NdimsType.IN_3D: 64 | newlines.append(line) 65 | if ndims == 3 and state != NdimsType.IN_2D: 66 | newlines.append(line) 67 | return newlines 68 | 69 | 70 | def modify_comments(lines): 71 | """ 72 | there are weird comments which are used by Sphinx, which look like 73 | // | 74 | I use this function to modify this kind of stuffs as 75 | // 76 | """ 77 | delim = " | " 78 | newlines = list() 79 | for line in lines: 80 | if "//" in line and delim in line: 81 | line = line.split(delim)[0] + "\n" 82 | newlines.append(line) 83 | return newlines 84 | 85 | 86 | def adjust_blank_lines(lines): 87 | """ 88 | this function merges two (and more) successive blank lines 89 | into one blank 90 | """ 91 | nitems = len(lines) 92 | flags = [True for _ in range(nitems)] 93 | for n in range(1, nitems): 94 | # check two neighbouring lines 95 | l0 = lines[n - 1] 96 | l1 = lines[n] 97 | if "\n" == l0 and "\n" == l1: 98 | flags[n] = False 99 | newlines = list() 100 | for line, flag in zip(lines, flags): 101 | if flag: 102 | newlines.append(line) 103 | return newlines 104 | 105 | 106 | def main(): 107 | argv = sys.argv 108 | # sanitise input 109 | assert 2 == len(argv) 110 | ndims = int(argv[1]) 111 | # input source files 112 | fnames = list() 113 | fnames += get_filenames("src") 114 | fnames += get_filenames("include") 115 | for fname in fnames: 116 | with open(fname, "r") as f: 117 | lines = f.readlines() 118 | lines = extract_given_dim(ndims, lines) 119 | lines = modify_comments(lines) 120 | lines = adjust_blank_lines(lines) 121 | if 0 == len(lines): 122 | # nothing remains, delete file 123 | os.system(f"rm {fname}") 124 | continue 125 | # dump 126 | lines = "".join(lines) 127 | with open(fname, "w") as f: 128 | f.write(lines) 129 | 130 | 131 | if __name__ == "__main__": 132 | main() 133 | -------------------------------------------------------------------------------- /.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) 2022 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=3 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple TC Solver 2 | 3 | [![License](https://img.shields.io/github/license/NaokiHori/SimpleTCSolver)](https://opensource.org/license/MIT) 4 | [![Last Commit](https://img.shields.io/github/last-commit/NaokiHori/SimpleTCSolver/main)](https://github.com/NaokiHori/SimpleTCSolver/commits/main) 5 | [![CI](https://github.com/NaokiHori/SimpleTCSolver/actions/workflows/ci.yml/badge.svg)](https://github.com/NaokiHori/SimpleTCSolver/actions/workflows/ci.yml) 6 | [![Documentation](https://github.com/NaokiHori/SimpleTCSolver/actions/workflows/doc.yml/badge.svg)](https://github.com/NaokiHori/SimpleTCSolver/actions/workflows/doc.yml) 7 | 8 | ![Thumbnail](https://github.com/NaokiHori/SimpleTCSolver/blob/main/docs/source/thumbnail.png) 9 | 10 | ## Overview 11 | 12 | This library numerically solves the incompressible Navier-Stokes equations in both two-dimensional and three-dimensional planar and curved channels using the finite-difference method. While the primary objective is to simulate Taylor-Couette flows, the solver can also be applied to planar flow simulations. 13 | 14 | For details on the governing equations and numerical methods ensuring conservative and consistent schemes, refer to the [documentation](https://naokihori.github.io/SimpleTCSolver). 15 | 16 | ## Features 17 | 18 | - Energy-consistent treatment of advective, pressure-gradient, and diffusive terms, ensuring proper conservation properties. 19 | - [MPI parallelization](https://github.com/NaokiHori/SimpleDecomp). 20 | - Efficient FFT-based direct Poisson solver. 21 | - Explicit and implicit treatments of diffusive terms in all spatial directions. 22 | - Scalar transport simulation. 23 | 24 | ## Dependencies 25 | 26 | - [C compiler](https://gcc.gnu.org) 27 | - [MPI](https://www.open-mpi.org) 28 | - [FFTW3](https://www.fftw.org) 29 | - [Python3](https://www.python.org) (only required for initializing flow fields in `NPY` format) 30 | 31 | ## Quick Start 32 | 33 | 1. **Set up your workspace** 34 | 35 | ```console 36 | mkdir -p /path/to/your/directory 37 | cd /path/to/your/directory 38 | ``` 39 | 40 | 2. **Clone the repository** 41 | 42 | ```console 43 | git clone --recurse-submodules https://github.com/NaokiHori/SimpleTCSolver 44 | cd SimpleTCSolver 45 | ``` 46 | 47 | 3. **Set initial conditions** 48 | 49 | `Python3` is used to generate the initial flow fields as `NPY` files. 50 | 51 | ```console 52 | cd initial_condition 53 | make output 54 | bash main.sh 55 | cd .. 56 | ``` 57 | 58 | 4. **Build the solver** 59 | 60 | ```console 61 | make output 62 | make all 63 | ``` 64 | 65 | ## Example Results 66 | 67 | ### Instantaneous Velocity Field 68 | 69 | ![Velocity Field](https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/snapshot.png) 70 | 71 | ### Maximum Divergence 72 | 73 | ![Divergence](https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/divergence.png) 74 | 75 | ### Normalized Energy Injection and Dissipation 76 | 77 | ![Energy Balance](https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/balance_main.png) 78 | 79 | The black-dashed line represents reference results from Ostilla et al., *J. Fluid Mech. (719), 2013*. 80 | 81 | The numerical scheme is designed to ensure energy injection and dissipation remain perfectly balanced (up to rounding error) in steady states: 82 | 83 | ![Energy Dissipation](https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/balance_dif.png) 84 | 85 | ## 2D Version 86 | 87 | Since Taylor-Couette flows are inherently three-dimensional, the default solver is designed for 3D simulations. However, a 2D version that extracts radial-azimuthal motions is available in the `2d` branch. 88 | 89 | ## Planar Flows 90 | 91 | This solver can also be used for planar flow simulations (e.g., normal channel flows). To enable this mode, set the `is_curved` flag in the flow initializer to `false`. For more details, refer to the [documentation](https://naokihori.github.io/SimpleTCSolver). 92 | 93 | ## Acknowledgement 94 | 95 | I would like to thank [Dr. Kazuyasu Sugiyama](https://researchmap.jp/50466786) for insightful discussions at *Flow for Future - PoF25* and the *37th CFD Symposium*. 96 | 97 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | SPHINXOPTS ?= 2 | SPHINXBUILD ?= sphinx-build 3 | SOURCEDIR = source 4 | BUILDDIR = build 5 | 6 | .PHONY: Makefile 7 | 8 | help: 9 | @echo "all : build" 10 | @echo "clean : clean-up" 11 | 12 | all: 13 | $(SPHINXBUILD) $(SOURCEDIR) $(BUILDDIR) 14 | 15 | clean: 16 | $(RM) -r $(BUILDDIR) 17 | -------------------------------------------------------------------------------- /docs/source/_static/custom.css: -------------------------------------------------------------------------------- 1 | div.body { 2 | max-width: none; 3 | } 4 | 5 | div.MathJax_Display { 6 | overflow-x: scroll; 7 | overflow-y: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /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 = "SimpleTCSolver" 8 | author = "Naoki Hori" 9 | copyright = f"2023, {author}" 10 | 11 | extensions = [ 12 | "myliteralinclude", 13 | "mydetails", 14 | ] 15 | 16 | from alabaster_params import html_theme 17 | from alabaster_params import html_static_path 18 | from alabaster_params import html_theme_options 19 | 20 | from mathjax_params import mathjax_path 21 | from mathjax_params import mathjax3_config 22 | 23 | pygments_style = "pstyle.MyAlabaster" 24 | 25 | -------------------------------------------------------------------------------- /docs/source/conf_params/alabaster_params.py: -------------------------------------------------------------------------------- 1 | html_theme = "alabaster" 2 | html_static_path = ["_static"] 3 | html_theme_options = { 4 | "description": "Massively-parallelised NS solver for planar and curved channel flows", 5 | "fixed_sidebar": "false", 6 | "github_banner": "false", 7 | "github_button": "true", 8 | "github_count": "true", 9 | "github_repo": "SimpleTCSolver", 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": "280px", 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/conf_params/mathjax_macro/general.py: -------------------------------------------------------------------------------- 1 | def add(macros): 2 | # coordinate 3 | macros["vx"] = "{x}" 4 | macros["vy"] = "{y}" 5 | macros["vr"] = "{r}" 6 | macros["vt"] = "{\\theta}" 7 | macros["vz"] = "{z}" 8 | # a symbol used to denote general coordinate 9 | macros["gcs"] = ["{\\xi^{#1}}", 1] 10 | # velocity and scalar 11 | macros["vel"] = ["{u_{#1}}", 1] 12 | macros["scalar"] = "{T}" 13 | # quadratic quantities 14 | macros["quad"] = ["{k_{#1}}", 1] 15 | # scale factors 16 | macros["sfact"] = ["{h_{\\gcs{#1}}}", 1] 17 | # velocity-gradient tensor and shear-stress tensor 18 | macros["vgt"] = ["{l_{#1 #2}}", 2] 19 | macros["sst"] = ["{\\tau_{#1 #2}}", 2] 20 | # derivatives 21 | macros["pder"] = ["{\\frac{\\partial #1}{\\partial #2}}", 2] 22 | macros["dder"] = ["{\\frac{\\delta #1}{\\delta #2}}", 2] 23 | # discrete operators 24 | macros["ave"] = ["{\\overline{#1}^{#2}}", 2] 25 | macros["dif"] = ["{\\delta_{#2} {#1}}", 2] 26 | macros["vat"] = ["{\\left. {#1} \\right|_{#2}}", 2] 27 | -------------------------------------------------------------------------------- /docs/source/conf_params/mathjax_macro/momentum.py: -------------------------------------------------------------------------------- 1 | def add(macros): 2 | # temporal derivatives 3 | macros["momtemp"] = [ 4 | ( 5 | "\\pder{\\vel{#1}}{t}" 6 | ), 7 | 1 8 | ] 9 | 10 | # conservative advective terms 11 | # 1st argument: direction to which transported 12 | # 2nd argument: transported velocity 13 | macros["momadv"] = [ 14 | ( 15 | "-" 16 | "\\frac{\\vel{#1}}{\\sfact{#1}}" 17 | "\\pder{\\vel{#2}}{\\gcs{#1}}" 18 | ), 19 | 2 20 | ] 21 | 22 | # additional advective term in x 23 | macros["momadvx"] = ( 24 | "+" 25 | "\\frac{1}{J}" 26 | "\\pder{}{\\gcs{1}}" 27 | "\\left(" 28 | " \\frac{J}{\\sfact{1}}" 29 | "\\right)" 30 | "\\vel{2}" 31 | "\\vel{2}" 32 | ) 33 | 34 | # additional advective term in y 35 | macros["momadvy"] = ( 36 | "-" 37 | "\\frac{1}{J}" 38 | "\\pder{}{\\gcs{1}}" 39 | "\\left(" 40 | " \\frac{J}{\\sfact{1}}" 41 | "\\right)" 42 | "\\vel{2}" 43 | "\\vel{1}" 44 | ) 45 | 46 | # pressure-gradient terms 47 | macros["mompre"] = [ 48 | ( 49 | "-" 50 | "\\frac{1}{h_{\\gcs{#1}}}" 51 | "\\pder{p}{\\gcs{#1}}" 52 | ), 53 | 1 54 | ] 55 | 56 | # conservative diffusive terms 57 | # 1st argument: direction to which transported 58 | # 2nd argument: transported velocity 59 | macros["momdif"] = [ 60 | ( 61 | "+" 62 | "\\frac{1}{J}" 63 | "\\pder{}{\gcs{#1}}" 64 | "\\left(" 65 | " \\frac{" 66 | " J" 67 | " }{" 68 | " \\sfact{#1}" 69 | " }" 70 | " \\sst{#1}{#2}" 71 | "\\right)" 72 | ), 73 | 2 74 | ] 75 | 76 | # additional diffusive term in x 77 | macros["momdifx"] = [ 78 | ( 79 | "-" 80 | "\\frac{1}{J}" 81 | "\\pder{}{\\gcs{1}}" 82 | "\\left(" 83 | " \\frac{J}{\\sfact{1}}" 84 | "\\right)" 85 | "\\sst{2}{2}" 86 | ) 87 | ] 88 | 89 | # additional diffusive term in y 90 | macros["momdify"] = [ 91 | ( 92 | "+" 93 | "\\frac{1}{J}" 94 | "\\pder{}{\\gcs{1}}" 95 | "\\left(" 96 | " \\frac{J}{\\sfact{1}}" 97 | "\\right)" 98 | "\\sst{2}{1}" 99 | ) 100 | ] 101 | 102 | -------------------------------------------------------------------------------- /docs/source/conf_params/mathjax_macro/scalar.py: -------------------------------------------------------------------------------- 1 | def add(macros): 2 | # temporal derivatives 3 | macros["scalartemp"] = ( 4 | "\\pder{\\scalar}{t}" 5 | ) 6 | 7 | # conservative advective terms 8 | macros["scalaradv"] = [ 9 | ( 10 | "-" 11 | "\\frac{\\vel{#1}}{\\sfact{#1}}" 12 | "\\pder{\\scalar}{\\gcs{#1}}" 13 | ), 14 | 1 15 | ] 16 | 17 | # conservative diffusive terms 18 | macros["scalardif"] = [ 19 | ( 20 | "+" 21 | "\\kappa" 22 | "\\frac{1}{J}" 23 | "\\pder{}{\gcs{#1}}" 24 | "\\left(" 25 | " \\frac{" 26 | " J" 27 | " }{" 28 | " \\sfact{#1}" 29 | " }" 30 | " \\frac{1}{\\sfact{#1}}" 31 | " \\pder{\\scalar}{\\gcs{#1}}" 32 | "\\right)" 33 | ), 34 | 1 35 | ] 36 | 37 | -------------------------------------------------------------------------------- /docs/source/conf_params/mathjax_params.py: -------------------------------------------------------------------------------- 1 | from mathjax_macro.general import add as add_general 2 | from mathjax_macro.momentum import add as add_momentum 3 | from mathjax_macro.scalar import add as add_scalar 4 | from mathjax_macro.discrete import add as add_discrete 5 | 6 | mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML" 7 | 8 | macros = dict() 9 | 10 | add_general(macros) 11 | add_momentum(macros) 12 | add_scalar(macros) 13 | add_discrete(macros) 14 | 15 | mathjax3_config = {"TeX": {"Macros": macros}} 16 | -------------------------------------------------------------------------------- /docs/source/conf_params/pstyle.py: -------------------------------------------------------------------------------- 1 | # ref: alabaster/support.py 2 | 3 | from pygments.style import Style 4 | from pygments.token import ( 5 | Keyword, 6 | Name, 7 | Comment, 8 | String, 9 | Error, 10 | Number, 11 | Operator, 12 | Generic, 13 | Whitespace, 14 | Punctuation, 15 | Other, 16 | Literal, 17 | ) 18 | 19 | # color fliped 20 | 21 | class MyAlabaster(Style): 22 | background_color = "#070707" 23 | default_style = "" 24 | styles = { 25 | Error: "#5BFFFF border:#10D6D6", 26 | Other: "#FFFFFF", 27 | Comment: "italic #70A6FD", 28 | Comment.Preproc: "noitalic", 29 | Keyword: "bold #FFBB9E", 30 | Keyword.Constant: "bold #FFBB9E", 31 | Keyword.Declaration: "bold #FFBB9E", 32 | Keyword.Namespace: "bold #FFBB9E", 33 | Keyword.Pseudo: "bold #FFBB9E", 34 | Keyword.Reserved: "bold #FFBB9E", 35 | Keyword.Type: "bold #FFBB9E", 36 | Operator: "#A7D7FF", 37 | Operator.Word: "bold #FFBB9E", 38 | Punctuation: "bold #FFFFFF", 39 | Name: "#FFFFFF", 40 | Name.Attribute: "#3B5FFF", 41 | Name.Builtin: "#FFBB9E", 42 | Name.Builtin.Pseudo: "#CB9A5B", 43 | Name.Class: "#FFFFFF", 44 | Name.Constant: "#FFFFFF", 45 | Name.Decorator: "#888", 46 | Name.Entity: "#31A3FF", 47 | Name.Exception: "bold #33FFFF", 48 | Name.Function: "#FFFFFF", 49 | Name.Property: "#FFFFFF", 50 | Name.Label: "#0A86FF", 51 | Name.Namespace: "#FFFFFF", 52 | Name.Other: "#FFFFFF", 53 | Name.Tag: "bold #FFBB9E", 54 | Name.Variable: "#FFFFFF", 55 | Name.Variable.Class: "#FFFFFF", 56 | Name.Variable.Global: "#FFFFFF", 57 | Name.Variable.Instance: "#FFFFFF", 58 | Number: "#66FFFF", 59 | Literal: "#FFFFFF", 60 | Literal.Date: "#FFFFFF", 61 | String: "#B165F9", 62 | String.Backtick: "#B165F9", 63 | String.Char: "#B165F9", 64 | String.Doc: "italic #70A6FD", 65 | String.Double: "#B165F9", 66 | String.Escape: "#B165F9", 67 | String.Heredoc: "#B165F9", 68 | String.Interpol: "#B165F9", 69 | String.Other: "#B165F9", 70 | String.Regex: "#B165F9", 71 | String.Single: "#B165F9", 72 | String.Symbol: "#B165F9", 73 | Generic: "#FFFFFF", 74 | Generic.Deleted: "#5BFFFF", 75 | Generic.Emph: "italic #FFFFFF", 76 | Generic.Error: "#10D6D6", 77 | Generic.Heading: "bold #FFFF7F", 78 | Generic.Inserted: "#FF5FFF", 79 | Generic.Output: "#888", 80 | Generic.Prompt: "#8BACCB", 81 | Generic.Strong: "bold #FFFFFF", 82 | Generic.Subheading: "bold #7FFF7F", 83 | Generic.Traceback: "bold #5BFFFF", 84 | } 85 | 86 | -------------------------------------------------------------------------------- /docs/source/discretisation/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _discretisation: 3 | 4 | ############## 5 | Discretisation 6 | ############## 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | spatial/main 12 | temporal/main 13 | 14 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/incompressibility.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _discrete_incompressibility: 3 | 4 | ############################ 5 | Incompressibility constraint 6 | ############################ 7 | 8 | The incompressibility constraint is defined at each cell center: 9 | 10 | .. math:: 11 | 12 | \ddiv. 13 | 14 | The (left-hand-side of) incompressibility constraint is computed to find the right-hand-side term of the Poisson equation: 15 | 16 | .. myliteralinclude:: /../../src/fluid/compute_potential.c 17 | :language: c 18 | :tag: local divergence 19 | 20 | and to monitor the maximum divergence of the flow field as a logging process: 21 | 22 | .. myliteralinclude:: /../../src/logging/divergence.c 23 | :language: c 24 | :tag: local divergence 25 | 26 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/main.rst: -------------------------------------------------------------------------------- 1 | ###################### 2 | Spatial discretisation 3 | ###################### 4 | 5 | .. note:: 6 | 7 | I would like to acknowledge `Dr. Kazuyasu Sugiyama `_ for fruitful discussions at *Flow for Future - PoF25* and *37th CFD Symposium*. 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | 12 | symbol/main 13 | prerequisite/main 14 | velocity_gradient_tensor 15 | incompressibility 16 | momentum/main 17 | scalar 18 | quad/main 19 | 20 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/main.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _discrete_momentum: 3 | 4 | ################ 5 | Momentum balance 6 | ################ 7 | 8 | The wall-normal, stream-wise, and span-wise momentum equations are defined at :math:`\gcs{1}`, :math:`\gcs{2}`, and :math:`\gcs{3}` cell faces, respectively. 9 | 10 | Note that, to circumvent severe time-step constraints, diagonal terms of the diffusive terms can be treated implicitly in time, which makes the implementation a bit complex. 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | 15 | x/main.rst 16 | y/main.rst 17 | z/main.rst 18 | 19 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/x/advection.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Advection 3 | ######### 4 | 5 | ********************* 6 | Wall-normal component 7 | ********************* 8 | 9 | .. math:: 10 | 11 | \dmomadv{1}{1} 12 | 13 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 14 | :language: c 15 | :tag: ux is advected in x 16 | 17 | ********************* 18 | Stream-wise component 19 | ********************* 20 | 21 | .. math:: 22 | 23 | \dmomadv{1}{2} 24 | 25 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 26 | :language: c 27 | :tag: ux is advected in y 28 | 29 | ******************* 30 | Span-wise component 31 | ******************* 32 | 33 | .. math:: 34 | 35 | \dmomadv{1}{3} 36 | 37 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 38 | :language: c 39 | :tag: ux is advected in z 40 | 41 | ******************** 42 | Additional component 43 | ******************** 44 | 45 | .. math:: 46 | 47 | \dmomadvx 48 | 49 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 50 | :language: c 51 | :tag: centrifugal effect 52 | 53 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/x/diffusion.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Diffusion 3 | ######### 4 | 5 | ********************** 6 | Wall-normal derivative 7 | ********************** 8 | 9 | .. math:: 10 | 11 | \dmomdif{1}{1} 12 | = 13 | 2 14 | \mu 15 | \frac{1}{J} 16 | \dif{}{\gcs{1}} 17 | \left( 18 | \frac{J}{\sfact{1}} 19 | \vgt{1}{1} 20 | \right) 21 | = 22 | 2 23 | \mu 24 | \frac{1}{J} 25 | \dif{}{\gcs{1}} 26 | \left( 27 | \frac{J}{\sfact{1}} 28 | \dlxx 29 | \right) 30 | 31 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 32 | :language: c 33 | :tag: second-order derivative in x 34 | 35 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 36 | :language: c 37 | :tag: diffusion in x 38 | 39 | ********************** 40 | Stream-wise derivative 41 | ********************** 42 | 43 | .. math:: 44 | 45 | \dmomdif{2}{1} 46 | = 47 | \mu 48 | \frac{1}{J} 49 | \dif{}{\gcs{2}} 50 | \left( 51 | \frac{J}{\sfact{2}} 52 | \vgt{2}{1} 53 | \right) 54 | + 55 | \mu 56 | \frac{1}{J} 57 | \dif{}{\gcs{2}} 58 | \left( 59 | \frac{J}{\sfact{2}} 60 | \vgt{1}{2} 61 | \right) 62 | 63 | ============= 64 | Diagonal part 65 | ============= 66 | 67 | .. math:: 68 | 69 | \mu 70 | \frac{1}{J} 71 | \dif{}{\gcs{2}} 72 | \left( 73 | \frac{J}{\sfact{2}} 74 | \vgt{2}{1}^{\prime} 75 | \right) 76 | = 77 | \mu 78 | \frac{1}{J} 79 | \dif{}{\gcs{2}} 80 | \left( 81 | \frac{J}{\sfact{2}} 82 | \dlyxa 83 | \right) 84 | 85 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 86 | :language: c 87 | :tag: second-order derivative in y 88 | 89 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 90 | :language: c 91 | :tag: diffusion in y, 0 92 | 93 | ================= 94 | Non-diagonal part 95 | ================= 96 | 97 | .. math:: 98 | 99 | \mu 100 | \frac{1}{J} 101 | \dif{}{\gcs{2}} 102 | \left( 103 | \frac{J}{\sfact{2}} 104 | \vgt{2}{1}^{\prime\prime} 105 | \right) 106 | + 107 | \mu 108 | \frac{1}{J} 109 | \dif{}{\gcs{2}} 110 | \left( 111 | \frac{J}{\sfact{2}} 112 | \vgt{1}{2} 113 | \right) 114 | 115 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 116 | :language: c 117 | :tag: diffusion in y, 1 118 | 119 | ******************** 120 | Span-wise derivative 121 | ******************** 122 | 123 | .. math:: 124 | 125 | \dmomdif{3}{1} 126 | = 127 | \mu 128 | \frac{1}{J} 129 | \dif{}{\gcs{3}} 130 | \left( 131 | \frac{J}{\sfact{3}} 132 | \vgt{3}{1} 133 | \right) 134 | + 135 | \mu 136 | \frac{1}{J} 137 | \dif{}{\gcs{3}} 138 | \left( 139 | \frac{J}{\sfact{3}} 140 | \vgt{1}{3} 141 | \right) 142 | 143 | ============= 144 | Diagonal part 145 | ============= 146 | 147 | .. math:: 148 | 149 | \mu 150 | \frac{1}{J} 151 | \dif{}{\gcs{3}} 152 | \left( 153 | \frac{J}{\sfact{3}} 154 | \vgt{3}{1} 155 | \right) 156 | = 157 | \mu 158 | \frac{1}{J} 159 | \dif{}{\gcs{3}} 160 | \left( 161 | \frac{J}{\sfact{3}} 162 | \dlzx 163 | \right) 164 | 165 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 166 | :language: c 167 | :tag: second-order derivative in z 168 | 169 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 170 | :language: c 171 | :tag: diffusion in z, 0 172 | 173 | ================= 174 | Non-diagonal part 175 | ================= 176 | 177 | .. math:: 178 | 179 | \mu 180 | \frac{1}{J} 181 | \dif{}{\gcs{3}} 182 | \left( 183 | \frac{J}{\sfact{3}} 184 | \vgt{1}{3} 185 | \right) 186 | 187 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 188 | :language: c 189 | :tag: diffusion in z, 1 190 | 191 | *************** 192 | Additional term 193 | *************** 194 | 195 | .. math:: 196 | 197 | \dmomdifx 198 | = 199 | - 200 | 2 201 | \mu 202 | \frac{1}{J} 203 | \ave{ 204 | \dif{ 205 | \left( 206 | \frac{J}{\sfact{1}} 207 | \right) 208 | }{\gcs{1}} 209 | \vgt{2}{2} 210 | }{\gcs{1}} 211 | 212 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 213 | :language: c 214 | :tag: additional diffusion 215 | 216 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/x/main.rst: -------------------------------------------------------------------------------- 1 | ############################## 2 | Wall-normal momentum transport 3 | ############################## 4 | 5 | .. math:: 6 | 7 | \pder{\vel{1}}{t} 8 | = 9 | & 10 | \dmomadv{1}{1} 11 | \dmomadv{1}{2} 12 | \dmomadv{1}{3} 13 | 14 | & 15 | \dmomadvx 16 | 17 | & 18 | \dmompre{1} 19 | 20 | & 21 | \dmomdif{1}{1} 22 | \dmomdif{2}{1} 23 | \dmomdif{3}{1} 24 | 25 | & 26 | \dmomdifx 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | 31 | advection 32 | pressure 33 | diffusion 34 | 35 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/x/pressure.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Pressure-gradient 3 | ################# 4 | 5 | .. math:: 6 | 7 | \dmompre{1} 8 | 9 | .. myliteralinclude:: /../../src/fluid/predict/ux.c 10 | :language: c 11 | :tag: pressure gradient effect 12 | 13 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/y/advection.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Advection 3 | ######### 4 | 5 | ********************* 6 | Wall-normal component 7 | ********************* 8 | 9 | .. math:: 10 | 11 | \dmomadv{2}{1} 12 | 13 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 14 | :language: c 15 | :tag: uy is advected in x 16 | 17 | ********************* 18 | Stream-wise component 19 | ********************* 20 | 21 | .. math:: 22 | 23 | \dmomadv{2}{2} 24 | 25 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 26 | :language: c 27 | :tag: uy is advected in y 28 | 29 | ******************* 30 | Span-wise component 31 | ******************* 32 | 33 | .. math:: 34 | 35 | \dmomadv{2}{3} 36 | 37 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 38 | :language: c 39 | :tag: uy is advected in z 40 | 41 | ******************** 42 | Additional component 43 | ******************** 44 | 45 | .. math:: 46 | 47 | \dmomadvy 48 | 49 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 50 | :language: c 51 | :tag: coriolis effect 52 | 53 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/y/diffusion.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Diffusion 3 | ######### 4 | 5 | ********************** 6 | Wall-normal derivative 7 | ********************** 8 | 9 | .. math:: 10 | 11 | \dmomdif{1}{2} 12 | = 13 | \mu 14 | \frac{1}{J} 15 | \dif{}{\gcs{1}} 16 | \left( 17 | \frac{J}{\sfact{1}} 18 | \vgt{1}{2} 19 | \right) 20 | + 21 | \mu 22 | \frac{1}{J} 23 | \dif{}{\gcs{1}} 24 | \left( 25 | \frac{J}{\sfact{1}} 26 | \vgt{2}{1} 27 | \right) 28 | 29 | ============= 30 | Diagonal part 31 | ============= 32 | 33 | .. math:: 34 | 35 | \mu 36 | \frac{1}{J} 37 | \dif{}{\gcs{1}} 38 | \left( 39 | \frac{J}{\sfact{1}} 40 | \vgt{1}{2} 41 | \right) 42 | = 43 | \mu 44 | \frac{1}{J} 45 | \dif{}{\gcs{1}} 46 | \left( 47 | \frac{J}{\sfact{1}} 48 | \dlxy 49 | \right) 50 | 51 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 52 | :language: c 53 | :tag: second-order derivative in x 54 | 55 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 56 | :language: c 57 | :tag: diffusion in x, 0 58 | 59 | ================= 60 | Non-diagonal part 61 | ================= 62 | 63 | .. math:: 64 | 65 | \mu 66 | \frac{1}{J} 67 | \dif{}{\gcs{1}} 68 | \left( 69 | \frac{J}{\sfact{1}} 70 | \vgt{2}{1} 71 | \right) 72 | 73 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 74 | :language: c 75 | :tag: diffusion in x, 1 76 | 77 | ********************** 78 | Stream-wise derivative 79 | ********************** 80 | 81 | .. math:: 82 | 83 | \dmomdif{2}{2} 84 | = 85 | 2 86 | \mu 87 | \frac{1}{J} 88 | \dif{}{\gcs{2}} 89 | \left( 90 | \frac{J}{\sfact{2}} 91 | \vgt{2}{2} 92 | \right) 93 | 94 | ============= 95 | Diagonal part 96 | ============= 97 | 98 | .. math:: 99 | 100 | 2 101 | \mu 102 | \frac{1}{J} 103 | \dif{}{\gcs{2}} 104 | \left( 105 | \frac{J}{\sfact{2}} 106 | \vgt{2}{2}^{\prime} 107 | \right) 108 | = 109 | 2 110 | \mu 111 | \frac{1}{J} 112 | \dif{}{\gcs{2}} 113 | \left( 114 | \frac{J}{\sfact{2}} 115 | \frac{1}{\sfact{2}} 116 | \dif{\vel{2}}{\gcs{2}} 117 | \right) 118 | 119 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 120 | :language: c 121 | :tag: second-order derivative in y 122 | 123 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 124 | :language: c 125 | :tag: diffusion in y, 0 126 | 127 | ================= 128 | Non-diagonal part 129 | ================= 130 | 131 | .. math:: 132 | 133 | 2 134 | \mu 135 | \frac{1}{J} 136 | \dif{}{\gcs{2}} 137 | \left( 138 | \frac{J}{\sfact{2}} 139 | \vgt{2}{2}^{\prime\prime} 140 | \right) 141 | 142 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 143 | :language: c 144 | :tag: diffusion in y, 1 145 | 146 | ******************** 147 | Span-wise derivative 148 | ******************** 149 | 150 | .. math:: 151 | 152 | \dmomdif{3}{2} 153 | = 154 | \mu 155 | \frac{1}{J} 156 | \dif{}{\gcs{3}} 157 | \left( 158 | \frac{J}{\sfact{3}} 159 | \vgt{3}{2} 160 | \right) 161 | + 162 | \mu 163 | \frac{1}{J} 164 | \dif{}{\gcs{3}} 165 | \left( 166 | \frac{J}{\sfact{3}} 167 | \vgt{2}{3} 168 | \right) 169 | 170 | ============= 171 | Diagonal part 172 | ============= 173 | 174 | .. math:: 175 | 176 | \mu 177 | \frac{1}{J} 178 | \dif{}{\gcs{3}} 179 | \left( 180 | \frac{J}{\sfact{3}} 181 | \dlzy 182 | \right) 183 | 184 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 185 | :language: c 186 | :tag: second-order derivative in z 187 | 188 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 189 | :language: c 190 | :tag: diffusion in z, 0 191 | 192 | ================= 193 | Non-diagonal part 194 | ================= 195 | 196 | .. math:: 197 | 198 | \mu 199 | \frac{1}{J} 200 | \dif{}{\gcs{3}} 201 | \left( 202 | \frac{J}{\sfact{3}} 203 | \vgt{2}{3} 204 | \right) 205 | 206 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 207 | :language: c 208 | :tag: diffusion in z, 1 209 | 210 | *************** 211 | Additional term 212 | *************** 213 | 214 | .. math:: 215 | 216 | \dmomdify 217 | = 218 | \mu 219 | \frac{1}{J} 220 | \ave{ 221 | \dif{ 222 | \left( 223 | \frac{J}{\sfact{1}} 224 | \right) 225 | }{\gcs{1}} 226 | \left( 227 | \vgt{2}{1} 228 | + 229 | \vgt{1}{2} 230 | \right) 231 | }{\gcs{1}} 232 | 233 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 234 | :language: c 235 | :tag: additional diffusion 236 | 237 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/y/main.rst: -------------------------------------------------------------------------------- 1 | ############################## 2 | Stream-wise momentum transport 3 | ############################## 4 | 5 | .. math:: 6 | 7 | \pder{\vel{2}}{t} 8 | = 9 | & 10 | \dmomadv{2}{1} 11 | \dmomadv{2}{2} 12 | \dmomadv{2}{3} 13 | 14 | & 15 | \dmomadvy 16 | 17 | & 18 | \dmompre{2} 19 | 20 | & 21 | \dmomdif{1}{2} 22 | \dmomdif{2}{2} 23 | \dmomdif{3}{2} 24 | 25 | & 26 | \dmomdify 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | 31 | advection 32 | pressure 33 | diffusion 34 | 35 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/y/pressure.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Pressure-gradient 3 | ################# 4 | 5 | .. math:: 6 | 7 | \dmompre{2} 8 | 9 | .. myliteralinclude:: /../../src/fluid/predict/uy.c 10 | :language: c 11 | :tag: pressure gradient effect 12 | 13 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/z/advection.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Advection 3 | ######### 4 | 5 | ********************* 6 | Wall-normal component 7 | ********************* 8 | 9 | .. math:: 10 | 11 | \dmomadv{3}{1} 12 | 13 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 14 | :language: c 15 | :tag: uz is advected in x 16 | 17 | ********************* 18 | Stream-wise component 19 | ********************* 20 | 21 | .. math:: 22 | 23 | \dmomadv{3}{2} 24 | 25 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 26 | :language: c 27 | :tag: uz is advected in y 28 | 29 | ******************* 30 | Span-wise component 31 | ******************* 32 | 33 | .. math:: 34 | 35 | \dmomadv{3}{3} 36 | 37 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 38 | :language: c 39 | :tag: uz is advected in z 40 | 41 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/z/diffusion.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Diffusion 3 | ######### 4 | 5 | ********************** 6 | Wall-normal derivative 7 | ********************** 8 | 9 | .. math:: 10 | 11 | \dmomdif{1}{3} 12 | = 13 | \mu 14 | \frac{1}{J} 15 | \dif{}{\gcs{1}} 16 | \left( 17 | \frac{J}{\sfact{1}} 18 | \vgt{1}{3} 19 | \right) 20 | + 21 | \mu 22 | \frac{1}{J} 23 | \dif{}{\gcs{1}} 24 | \left( 25 | \frac{J}{\sfact{1}} 26 | \vgt{3}{1} 27 | \right) 28 | 29 | ============= 30 | Diagonal part 31 | ============= 32 | 33 | .. math:: 34 | 35 | \mu 36 | \frac{1}{J} 37 | \dif{}{\gcs{1}} 38 | \left( 39 | \frac{J}{\sfact{1}} 40 | \vgt{1}{3} 41 | \right) 42 | = 43 | \mu 44 | \frac{1}{J} 45 | \dif{}{\gcs{1}} 46 | \left( 47 | \frac{J}{\sfact{1}} 48 | \dlxz 49 | \right) 50 | 51 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 52 | :language: c 53 | :tag: second-order derivative in x 54 | 55 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 56 | :language: c 57 | :tag: diffusion in x, 0 58 | 59 | ================= 60 | Non-diagonal part 61 | ================= 62 | 63 | .. math:: 64 | 65 | \mu 66 | \frac{1}{J} 67 | \dif{}{\gcs{1}} 68 | \left( 69 | \frac{J}{\sfact{1}} 70 | \vgt{3}{1} 71 | \right) 72 | 73 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 74 | :language: c 75 | :tag: diffusion in x, 1 76 | 77 | ********************** 78 | Stream-wise derivative 79 | ********************** 80 | 81 | .. math:: 82 | 83 | \dmomdif{2}{3} 84 | = 85 | \mu 86 | \frac{1}{J} 87 | \dif{}{\gcs{2}} 88 | \left( 89 | \frac{J}{\sfact{2}} 90 | \vgt{2}{3} 91 | \right) 92 | + 93 | \mu 94 | \frac{1}{J} 95 | \dif{}{\gcs{2}} 96 | \left( 97 | \frac{J}{\sfact{2}} 98 | \vgt{3}{2} 99 | \right) 100 | 101 | ============= 102 | Diagonal part 103 | ============= 104 | 105 | .. math:: 106 | 107 | \mu 108 | \frac{1}{J} 109 | \dif{}{\gcs{2}} 110 | \left( 111 | \frac{J}{\sfact{2}} 112 | \vgt{2}{3} 113 | \right) 114 | = 115 | \mu 116 | \frac{1}{J} 117 | \dif{}{\gcs{2}} 118 | \left( 119 | \frac{J}{\sfact{2}} 120 | \dlyz 121 | \right) 122 | 123 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 124 | :language: c 125 | :tag: second-order derivative in y 126 | 127 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 128 | :language: c 129 | :tag: diffusion in y, 0 130 | 131 | ================= 132 | Non-diagonal part 133 | ================= 134 | 135 | .. math:: 136 | 137 | \mu 138 | \frac{1}{J} 139 | \dif{}{\gcs{2}} 140 | \left( 141 | \frac{J}{\sfact{2}} 142 | \vgt{3}{2} 143 | \right) 144 | 145 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 146 | :language: c 147 | :tag: diffusion in y, 1 148 | 149 | ******************** 150 | Span-wise derivative 151 | ******************** 152 | 153 | .. math:: 154 | 155 | \dmomdif{3}{3} 156 | = 157 | 2 158 | \mu 159 | \frac{1}{J} 160 | \dif{}{\gcs{3}} 161 | \left( 162 | \frac{J}{\sfact{3}} 163 | \vgt{3}{3} 164 | \right) 165 | = 166 | 2 167 | \mu 168 | \frac{1}{J} 169 | \dif{}{\gcs{3}} 170 | \left( 171 | \frac{J}{\sfact{3}} 172 | \dlzz 173 | \right) 174 | 175 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 176 | :language: c 177 | :tag: second-order derivative in z 178 | 179 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 180 | :language: c 181 | :tag: diffusion in z 182 | 183 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/z/main.rst: -------------------------------------------------------------------------------- 1 | ############################ 2 | Span-wise momentum transport 3 | ############################ 4 | 5 | .. math:: 6 | 7 | \pder{\vel{3}}{t} 8 | = 9 | & 10 | \dmomadv{3}{1} 11 | \dmomadv{3}{2} 12 | \dmomadv{3}{3} 13 | 14 | & 15 | \dmompre{3} 16 | 17 | & 18 | \dmomdif{1}{3} 19 | \dmomdif{2}{3} 20 | \dmomdif{3}{3} 21 | 22 | .. toctree:: 23 | :maxdepth: 1 24 | 25 | advection 26 | pressure 27 | diffusion 28 | 29 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/momentum/z/pressure.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Pressure-gradient 3 | ################# 4 | 5 | .. math:: 6 | 7 | \dmompre{3} 8 | 9 | .. myliteralinclude:: /../../src/fluid/predict/uz.c 10 | :language: c 11 | :tag: pressure gradient effect 12 | 13 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/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 | scalar 17 | 18 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/prerequisite/scalar.rst: -------------------------------------------------------------------------------- 1 | ########################## 2 | Relations involving scalar 3 | ########################## 4 | 5 | **************** 6 | Differentiations 7 | **************** 8 | 9 | .. math:: 10 | 11 | \sumzc 12 | \sumyc 13 | \sumxc 14 | \scalar 15 | \dif{q}{\gcs{1}} 16 | = 17 | - 18 | \sumzc 19 | \sumyc 20 | \left( 21 | \vat{\left(\scalar q\right)}{\frac{1}{2}} 22 | + 23 | \sumxf 24 | \dif{\scalar}{\gcs{1}} 25 | q 26 | - 27 | \vat{\left(\scalar q\right)}{\ngp{1} + \frac{1}{2}} 28 | \right). 29 | 30 | .. math:: 31 | 32 | \sumzc 33 | \sumyc 34 | \sumxc 35 | \scalar 36 | \dif{q}{\gcs{2}} 37 | = 38 | - 39 | \sumzc 40 | \sumyf 41 | \sumxc 42 | \dif{\scalar}{\gcs{2}} 43 | q. 44 | 45 | .. math:: 46 | 47 | \sumzc 48 | \sumyc 49 | \sumxc 50 | \scalar 51 | \dif{q}{\gcs{3}} 52 | = 53 | - 54 | \sumzf 55 | \sumyc 56 | \sumxc 57 | \dif{\scalar}{\gcs{3}} 58 | q. 59 | 60 | ******** 61 | Averages 62 | ******** 63 | 64 | .. math:: 65 | 66 | \sumzc 67 | \sumyc 68 | \sumxc 69 | \scalar 70 | \ave{q}{\gcs{1}} 71 | = 72 | \sumzc 73 | \sumyc 74 | \left( 75 | \vat{\scalar}{1} 76 | \frac{\vat{q}{\frac{1}{2}}}{2} 77 | + 78 | \sum_{i = \frac{3}{2}}^{\ngp{1} - \frac{1}{2}} 79 | \ave{\scalar}{\gcs{1}} 80 | q 81 | + 82 | \vat{\scalar}{\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 | \scalar 92 | \ave{q}{\gcs{2}} 93 | = 94 | \sumzc 95 | \sumyf 96 | \sumxc 97 | \ave{\scalar}{\gcs{2}} 98 | q. 99 | 100 | .. math:: 101 | 102 | \sumzc 103 | \sumyc 104 | \sumxc 105 | \scalar 106 | \ave{q}{\gcs{3}} 107 | = 108 | \sumzf 109 | \sumyc 110 | \sumxc 111 | \ave{\scalar}{\gcs{3}} 112 | q. 113 | 114 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/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/discretisation/spatial/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/discretisation/spatial/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/discretisation/spatial/quad/main.rst: -------------------------------------------------------------------------------- 1 | ################## 2 | Quadratic quantity 3 | ################## 4 | 5 | To see the global and discrete balance of the quadratic quantity, :ref:`the momentum balance ` for each direction is integrated in the whole volume after multiplied by the corresponding local velocity. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | 10 | advection.rst 11 | pressure.rst 12 | diffusion.rst 13 | 14 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/quad/pressure.rst: -------------------------------------------------------------------------------- 1 | ################# 2 | Pressure-gradient 3 | ################# 4 | 5 | The pressure-gradient terms 6 | 7 | .. math:: 8 | 9 | - 10 | \frac{1}{\sfact{i}} 11 | \dif{p}{\gcs{i}}, 12 | 13 | which 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 | \frac{1}{J} 65 | \dif{ 66 | \left( 67 | \frac{J}{\sfact{1}} 68 | \vel{1} 69 | \right) 70 | }{\gcs{1}} 71 | + 72 | \frac{1}{J} 73 | \dif{ 74 | \left( 75 | \frac{J}{\sfact{2}} 76 | \vel{2} 77 | \right) 78 | }{\gcs{2}} 79 | + 80 | \frac{1}{J} 81 | \dif{ 82 | \left( 83 | \frac{J}{\sfact{3}} 84 | \vel{3} 85 | \right) 86 | }{\gcs{3}} 87 | \right\}, 88 | 89 | which is zero because the component inside the wavy parentheses is :ref:`the incompressibility constraint `. 90 | 91 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/scalar.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _discrete_scalar: 3 | 4 | ################ 5 | Scalar transport 6 | ################ 7 | 8 | The scalar is defined at each cell center and follows 9 | 10 | .. math:: 11 | 12 | \pder{\scalar}{t} 13 | = 14 | & 15 | \dscalaradv{1} 16 | \dscalaradv{2} 17 | \dscalaradv{3} 18 | 19 | & 20 | \dscalardif{1} 21 | \dscalardif{2} 22 | \dscalardif{3}. 23 | 24 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/symbol/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/discretisation/spatial/symbol/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/discretisation/spatial/symbol/main.rst: -------------------------------------------------------------------------------- 1 | ###### 2 | Symbol 3 | ###### 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | 8 | scale_factor 9 | average 10 | differentiation 11 | summation 12 | 13 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/symbol/scale_factor.rst: -------------------------------------------------------------------------------- 1 | ##################################### 2 | Scale factor and Jacobian determinant 3 | ##################################### 4 | 5 | Discrete scale factors are given by 6 | 7 | .. math:: 8 | 9 | \sfact{1} 10 | & 11 | \equiv 12 | \Delta \vx, 13 | 14 | \sfact{2} 15 | & 16 | \equiv 17 | \Delta \vy, 18 | 19 | \sfact{3} 20 | & 21 | \equiv 22 | \Delta \vz, 23 | 24 | for Cartesian coordinates (``is_curved == false``), while 25 | 26 | .. math:: 27 | 28 | \sfact{1} 29 | & 30 | \equiv 31 | \Delta \vr, 32 | 33 | \sfact{2} 34 | & 35 | \equiv 36 | \vr 37 | \Delta \vt, 38 | 39 | \sfact{3} 40 | & 41 | \equiv 42 | \Delta \vz, 43 | 44 | for cylindrical coordinates (``is_curved == true``), respectively. 45 | 46 | They are stored at the wall-normal cell faces and centers (except :math:`\sfact{3}`, which is constant across the whole domain): 47 | 48 | .. myliteralinclude:: /../../src/domain.c 49 | :language: c 50 | :tag: x scale factors at x cell faces 51 | 52 | .. myliteralinclude:: /../../src/domain.c 53 | :language: c 54 | :tag: x scale factors at x cell centers 55 | 56 | .. myliteralinclude:: /../../src/domain.c 57 | :language: c 58 | :tag: y scale factors at x cell faces 59 | 60 | .. myliteralinclude:: /../../src/domain.c 61 | :language: c 62 | :tag: y scale factors at x cell centers 63 | 64 | Discrete Jacobian determinants, which are also defined at cell faces and centers, are simply the product of the local scale factors: 65 | 66 | .. math:: 67 | 68 | J 69 | \equiv 70 | \Pi_i 71 | \sfact{i}. 72 | 73 | .. myliteralinclude:: /../../src/domain.c 74 | :language: c 75 | :tag: jacobian determinants at x cell faces 76 | 77 | .. myliteralinclude:: /../../src/domain.c 78 | :language: c 79 | :tag: jacobian determinants at x cell centers 80 | 81 | -------------------------------------------------------------------------------- /docs/source/discretisation/spatial/symbol/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/discretisation/spatial/velocity_gradient_tensor.rst: -------------------------------------------------------------------------------- 1 | ######################## 2 | Velocity-gradient tensor 3 | ######################## 4 | 5 | For later convenience, 9 tensor components are pre-computed and stored to arrays. 6 | 7 | ** 8 | 11 9 | ** 10 | 11 | .. math:: 12 | 13 | \vat{ 14 | \vgt{1}{1} 15 | }{ 16 | \ccindex{i}, 17 | \ccindex{j}, 18 | \ccindex{k} 19 | } 20 | = 21 | \dlxx 22 | 23 | .. myliteralinclude:: /../../src/fluid/predict/lxx.c 24 | :language: c 25 | :tag: compute lxx 26 | 27 | ** 28 | 21 29 | ** 30 | 31 | .. math:: 32 | 33 | \vat{ 34 | \vgt{2}{1} 35 | }{ 36 | \cpindex{i}, 37 | \cpindex{j}, 38 | \ccindex{k} 39 | } 40 | = 41 | \vat{ 42 | \vgt{2}{1}^{\prime} 43 | }{ 44 | \cpindex{i}, 45 | \cpindex{j}, 46 | \ccindex{k} 47 | } 48 | + 49 | \vat{ 50 | \vgt{2}{1}^{\prime\prime} 51 | }{ 52 | \cpindex{i}, 53 | \cpindex{j}, 54 | \ccindex{k} 55 | } 56 | = 57 | \dlyx 58 | 59 | Two terms are computed and stored separately. 60 | 61 | .. math:: 62 | 63 | \vat{ 64 | \vgt{2}{1}^{\prime} 65 | }{ 66 | \cpindex{i}, 67 | \cpindex{j}, 68 | \ccindex{k} 69 | } 70 | = 71 | \dlyxa 72 | 73 | .. myliteralinclude:: /../../src/fluid/predict/lyx.c 74 | :language: c 75 | :tag: compute dominant term of lyx 76 | 77 | .. math:: 78 | 79 | \vat{ 80 | \vgt{2}{1}^{\prime\prime} 81 | }{ 82 | \cpindex{i}, 83 | \cpindex{j}, 84 | \ccindex{k} 85 | } 86 | = 87 | \dlyxb 88 | 89 | .. myliteralinclude:: /../../src/fluid/predict/lyx.c 90 | :language: c 91 | :tag: compute non-dominant term of lyx 92 | 93 | ** 94 | 31 95 | ** 96 | 97 | .. math:: 98 | 99 | \vat{ 100 | \vgt{3}{1} 101 | }{ 102 | \cpindex{i}, 103 | \ccindex{j}, 104 | \cpindex{k} 105 | } 106 | = 107 | \dlzx 108 | 109 | .. myliteralinclude:: /../../src/fluid/predict/lzx.c 110 | :language: c 111 | :tag: compute lzx 112 | 113 | ** 114 | 12 115 | ** 116 | 117 | .. math:: 118 | 119 | \vat{ 120 | \vgt{1}{2} 121 | }{ 122 | \cpindex{i}, 123 | \cpindex{j}, 124 | \ccindex{k} 125 | } 126 | = 127 | \dlxy 128 | 129 | .. myliteralinclude:: /../../src/fluid/predict/lxy.c 130 | :language: c 131 | :tag: compute lxy 132 | 133 | ** 134 | 22 135 | ** 136 | 137 | .. math:: 138 | 139 | \vat{ 140 | \vgt{2}{2} 141 | }{ 142 | \ccindex{i}, 143 | \ccindex{j}, 144 | \ccindex{k} 145 | } 146 | = 147 | \vat{ 148 | \vgt{2}{2}^{\prime} 149 | }{ 150 | \ccindex{i}, 151 | \ccindex{j}, 152 | \ccindex{k} 153 | } 154 | + 155 | \vat{ 156 | \vgt{2}{2}^{\prime\prime} 157 | }{ 158 | \ccindex{i}, 159 | \ccindex{j}, 160 | \ccindex{k} 161 | } 162 | = 163 | \dlyy 164 | 165 | Two terms are computed and stored separately. 166 | 167 | .. math:: 168 | 169 | \vat{ 170 | \vgt{2}{2}^{\prime} 171 | }{ 172 | \ccindex{i}, 173 | \ccindex{j}, 174 | \ccindex{k} 175 | } 176 | = 177 | \dlyya 178 | 179 | .. myliteralinclude:: /../../src/fluid/predict/lyy.c 180 | :language: c 181 | :tag: compute dominant term of lyy 182 | 183 | .. math:: 184 | 185 | \vat{ 186 | \vgt{2}{2}^{\prime\prime} 187 | }{ 188 | \ccindex{i}, 189 | \ccindex{j}, 190 | \ccindex{k} 191 | } 192 | = 193 | \dlyyb 194 | 195 | .. myliteralinclude:: /../../src/fluid/predict/lyy.c 196 | :language: c 197 | :tag: compute non-dominant term of lyy 198 | 199 | ** 200 | 32 201 | ** 202 | 203 | .. math:: 204 | 205 | \vat{ 206 | \vgt{3}{2} 207 | }{ 208 | \ccindex{i}, 209 | \cpindex{j}, 210 | \cpindex{k} 211 | } 212 | = 213 | \dlzy 214 | 215 | .. myliteralinclude:: /../../src/fluid/predict/lzy.c 216 | :language: c 217 | :tag: compute lzy 218 | 219 | ** 220 | 13 221 | ** 222 | 223 | .. math:: 224 | 225 | \vat{ 226 | \vgt{1}{3} 227 | }{ 228 | \cpindex{i}, 229 | \ccindex{j}, 230 | \cpindex{k} 231 | } 232 | = 233 | \dlxz 234 | 235 | .. myliteralinclude:: /../../src/fluid/predict/lxz.c 236 | :language: c 237 | :tag: compute lxz 238 | 239 | ** 240 | 23 241 | ** 242 | 243 | .. math:: 244 | 245 | \vat{ 246 | \vgt{2}{3} 247 | }{ 248 | \ccindex{i}, 249 | \cpindex{j}, 250 | \cpindex{k} 251 | } 252 | = 253 | \dlyz 254 | 255 | .. myliteralinclude:: /../../src/fluid/predict/lyz.c 256 | :language: c 257 | :tag: compute lyz 258 | 259 | ** 260 | 33 261 | ** 262 | 263 | .. math:: 264 | 265 | \vat{ 266 | \vgt{3}{3} 267 | }{ 268 | \ccindex{i}, 269 | \ccindex{j}, 270 | \ccindex{k} 271 | } 272 | = 273 | \dlzz 274 | 275 | .. myliteralinclude:: /../../src/fluid/predict/lzz.c 276 | :language: c 277 | :tag: compute lzz 278 | 279 | -------------------------------------------------------------------------------- /docs/source/discretisation/temporal/correction.rst: -------------------------------------------------------------------------------- 1 | ############### 2 | Correction step 3 | ############### 4 | 5 | Updated but still non-solenoidal velocity field :math:`u_i^*` is corrected to be divergence-free by solving a Poisson equation with respect to the scalar potential :math:`\phi`: 6 | 7 | .. math:: 8 | 9 | \frac{1}{J} 10 | \dif{}{\gcs{1}} 11 | \left( 12 | \frac{J}{\sfact{1}} 13 | \frac{1}{\sfact{1}} 14 | \dif{\phi}{\gcs{1}} 15 | \right) 16 | + 17 | \frac{1}{J} 18 | \dif{}{\gcs{2}} 19 | \left( 20 | \frac{J}{\sfact{2}} 21 | \frac{1}{\sfact{2}} 22 | \dif{\phi}{\gcs{2}} 23 | \right) 24 | + 25 | \frac{1}{J} 26 | \dif{}{\gcs{3}} 27 | \left( 28 | \frac{J}{\sfact{3}} 29 | \frac{1}{\sfact{3}} 30 | \dif{\phi}{\gcs{3}} 31 | \right) 32 | = 33 | \frac{1}{\Delta t} 34 | \dif{\vel{i}^*}{\gcs{i}}. 35 | 36 | The eigenvalues are computed as follows: 37 | 38 | .. myliteralinclude:: /../../src/fluid/compute_potential.c 39 | :language: c 40 | :tag: azimuthal eigenvalues 41 | 42 | .. myliteralinclude:: /../../src/fluid/compute_potential.c 43 | :language: c 44 | :tag: axial eigenvalues 45 | 46 | In the radial direction, tri-diagonal matrices are to be solved for each :math:`y` and :math:`z`: 47 | 48 | .. myliteralinclude:: /../../src/fluid/compute_potential.c 49 | :language: c 50 | :tag: solve tri-diagonal matrix 51 | 52 | After computing the scalar potential :math:`\phi`, the velocity field is corrected using its gradient: 53 | 54 | .. math:: 55 | 56 | \pder{\phi}{x_i} 57 | \approx 58 | \vec{e_{\gcs{1}}} 59 | \frac{1}{\sfact{1}} 60 | \dif{\phi}{\gcs{1}} 61 | + 62 | \vec{e_{\gcs{2}}} 63 | \frac{1}{\sfact{2}} 64 | \dif{\phi}{\gcs{2}} 65 | + 66 | \vec{e_{\gcs{3}}} 67 | \frac{1}{\sfact{3}} 68 | \dif{\phi}{\gcs{3}}. 69 | 70 | .. myliteralinclude:: /../../src/fluid/correct/ux.c 71 | :language: c 72 | :tag: correct x velocity 73 | 74 | .. myliteralinclude:: /../../src/fluid/correct/uy.c 75 | :language: c 76 | :tag: correct y velocity 77 | 78 | .. myliteralinclude:: /../../src/fluid/correct/uz.c 79 | :language: c 80 | :tag: correct z velocity 81 | 82 | -------------------------------------------------------------------------------- /docs/source/discretisation/temporal/main.rst: -------------------------------------------------------------------------------- 1 | ####################### 2 | Temporal discretisation 3 | ####################### 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | 8 | correction 9 | 10 | -------------------------------------------------------------------------------- /docs/source/equation/figures/plot.gp: -------------------------------------------------------------------------------- 1 | # physical coordinate (Cartesian) 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 | # physical coordinate (cylindrical) 51 | { 52 | reset 53 | xmin = + 0.0 54 | xmax = + 4.5 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 'cyl.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 | rmin = 1. 77 | rmax = rmin + 3. 78 | tmin = 0. 79 | tmax = pi / 3. 80 | deltar = (rmax - rmin) / num 81 | deltat = (tmax - tmin) / num 82 | do for [i = 0 : num : 1] { 83 | if (0 == i) { 84 | r = rmin 85 | } else if (num == i) { 86 | r = rmax 87 | } else { 88 | r = i - num / 2 89 | r = rmin + (rmax - rmin) * 1. / (1. + exp(- 1. * r)) 90 | } 91 | set object circle at first 0., first 0. size r arc [180. / pi * tmin : 180. / pi * tmax] fc rgb '#000000' lw 10 nowedge 92 | } 93 | do for [i = 0 : num : 1] { 94 | t = tmin + i * deltat 95 | set arrow from first rmin * cos(t), first rmin * sin(t) to first rmax * cos(t), first rmax * sin(t) nohead ls 1 96 | } 97 | plot \ 98 | NaN notitle 99 | } 100 | 101 | # computational coordinate 102 | { 103 | reset 104 | xmin = - 0.5 105 | xmax = + 4.0 106 | ymin = - 0.5 107 | ymax = + 4.0 108 | lx = xmax-xmin 109 | ly = ymax-ymin 110 | set terminal epslatex standalone color size lx,ly font ',12' 111 | set output 'comp.tex' 112 | unset border 113 | set lmargin 0 114 | set rmargin 0 115 | set bmargin 0 116 | set tmargin 0 117 | unset xlabel 118 | unset ylabel 119 | set xrange [xmin:xmax] 120 | set yrange [ymin:ymax] 121 | unset xtics 122 | unset ytics 123 | set size ratio -1 124 | set samples 10000 125 | set style line 1 lc rgb '#000000' lw 10 126 | num = 8 127 | xmin = 0. 128 | xmax = 3.5 129 | ymin = 0. 130 | ymax = 3.5 131 | deltax = (xmax - xmin) / num 132 | deltay = (ymax - ymin) / num 133 | do for [i = 0 : num : 1] { 134 | x = xmin + i * deltax 135 | set arrow from first x, first ymin to first x, first ymax nohead ls 1 136 | y = ymin + i * deltay 137 | set arrow from first xmin, first y to first xmax, first y nohead ls 1 138 | } 139 | plot \ 140 | NaN notitle 141 | } 142 | 143 | # merge above elements 144 | { 145 | reset 146 | xmin = 0.0 147 | xmax = 13.5 148 | ymin = 0.0 149 | ymax = 5.25 150 | lx = xmax - xmin 151 | ly = ymax - ymin 152 | set terminal epslatex standalone color size lx,ly font ',20' 153 | set output 'result.tex' 154 | unset border 155 | set lmargin 0 156 | set rmargin 0 157 | set bmargin 0 158 | set tmargin 0 159 | unset xlabel 160 | unset ylabel 161 | set xrange [xmin:xmax] 162 | set yrange [ymin:ymax] 163 | unset xtics 164 | unset ytics 165 | set size ratio -1 166 | ref = 4.5 167 | set label 'Cartesian coordinate' center at first 0.5 * ref, first 1. * ref + 0.35 textcolor rgb '#000000' 168 | set label 'Cylindrical coordinate' center at first 1.5 * ref, first 1. * ref + 0.35 textcolor rgb '#000000' 169 | set label 'Computational coordinate' center at first 2.5 * ref, first 1. * ref + 0.35 textcolor rgb '#000000' 170 | set label '$\left( x, y \right)$' center at first 0.5 * ref, first 1. * ref - 0.05 textcolor rgb '#000000' 171 | set label '$\left( r, \theta \right)$' center at first 1.5 * ref, first 1. * ref - 0.05 textcolor rgb '#000000' 172 | set label '$\left( \xi^1, \xi^2 \right)$' center at first 2.5 * ref, first 1. * ref - 0.05 textcolor rgb '#000000' 173 | set label '\includegraphics[width=4.500in, height=4.500in]{car.pdf}' center at first 0.5 * ref, first 0.5 * ref 174 | set label '\includegraphics[width=4.500in, height=4.500in]{cyl.pdf}' center at first 1.5 * ref, first 0.5 * ref 175 | set label '\includegraphics[width=4.500in, height=4.500in]{comp.pdf}' center at first 2.5 * ref, first 0.5 * ref 176 | plot \ 177 | NaN notitle 178 | } 179 | 180 | -------------------------------------------------------------------------------- /docs/source/equation/figures/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/e0c6362d728a99fada40ed225220b9408a2825c3/docs/source/equation/figures/result.png -------------------------------------------------------------------------------- /docs/source/example/energy/data/energy.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 | ys = list() 14 | zs = list() 15 | for fname in fnames: 16 | data = np.loadtxt(fname) 17 | t = data[:, 0] 18 | ex = data[:, 1] 19 | ey = data[:, 2] 20 | ez = data[:, 3] 21 | sc = data[:, 4] 22 | et = ex + ey + ez 23 | e0 = et[0] 24 | s0 = sc[0] 25 | et /= e0 26 | sc /= s0 27 | ls.append(fname.strip().split("energy-")[1].split(".dat")[0]) 28 | xs.append(t[1:]) 29 | ys.append(1. - et[1:]) 30 | zs.append(1. - sc[1:]) 31 | return ls, xs, ys, zs 32 | 33 | if __name__ == "__main__": 34 | argv = sys.argv 35 | assert(4 == len(argv)) 36 | idname = argv[1] 37 | ofname1 = argv[2] 38 | ofname2 = argv[3] 39 | ls, xs, ys, zs = load(idname) 40 | # 41 | fig = pyplot.figure() 42 | ax = fig.add_subplot(111) 43 | colors = pyplot.rcParams["axes.prop_cycle"].by_key()["color"] 44 | for l, x, y, z, color in zip(ls, xs, ys, zs, colors): 45 | ax.plot(x, y, linestyle="solid", color=color, label=l) 46 | ax.plot(x, z, linestyle="dashed", color=color) 47 | kwrds = { 48 | "title": "", 49 | "xlabel": "time", 50 | "ylabel": "$-\Delta E / E_0$", 51 | "yscale": "log", 52 | } 53 | ax.legend() 54 | ax.set(**kwrds) 55 | pyplot.savefig(ofname1) 56 | pyplot.close() 57 | # 58 | fig = pyplot.figure() 59 | ax = fig.add_subplot(111) 60 | xs = list() 61 | y1s = list() 62 | z1s = list() 63 | for l, y, z in zip(ls, ys, zs): 64 | xs.append(float(l)) 65 | y1s.append(y[-1]) 66 | z1s.append(z[-1]) 67 | xs = np.array(xs) 68 | ax.plot(xs, y1s, marker="o", label="velocity", color="#FF0000") 69 | ax.plot(xs, z1s, marker="o", label="scalar", color="#0000FF") 70 | ax.plot(xs, 2. * y1s[0] / xs[0]**3. * xs**3., label="3rd order", color="#000000", linestyle="dashed") 71 | kwrds = { 72 | "title": "", 73 | "xlabel": "$\Delta t$", 74 | "ylabel": "$-\Delta E / E_0$", 75 | "xscale": "log", 76 | "yscale": "log", 77 | } 78 | ax.legend() 79 | ax.set(**kwrds) 80 | pyplot.savefig(ofname2) 81 | pyplot.close() 82 | 83 | -------------------------------------------------------------------------------- /docs/source/example/energy/data/exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | # set initial condition, model 1/4 cylinder 7 | cd initial_condition 8 | make output && make datadel 9 | is_curved=true \ 10 | lx=1.0e+0 \ 11 | ly=0.7853981633974483 \ 12 | lz=2.0e+0 \ 13 | glisize=32 \ 14 | gljsize=16 \ 15 | glksize=32 \ 16 | python main.py output 17 | cd .. 18 | 19 | # build and run 20 | make output && make datadel && make all 21 | timemax=10. \ 22 | wtimemax=6.0e+2 \ 23 | log_rate=1.0e+0 \ 24 | save_rate=2.0e+2 \ 25 | save_after=0.0e+0 \ 26 | stat_rate=1.0e-1 \ 27 | stat_after=1.0e+2 \ 28 | coef_dt_adv=1. \ 29 | coef_dt_dif=1. \ 30 | Re=1.e16 \ 31 | Pr=1.e0 \ 32 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 33 | 34 | # stash last flow field 35 | mv $(find output/save -type d | sort | tail -n 1) dirname_ic 36 | 37 | # try different dt 38 | for factor in 0.1 0.2 0.4 0.8 39 | do 40 | make datadel 41 | timemax=15. \ 42 | wtimemax=6.0e+2 \ 43 | log_rate=1.0e-1 \ 44 | save_rate=5.0e+1 \ 45 | save_after=0.0e+0 \ 46 | stat_rate=1.0e-1 \ 47 | stat_after=1.0e+3 \ 48 | coef_dt_adv=${factor} \ 49 | coef_dt_dif=0.95 \ 50 | Re=1.e16 \ 51 | Pr=1.e0 \ 52 | mpirun -n 2 --oversubscribe ./a.out dirname_ic 53 | mv output/log/total_energy.dat ./energy-${factor}.dat 54 | done 55 | 56 | # post process 57 | mkdir artifacts 58 | python3 \ 59 | docs/source/example/energy/data/energy.py \ 60 | . \ 61 | artifacts/energy1.png \ 62 | artifacts/energy2.png 63 | 64 | -------------------------------------------------------------------------------- /docs/source/example/energy/main.rst: -------------------------------------------------------------------------------- 1 | ###### 2 | Energy 3 | ###### 4 | 5 | .. include:: /reference/reference.txt 6 | 7 | Since the current project adopts the energy-conserving scheme, the total discrete kinetic energy should be conserved. 8 | However, since the explicit Runge-Kutta scheme is used, the discrete kinetic energy is dissipated, which is confirmed here. 9 | 10 | .. mydetails:: Configuration 11 | 12 | .. literalinclude:: data/exec.sh 13 | :language: bash 14 | 15 | Total discrete kinetic energy as a function of time: 16 | 17 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/energy/energy1.png 18 | :width: 600 19 | 20 | Discrete kinetic energy decay as a function of time step size: 21 | 22 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/energy/energy2.png 23 | :width: 600 24 | 25 | The third-order convergence is expected (e.g. |MORINISHI1998|). 26 | 27 | -------------------------------------------------------------------------------- /docs/source/example/main.rst: -------------------------------------------------------------------------------- 1 | ####### 2 | Example 3 | ####### 4 | 5 | Several example simulations are performed and the results are discussed here. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | 10 | typical/main 11 | energy/main 12 | 13 | -------------------------------------------------------------------------------- /docs/source/example/typical/data/balance_dif.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): 8 | data = np.loadtxt(fname) 9 | x = data[:, 0] 10 | y = data[:, 1] 11 | z = data[:, 2] 12 | return x, y, z 13 | 14 | def normalise(config, values): 15 | return values / factor 16 | 17 | if __name__ == "__main__": 18 | argv = sys.argv 19 | assert 4 == len(argv) 20 | ifnames = [argv[1], argv[2]] 21 | ofname = argv[3] 22 | x0, y0, z0 = load(ifnames[0]) 23 | x1, y1, z1 = load(ifnames[1]) 24 | y = np.abs(y1 - y0) 25 | z = np.abs(z1 - z0) 26 | fig = pyplot.figure() 27 | ax = fig.add_subplot(111) 28 | ax.plot(x0, y, color="#FF0000", label="velocity") 29 | ax.plot(x0, z, color="#0000FF", label="scalar") 30 | kwrds = { 31 | "title": "", 32 | "xlabel": "Time", 33 | "ylabel": "Injection - Dissipation", 34 | "yscale": "log", 35 | } 36 | ax.set(**kwrds) 37 | ax.legend() 38 | pyplot.savefig(ofname) 39 | pyplot.close() 40 | 41 | -------------------------------------------------------------------------------- /docs/source/example/typical/data/balance_main.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): 8 | data = np.loadtxt(fname) 9 | x = data[:, 0] 10 | y = data[:, 1] 11 | return x, y 12 | 13 | def normalise(config, values): 14 | ri = 1. 15 | ui = 1. 16 | re = np.load(f"{config}/Re.npy") 17 | lengths = np.load(f"{config}/lengths.npy") 18 | ro = ri + lengths[0] 19 | factor = 2. / re * ri**2. * ro**2. / (ro**2. - ri**2.) * (ui / ri)**2. * lengths[1] * lengths[2] 20 | return values / factor 21 | 22 | if __name__ == "__main__": 23 | argv = sys.argv 24 | assert 5 == len(argv) 25 | config = argv[1] 26 | ifnames = [argv[2], argv[3]] 27 | ofname = argv[4] 28 | x0, y0 = load(ifnames[0]) 29 | x1, y1 = load(ifnames[1]) 30 | y0 = normalise(config, y0) 31 | y1 = normalise(config, y1) 32 | fig = pyplot.figure() 33 | ax = fig.add_subplot(111) 34 | ax.plot(x0, y0, color="#FF0000", label="dissipation") 35 | ax.plot(x1, y1, color="#0000FF", label="injection") 36 | ax.plot(x0, np.full(x0.shape, 1.1375), color="#000000", linestyle="--", label="Ostilla et al., JFM, 2013") 37 | kwrds = { 38 | "xlabel": "Time", 39 | "ylabel": "Nu", 40 | "xlim": [0., 200.], 41 | } 42 | ax.set(**kwrds) 43 | ax.legend() 44 | pyplot.savefig(ofname) 45 | pyplot.close() 46 | 47 | -------------------------------------------------------------------------------- /docs/source/example/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): 8 | data = np.loadtxt(fname) 9 | x = data[:, 0] 10 | y = data[:, 1] 11 | return x, y 12 | 13 | if __name__ == "__main__": 14 | argv = sys.argv 15 | assert 3 == len(argv) 16 | ifname = argv[1] 17 | ofname = argv[2] 18 | x, y = load(ifname) 19 | fig = pyplot.figure() 20 | ax = fig.add_subplot(111) 21 | ax.plot(x, y, color="#FF0000") 22 | kwrds = { 23 | "xlabel": "Time", 24 | "ylabel": "Maximum divergence", 25 | "ylim": [1.e-16, 1.e-13], 26 | "yticks": [1.e-16, 1.e-15, 1.e-14, 1.e-13], 27 | "yscale": "log", 28 | } 29 | ax.set(**kwrds) 30 | pyplot.savefig(ofname) 31 | pyplot.close() 32 | 33 | -------------------------------------------------------------------------------- /docs/source/example/typical/data/exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | # set initial condition, model half cylinder 7 | cd initial_condition 8 | make output && make datadel 9 | is_curved=true \ 10 | lx=1.0e+0 \ 11 | ly=0.39269908169872414 \ 12 | lz=2.0e+0 \ 13 | glisize=64 \ 14 | gljsize=8 \ 15 | glksize=32 \ 16 | python3 main.py output 17 | cd .. 18 | 19 | # build and run 20 | make output && make datadel && make all 21 | timemax=4.0e+2 \ 22 | wtimemax=6.0e+2 \ 23 | log_rate=1.0e+0 \ 24 | save_rate=1.0e+2 \ 25 | save_after=0.0e+0 \ 26 | stat_rate=1.0e-1 \ 27 | stat_after=1.0e+2 \ 28 | coef_dt_adv=1. \ 29 | coef_dt_dif=1. \ 30 | Re=80. \ 31 | Pr=1. \ 32 | mpirun -n 2 --oversubscribe ./a.out initial_condition/output 33 | 34 | # post process 35 | mkdir artifacts 36 | python3 \ 37 | docs/source/example/typical/data/snapshot.py \ 38 | $(find output/save -type d | sort | tail -n 1) \ 39 | artifacts/snapshot.png 40 | python3 \ 41 | docs/source/example/typical/data/divergence.py \ 42 | output/log/divergence.dat \ 43 | artifacts/divergence.png 44 | python3 \ 45 | docs/source/example/typical/data/balance_main.py \ 46 | $(find output/save -type d | sort | tail -n 1) \ 47 | output/log/dissipation.dat \ 48 | output/log/injection.dat \ 49 | artifacts/balance_main.png 50 | python3 \ 51 | docs/source/example/typical/data/balance_dif.py \ 52 | output/log/dissipation.dat \ 53 | output/log/injection.dat \ 54 | artifacts/balance_dif.png 55 | 56 | -------------------------------------------------------------------------------- /docs/source/example/typical/data/snapshot.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 | x = np.load(f"{dname}/xc.npy") 9 | lengths = np.load(f"{dname}/lengths.npy") 10 | glsizes = np.load(f"{dname}/glsizes.npy") 11 | lz = lengths[2] 12 | glksize = glsizes[2] 13 | dz = lz / glksize 14 | ux = np.load(f"{dname}/ux.npy") 15 | uy = np.load(f"{dname}/uy.npy") 16 | uz = np.load(f"{dname}/uz.npy") 17 | t = np.load(f"{dname}/t.npy") 18 | z = np.linspace(0.5 * dz, lz - 0.5 * dz, glksize) 19 | ux = np.average(ux, axis=1) 20 | uy = np.average(uy, axis=1) 21 | uz = np.average(uz, axis=1) 22 | t = np.average(t, axis=1) 23 | ux = 0.5 * ux[:, 1:] + 0.5 * ux[:, :-1] 24 | uz = uz[:, 1:-1] 25 | # enforce plumes to be centre 26 | argmin = np.argmin(np.average(uy, axis=1)) 27 | ux = np.roll(ux, shift=-argmin, axis=0) 28 | uy = np.roll(uy, shift=-argmin, axis=0) 29 | uz = np.roll(uz, shift=-argmin, axis=0) 30 | t = np.roll(t, shift=-argmin, axis=0) 31 | return x, z, ux, uy, uz, t 32 | 33 | if __name__ == "__main__": 34 | argv = sys.argv 35 | assert 3 == len(argv) 36 | idname = argv[1] 37 | ofname = argv[2] 38 | x, z, ux, uy, uz, t = load(idname) 39 | fig = pyplot.figure() 40 | ax131 = fig.add_subplot(131) 41 | ax132 = fig.add_subplot(132) 42 | ax133 = fig.add_subplot(133) 43 | ax131.contourf(x, z, uy, vmin=0., vmax=1., levels=11, cmap="bwr") 44 | ax132.contourf(x[1:-1], z, (ux**2. + uz**2.)**0.5, levels=11, cmap="bwr") 45 | ax132.quiver(x[1:-1], z, ux, uz) 46 | ax133.contourf(x, z, t, vmin=-0.5, vmax=+0.5, levels=11, cmap="viridis") 47 | kwrds = { 48 | "aspect": "equal", 49 | "xlim": [1., 2.], 50 | "ylim": [0., 2.], 51 | "xlabel": "r", 52 | "ylabel": "z", 53 | "xticks": [1., 1.5, 2.], 54 | "yticks": [0., 1., 2.], 55 | } 56 | ax131.set(**kwrds) 57 | ax132.set(**kwrds) 58 | ax133.set(**kwrds) 59 | ax131.set_title("uy") 60 | ax132.set_title("roll") 61 | ax133.set_title("scalar") 62 | pyplot.savefig(ofname) 63 | pyplot.close() 64 | 65 | -------------------------------------------------------------------------------- /docs/source/example/typical/main.rst: -------------------------------------------------------------------------------- 1 | ############ 2 | Typical case 3 | ############ 4 | 5 | .. include:: /reference/reference.txt 6 | 7 | To check whether the code works properly, a low Reynolds number case is simulated to see the Taylor rolls. 8 | 9 | .. mydetails:: Configuration 10 | 11 | .. literalinclude:: data/exec.sh 12 | :language: bash 13 | 14 | The azimuthal velocity field, radial-axial velocity field, and scalar field averaged in the azimuthal direction are visualised: 15 | 16 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/snapshot.png 17 | :width: 600 18 | 19 | The maximum divergence as a function of time: 20 | 21 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/divergence.png 22 | :width: 600 23 | 24 | The normalised energy injection and dissipation (divided by the laminar reference value) inside the domain is plotted as a function of time. 25 | Note that these normalised energy budgets coincide with the definition of the Nusselt number of the angular velocity flux (|ECKHARDT2007|), and the black-dashed line is displayed as a counterpart (|OSTILLA2013|). 26 | 27 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/balance_main.png 28 | :width: 600 29 | 30 | Recall that the schemes adopted in this project are designed so that the energy injection and the dissipation balances statistically, which can be confirmed by the following plot showing the difference between these two quantities as well as an analogous relation with respect to the passive scalar: 31 | 32 | .. image:: https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/artifacts/artifacts/typical/balance_dif.png 33 | :width: 600 34 | 35 | Initially they are different, which is because the flow is not in a steady state. 36 | Eventually the flow reaches a stationary state, at which the deviations vanish. 37 | 38 | -------------------------------------------------------------------------------- /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 | Simple Taylor-Couette Solver 3 | ############################ 4 | 5 | *A unified incompressible Navier-Stokes solver for Rayleigh-Bénard and Taylor-Couette flows.* 6 | 7 | .. image:: thumbnail.png 8 | :width: 800 9 | 10 | .. toctree:: 11 | :hidden: 12 | 13 | equation/main 14 | discretisation/main 15 | example/main 16 | reference/main 17 | 18 | -------------------------------------------------------------------------------- /docs/source/reference/main.rst: -------------------------------------------------------------------------------- 1 | ######### 2 | Reference 3 | ######### 4 | 5 | .. include:: ./reference.txt 6 | 7 | * |VERZICCO1996| 8 | * |MORINISHI1998| 9 | * |FUKAGATA2002| 10 | * |MORINISHI2004| 11 | * |BARBOSA2005| 12 | * |ECKHARDT2007| 13 | * |OSTILLA2013| 14 | * |OUD2016| 15 | * |KAJISHIMA2017| 16 | -------------------------------------------------------------------------------- /docs/source/reference/reference.txt: -------------------------------------------------------------------------------- 1 | .. |VERZICCO1996| replace:: Verzicco et al., *J. Comput. Phys.* (**123**), 1996 2 | .. |MORINISHI1998| replace:: Morinishi et al., *J. Comput. Phys.* (**143**), 1997 3 | .. |FUKAGATA2002| replace:: Fukagata and Kasagi, *J. Comput. Phys.* (**181**), 2002 4 | .. |MORINISHI2004| replace:: Morinishi et al., *J. Comput. Phys.* (**197**), 2004 5 | .. |BARBOSA2005| replace:: Barbosa and Daube, *Comput. Fluids* (**34**), 2005 6 | .. |ECKHARDT2007| replace:: Eckhardt et al., *J. Fluid Mech.* (**581**), 2007 7 | .. |OSTILLA2013| replace:: Ostilla et al., *J. Fluid Mech.* (**719**), 2013 8 | .. |OUD2016| replace:: Oud et al., *J. Comput. Phys.* (**325**), 2016 9 | .. |KAJISHIMA2017| replace:: Kajishima and Taira, *Springer*, 2017 10 | -------------------------------------------------------------------------------- /docs/source/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NaokiHori/SimpleTCSolver/e0c6362d728a99fada40ed225220b9408a2825c3/docs/source/thumbnail.png -------------------------------------------------------------------------------- /exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## durations 4 | # maximum duration (in free-fall time) 5 | export timemax=5.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=1.0e+0 10 | # save rate (in free-fall time) 11 | export save_rate=5.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+0 16 | # statistics collection after (in free-fall time) 17 | export stat_after=4.0e+2 18 | 19 | ## safety factors to decide time step size 20 | ## for advective and diffusive terms 21 | export coef_dt_adv=1. 22 | export coef_dt_dif=1. 23 | 24 | ## physical parameters 25 | export Re=80. 26 | export Pr=1. 27 | 28 | # name of directory in which initial conditions (incl. domain size etc.) are stored 29 | dirname_ic=initial_condition/output 30 | 31 | mpirun -n 2 --oversubscribe ./a.out ${dirname_ic} 32 | -------------------------------------------------------------------------------- /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 prepare)( 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 | // [0 : isize+1] 7 | #define HXXC(I) (hxxc[(I )]) 8 | #define HXXC_NADDS (int [2]){1, 1} 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/hyxc.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_HYXC_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_HYXC_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [0 : isize+1] 7 | #define HYXC(I) (hyxc[(I )]) 8 | #define HYXC_NADDS (int [2]){1, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_HYXC_H 11 | -------------------------------------------------------------------------------- /include/array_macros/domain/hyxf.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_DOMAIN_HYXF_H) 2 | #define INCLUDE_ARRAY_MACROS_DOMAIN_HYXF_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1] 7 | #define HYXF(I) (hyxf[(I-1)]) 8 | #define HYXF_NADDS (int [2]){0, 1} 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_DOMAIN_HYXF_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 | // [0 : isize+1] 7 | #define JDXC(I) (jdxc[(I )]) 8 | #define JDXC_NADDS (int [2]){1, 1} 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/lxx.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LXX_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LXX_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LXX(I, J, K) (lxx[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LXX_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LXX_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lxy.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LXY_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LXY_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define LXY(I, J, K) (lxy[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define LXY_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LXY_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lxz.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LXZ_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LXZ_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define LXZ(I, J, K) (lxz[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define LXZ_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LXZ_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lyx0.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LYX0_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LYX0_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define LYX0(I, J, K) (lyx0[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define LYX0_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LYX0_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lyx1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LYX1_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LYX1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define LYX1(I, J, K) (lyx1[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define LYX1_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LYX1_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lyy0.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LYY0_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LYY0_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LYY0(I, J, K) (lyy0[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LYY0_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LYY0_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lyy1.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LYY1_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LYY1_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LYY1(I, J, K) (lyy1[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LYY1_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LYY1_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lyz.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LYZ_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LYZ_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LYZ(I, J, K) (lyz[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LYZ_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LYZ_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lzx.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LZX_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LZX_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define LZX(I, J, K) (lzx[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define LZX_NADDS (int [NDIMS][2]){ {0, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LZX_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lzy.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LZY_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LZY_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LZY(I, J, K) (lzy[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LZY_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LZY_H 11 | -------------------------------------------------------------------------------- /include/array_macros/fluid/lzz.h: -------------------------------------------------------------------------------- 1 | #if !defined(INCLUDE_ARRAY_MACROS_FLUID_LZZ_H) 2 | #define INCLUDE_ARRAY_MACROS_FLUID_LZZ_H 3 | 4 | // This file is generated by tools/define_arrays.py 5 | 6 | // [1 : isize+0], [0 : jsize+1], [0 : ksize+1] 7 | #define LZZ(I, J, K) (lzz[(I-1) + (isize+0) * ((J ) + (jsize+2) * (K ))]) 8 | #define LZZ_NADDS (int [NDIMS][2]){ {0, 0}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_LZZ_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], [0 : ksize+1] 7 | #define P(I, J, K) (p[(I ) + (isize+2) * ((J ) + (jsize+2) * (K ))]) 8 | #define P_NADDS (int [NDIMS][2]){ {1, 1}, {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], [0 : ksize+1] 7 | #define PSI(I, J, K) (psi[(I ) + (isize+2) * ((J ) + (jsize+2) * (K ))]) 8 | #define PSI_NADDS (int [NDIMS][2]){ {1, 1}, {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], [1 : ksize+0] 7 | #define SRCT(I, J, K) (srct[(I-1) + (isize+0) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define SRCT_NADDS (int [NDIMS][2]){ {0, 0}, {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], [1 : ksize+0] 7 | #define SRCUX(I, J, K) (srcux[(I-2) + (isize-1) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define SRCUX_NADDS (int [NDIMS][2]){ {-1, 0}, {0, 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], [1 : ksize+0] 7 | #define SRCUY(I, J, K) (srcuy[(I-1) + (isize+0) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define SRCUY_NADDS (int [NDIMS][2]){ {0, 0}, {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 | // [1 : isize+0], [1 : jsize+0], [1 : ksize+0] 7 | #define SRCUZ(I, J, K) (srcuz[(I-1) + (isize+0) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define SRCUZ_NADDS (int [NDIMS][2]){ {0, 0}, {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_SRCUZ_H 11 | -------------------------------------------------------------------------------- /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], [0 : ksize+1] 7 | #define T(I, J, K) (t[(I ) + (isize+2) * ((J ) + (jsize+2) * (K ))]) 8 | #define T_NADDS (int [NDIMS][2]){ {1, 1}, {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], [0 : ksize+1] 7 | #define UX(I, J, K) (ux[(I-1) + (isize+1) * ((J ) + (jsize+2) * (K ))]) 8 | #define UX_NADDS (int [NDIMS][2]){ {0, 1}, {1, 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], [0 : ksize+1] 7 | #define UY(I, J, K) (uy[(I ) + (isize+2) * ((J ) + (jsize+2) * (K ))]) 8 | #define UY_NADDS (int [NDIMS][2]){ {1, 1}, {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 | // [0 : isize+1], [0 : jsize+1], [0 : ksize+1] 7 | #define UZ(I, J, K) (uz[(I ) + (isize+2) * ((J ) + (jsize+2) * (K ))]) 8 | #define UZ_NADDS (int [NDIMS][2]){ {1, 1}, {1, 1}, {1, 1}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_FLUID_UZ_H 11 | -------------------------------------------------------------------------------- /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], [1 : ksize+0] 7 | #define ADV(I, J, K) (adv[(I-1) + (isize+1) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define ADV_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, {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], [1 : ksize+0] 7 | #define DIF(I, J, K) (dif[(I-1) + (isize+1) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define DIF_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_DIF_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], [1 : ksize+0] 7 | #define UX1(I, J, K) (ux1[(I-1) + (isize+1) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UX1_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, {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], [1 : ksize+0] 7 | #define UX2(I, J, K) (ux2[(I-1) + (isize+1) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UX2_NADDS (int [NDIMS][2]){ {0, 1}, {0, 0}, {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], [1 : ksize+0] 7 | #define UY1(I, J, K) (uy1[(I ) + (isize+2) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UY1_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, {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], [1 : ksize+0] 7 | #define UY2(I, J, K) (uy2[(I ) + (isize+2) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UY2_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, {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 | // [0 : isize+1], [1 : jsize+0], [1 : ksize+0] 7 | #define UZ1(I, J, K) (uz1[(I ) + (isize+2) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UZ1_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UZ1_H 11 | -------------------------------------------------------------------------------- /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 | // [0 : isize+1], [1 : jsize+0], [1 : ksize+0] 7 | #define UZ2(I, J, K) (uz2[(I ) + (isize+2) * ((J-1) + (jsize+0) * (K-1))]) 8 | #define UZ2_NADDS (int [NDIMS][2]){ {1, 1}, {0, 0}, {0, 0}, } 9 | 10 | #endif // INCLUDE_ARRAY_MACROS_STATISTICS_UZ2_H 11 | -------------------------------------------------------------------------------- /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 5 | #include "sdecomp.h" 6 | 7 | // definition of a structure domain_t 8 | /** 9 | * @struct domain_t 10 | * @brief struct storing parameters relevant to spatial domain 11 | * @var info : MPI domain decomposition 12 | * @var is_curved : cylindrical (true) or Cartesian (false) 13 | * @var glsizes : global number of grid points in each direction 14 | * @var mysizes : local (my) number of grid points in each direction 15 | * @var offsets : offsets to my starting index in each direction 16 | * @var lengths : domain size in each direction 17 | * @var xf, xc : cell-face and cell-center locations in x direction 18 | * @var hxxf, hxxc : wall-normal scale factors at x faces and centers 19 | * @var hyxf, hyxc : stream-wise scale factors at x faces and centers 20 | * @var hz : span-wise scale factor 21 | * @var jdxf, jdxc : Jacobian determinants at x faces and centers 22 | */ 23 | typedef struct { 24 | sdecomp_info_t * info; 25 | bool is_curved; 26 | size_t glsizes[NDIMS]; 27 | size_t mysizes[NDIMS]; 28 | size_t offsets[NDIMS]; 29 | double lengths[NDIMS]; 30 | double * restrict xf, * restrict xc; 31 | double * restrict jdxf, * restrict jdxc; 32 | double * restrict hxxf, * restrict hxxc; 33 | double * restrict hyxf, * restrict hyxc; 34 | double hz; 35 | } domain_t; 36 | 37 | // constructor 38 | extern int domain_init( 39 | const char dirname_ic[], 40 | domain_t * domain 41 | ); 42 | 43 | // save members which are necessary to restart 44 | extern int domain_save( 45 | const char dirname[], 46 | const domain_t * domain 47 | ); 48 | 49 | #endif // DOMAIN_H 50 | -------------------------------------------------------------------------------- /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 | // 1-byte boolean 12 | const char * npy_boolean; 13 | // 8-byte little-endian unsigned integer 14 | const char * npy_size_t; 15 | // 8-byte little-endian floating point 16 | const char * npy_double; 17 | // initialiser 18 | int (* const init)( 19 | void 20 | ); 21 | // general-purpose file opener 22 | FILE * (* const fopen)( 23 | const char * path, 24 | const char * mode 25 | ); 26 | // general-purpose file closer 27 | int (* const fclose)( 28 | FILE * stream 29 | ); 30 | // prepare directory to be stored 31 | int (* const mkdir)( 32 | const char dirname[] 33 | ); 34 | // NPY serial read (called by one process) 35 | int (* const r_serial)( 36 | const char dirname[], 37 | const char dsetname[], 38 | const size_t ndims, 39 | const size_t * shape, 40 | const char dtype[], 41 | const size_t size, 42 | void * data 43 | ); 44 | // NPY serial write (called by one process) 45 | int (* const w_serial)( 46 | const char dirname[], 47 | const char dsetname[], 48 | const size_t ndims, 49 | const size_t * shape, 50 | const char dtype[], 51 | const size_t size, 52 | const void * data 53 | ); 54 | // NPY parallel read of N-dimensional array (called by all processes) 55 | int (* const r_nd_parallel)( 56 | const MPI_Comm comm, 57 | const char dirname[], 58 | const char dsetname[], 59 | const size_t ndims, 60 | const int * array_of_sizes, 61 | const int * array_of_subsizes, 62 | const int * array_of_starts, 63 | const char dtype[], 64 | const size_t size, 65 | void * data 66 | ); 67 | // NPY parallel write of N-dimensional array (called by all processes) 68 | int (* const w_nd_parallel)( 69 | const MPI_Comm comm, 70 | const char dirname[], 71 | const char dsetname[], 72 | const size_t ndims, 73 | const int * array_of_sizes, 74 | const int * array_of_subsizes, 75 | const int * array_of_starts, 76 | const char dtype[], 77 | const size_t size, 78 | const void * data 79 | ); 80 | } fileio_t; 81 | 82 | extern const fileio_t fileio; 83 | 84 | #endif // FILEIO_H 85 | -------------------------------------------------------------------------------- /include/fluid.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_H) 2 | #define FLUID_H 3 | 4 | #include "array.h" 5 | #include "domain.h" 6 | 7 | // definition of a structure fluid_t_ 8 | /** 9 | * @struct fluid_t 10 | * @brief struct storing fluid-related variables 11 | * @var u[x-z] : velocity in each direction 12 | * @var p, psi : pressure, scalar potential 13 | * @var t : scalar field 14 | * @var srcu[x-z] : Runge-Kutta source terms for velocities 15 | * @var l[x-z][x-z] : velocity-gradient tensor components 16 | * @var Re, Pr : Reynolds and Prandtl number 17 | */ 18 | typedef struct { 19 | array_t ux; 20 | array_t uy; 21 | array_t uz; 22 | array_t p; 23 | array_t psi; 24 | array_t t; 25 | array_t srcux[3]; 26 | array_t srcuy[3]; 27 | array_t srcuz[3]; 28 | array_t srct[3]; 29 | array_t lxx; 30 | array_t lyx0, lyx1, lxy; 31 | array_t lzx, lxz; 32 | array_t lyy0, lyy1; 33 | array_t lzy, lyz; 34 | array_t lzz; 35 | double Re, Pr; 36 | } fluid_t; 37 | 38 | #endif // FLUID_H 39 | -------------------------------------------------------------------------------- /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 | // initialiser of fluid_t 9 | extern int fluid_init( 10 | const char dirname_ic[], 11 | const domain_t * domain, 12 | fluid_t * fluid 13 | ); 14 | 15 | // save flow field 16 | extern int fluid_save( 17 | const char dirname[], 18 | const domain_t * domain, 19 | const fluid_t * fluid 20 | ); 21 | 22 | extern double fluid_compute_momentum_diffusivity ( 23 | const fluid_t * fluid 24 | ); 25 | 26 | extern double fluid_compute_scalar_diffusivity ( 27 | const fluid_t * fluid 28 | ); 29 | 30 | // update fields using the previously-computed RK source terms 31 | extern int fluid_predict_field( 32 | const domain_t * domain, 33 | const size_t rkstep, 34 | const double dt, 35 | fluid_t * fluid 36 | ); 37 | 38 | // compute scalar potential by solving Poisson equation 39 | extern int fluid_compute_potential( 40 | const domain_t * domain, 41 | const size_t rkstep, 42 | const double dt, 43 | fluid_t * fluid 44 | ); 45 | 46 | // correct velocity field using scalar potential 47 | extern int fluid_correct_velocity( 48 | const domain_t * domain, 49 | const size_t rkstep, 50 | const double dt, 51 | fluid_t * fluid 52 | ); 53 | 54 | // update pressure 55 | extern int fluid_update_pressure( 56 | const domain_t * domain, 57 | const size_t rkstep, 58 | const double dt, 59 | fluid_t * fluid 60 | ); 61 | 62 | // exchange halos and impose boundary conditions 63 | 64 | extern int fluid_update_boundaries_ux( 65 | const domain_t * domain, 66 | array_t * array 67 | ); 68 | 69 | extern int fluid_update_boundaries_uy( 70 | const domain_t * domain, 71 | array_t * array 72 | ); 73 | 74 | extern int fluid_update_boundaries_uz( 75 | const domain_t * domain, 76 | array_t * array 77 | ); 78 | 79 | extern int fluid_update_boundaries_p( 80 | const domain_t * domain, 81 | array_t * array 82 | ); 83 | 84 | extern int fluid_update_boundaries_psi( 85 | const domain_t * domain, 86 | array_t * array 87 | ); 88 | 89 | extern int fluid_update_boundaries_t( 90 | const domain_t * domain, 91 | array_t * array 92 | ); 93 | 94 | #endif // FLUID_SOLVER_H 95 | -------------------------------------------------------------------------------- /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 | int halo_communicate_in_z( 11 | const domain_t * domain, 12 | MPI_Datatype * dtype, 13 | array_t * array 14 | ); 15 | 16 | #endif // HALO_H 17 | -------------------------------------------------------------------------------- /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 | double * restrict z2pncl; 30 | size_t x1pncl_mysizes[NDIMS]; 31 | size_t y1pncl_mysizes[NDIMS]; 32 | size_t z2pncl_mysizes[NDIMS]; 33 | tdm_info_t * tdm_x; 34 | tdm_info_t * tdm_y; 35 | tdm_info_t * tdm_z; 36 | sdecomp_transpose_plan_t * transposer_x1_to_y1; 37 | sdecomp_transpose_plan_t * transposer_y1_to_x1; 38 | sdecomp_transpose_plan_t * transposer_x1_to_z2; 39 | sdecomp_transpose_plan_t * transposer_z2_to_x1; 40 | } linear_system_t; 41 | 42 | extern int linear_system_init( 43 | const sdecomp_info_t * info, 44 | const bool implicit[NDIMS], 45 | const size_t glsizes[NDIMS], 46 | linear_system_t * linear_system 47 | ); 48 | 49 | extern int linear_system_finalise( 50 | linear_system_t * linear_system 51 | ); 52 | 53 | #endif // LINEAR_SYSTEM_H 54 | -------------------------------------------------------------------------------- /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 | /* implicit.c */ 11 | // flags to specify the diffusive treatment of the momentum equations 12 | extern const bool param_implicit_x; 13 | extern const bool param_implicit_y; 14 | extern const bool param_implicit_z; 15 | 16 | /* boundary-condition.c */ 17 | // NOTE: impermeable walls and Neumann BC for the pressure are unchangeable 18 | // negative-x-wall velocity in y direction 19 | extern const double param_uy_xm; 20 | // positive-x-wall velocity in y direction 21 | extern const double param_uy_xp; 22 | // scalar value on the negative wall 23 | extern const double param_t_xm; 24 | // scalar value on the positive wall 25 | extern const double param_t_xp; 26 | 27 | #endif // PARAM_H 28 | -------------------------------------------------------------------------------- /include/runge_kutta.h: -------------------------------------------------------------------------------- 1 | #if !defined(RUNGE_KUTTA_H) 2 | #define RUNGE_KUTTA_H 3 | 4 | #include 5 | 6 | // Runge-Kutta configurations 7 | // indices 8 | extern const uint_fast8_t rk_a; // 0 9 | extern const uint_fast8_t rk_b; // 1 10 | extern const uint_fast8_t rk_g; // 2 11 | // NOTE: alpha, beta, gamma and thus three here 12 | typedef double rkcoef_t[3]; 13 | // NOTE: only three-step Wray is allowed 14 | #define RKSTEPMAX 3 15 | extern const rkcoef_t rkcoefs[RKSTEPMAX]; 16 | 17 | #endif // RUNGE_KUTTA_H 18 | -------------------------------------------------------------------------------- /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/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_is_curved(): 10 | truish_list = ["True", "true"] 11 | is_curved = os.environ.get("is_curved") 12 | if None == is_curved: 13 | print("is_curved is not given") 14 | sys.exit(1) 15 | if is_curved in truish_list: 16 | return True 17 | else: 18 | return False 19 | 20 | 21 | def get_lengths(): 22 | lx = os.environ.get("lx") 23 | ly = os.environ.get("ly") 24 | lz = os.environ.get("lz") 25 | if lz: 26 | lengths = [lx, ly, lz] 27 | else: 28 | lengths = [lx, ly] 29 | return list(map(float, lengths)) 30 | 31 | 32 | def get_glsizes(): 33 | glisize = os.environ.get("glisize") 34 | gljsize = os.environ.get("gljsize") 35 | glksize = os.environ.get("glksize") 36 | if glksize: 37 | glsizes = [glisize, gljsize, glksize] 38 | else: 39 | glsizes = [glisize, gljsize] 40 | return list(map(int, glsizes)) 41 | 42 | 43 | def init_time(dest): 44 | # iterator and time 45 | step = np.array(0, dtype=np.uint64) 46 | time = np.array(0, dtype=np.float64) 47 | np.save(f"{dest}/step.npy", step) 48 | np.save(f"{dest}/time.npy", time) 49 | return 50 | 51 | 52 | def init_domain(is_curved, lengths, glsizes, dest): 53 | # generate equidistant sequence 54 | # NOTE: cell face has +1 elements 55 | xf = np.arange(0, glsizes[0] + 1, 1) 56 | # stretched grid, clipped Chebyshev just as an example 57 | is_uniform = False 58 | if not is_uniform: 59 | # number of grid points to be clipped at the edges 60 | nclip = 3 61 | # gather close to the boundaries 62 | xf = np.cos(np.pi * (xf + 1. * nclip) / (glsizes[0] + 2. * nclip)) 63 | # make the descending order ascending 64 | xf *= -1. 65 | # normalse to enforce [0 : lx] 66 | xf = lengths[0] * (xf - np.min(xf)) / (np.max(xf) - np.min(xf)) 67 | # cell centers are located at the center 68 | # of the two neighbouring cell faces, 69 | # which are appended by the boundaries 70 | xc = 0. 71 | xc = np.append(xc, 0.5 * xf[:-1] + 0.5 * xf[1:]) 72 | xc = np.append(xc, lengths[0]) 73 | # offset 74 | # inner cylinder radius for TC domains, otherwise (planar channel) just set 0 75 | xmin = 1. if is_curved else 0. 76 | xf += xmin 77 | xc += xmin 78 | np.save(f"{dest}/is_curved.npy", np.array(is_curved, dtype=np.bool_)) 79 | np.save(f"{dest}/xf.npy", np.array(xf, dtype=np.float64)) 80 | np.save(f"{dest}/xc.npy", np.array(xc, dtype=np.float64)) 81 | np.save(f"{dest}/glsizes.npy", np.array(glsizes, dtype=np.uint64)) 82 | np.save(f"{dest}/lengths.npy", np.array(lengths, dtype=np.float64)) 83 | return xf, xc 84 | 85 | 86 | def init_fluid(is_3d, lengths, glsizes, xf, xc, dest): 87 | if is_3d: 88 | ux = rng.random((glsizes[2], glsizes[1], glsizes[0] + 1), dtype=np.float64) 89 | uy = rng.random((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 90 | uz = rng.random((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 91 | p = rng.random((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 92 | t = rng.random((glsizes[2], glsizes[1], glsizes[0] + 2), dtype=np.float64) 93 | ux -= 0.5 94 | uz -= 0.5 95 | p -= 0.5 96 | t -= 0.5 97 | np.save(f"{dest}/ux.npy", ux) 98 | np.save(f"{dest}/uy.npy", uy) 99 | np.save(f"{dest}/uz.npy", uz) 100 | np.save(f"{dest}/p.npy", p) 101 | np.save(f"{dest}/t.npy", t) 102 | else: 103 | ux = rng.random((glsizes[1], glsizes[0] + 1), dtype=np.float64) 104 | uy = rng.random((glsizes[1], glsizes[0] + 2), dtype=np.float64) 105 | p = rng.random((glsizes[1], glsizes[0] + 2), dtype=np.float64) 106 | t = rng.random((glsizes[1], glsizes[0] + 2), dtype=np.float64) 107 | ux -= 0.5 108 | p -= 0.5 109 | t -= 0.5 110 | np.save(f"{dest}/ux.npy", ux) 111 | np.save(f"{dest}/uy.npy", uy) 112 | np.save(f"{dest}/p.npy", p) 113 | np.save(f"{dest}/t.npy", t) 114 | 115 | 116 | def main(): 117 | is_curved = get_is_curved() 118 | lengths = get_lengths() 119 | glsizes = get_glsizes() 120 | assert len(lengths) == len(glsizes) 121 | dest = sys.argv[1] 122 | is_3d = 3 == len(lengths) 123 | if is_3d: 124 | print("A 3D field is initialised") 125 | else: 126 | print("A 2D field is initialised") 127 | # init and save 128 | init_time(dest) 129 | xf, xc = init_domain(is_curved, lengths, glsizes, dest) 130 | init_fluid(is_3d, lengths, glsizes, xf, xc, dest) 131 | 132 | 133 | main() 134 | -------------------------------------------------------------------------------- /initial_condition/main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## overall configurations 4 | # curved channel (true) or planar channel (false) 5 | # NOTE: for curved channels, the inner cylinder radius is always fixed to 1 6 | export is_curved=true 7 | 8 | ## domain size 9 | # domain lengths 10 | export lx=1.0e+0 11 | export ly=1.0e+0 12 | export lz=2.0e+0 13 | # number of cell centers 14 | export glisize=32 15 | export gljsize=8 16 | export glksize=64 17 | 18 | ## where to write resulting NPY files 19 | export dirname="output" 20 | 21 | python3 main.py ${dirname} 22 | -------------------------------------------------------------------------------- /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 | /** 8 | * @brief update boundary values of the pressure 9 | * @param[in] domain : information about domain decomposition and size 10 | * @param[in,out] array : pressure 11 | * @return : error code 12 | */ 13 | int fluid_update_boundaries_p( 14 | const domain_t * domain, 15 | array_t * array 16 | ){ 17 | // update boundary values 18 | { 19 | const int isize = domain->mysizes[0]; 20 | const int jsize = domain->mysizes[1]; 21 | const int ksize = domain->mysizes[2]; 22 | double * p = array->data; 23 | for(int k = 1; k <= ksize; k++){ 24 | for(int j = 1; j <= jsize; j++){ 25 | // Neumann 26 | P( 0, j, k) = P( 1, j, k); 27 | P(isize+1, j, k) = P(isize, j, k); 28 | } 29 | } 30 | } 31 | // communicate 32 | { 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 41 | return 1; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /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 | /** 8 | * @brief update boundary values of the scalar potential 9 | * @param[in] domain : information about domain decomposition and size 10 | * @param[in,out] psi : scalar potential 11 | * @return : error code 12 | */ 13 | int fluid_update_boundaries_psi( 14 | const domain_t * domain, 15 | array_t * array 16 | ){ 17 | // update boundary values 18 | { 19 | const int isize = domain->mysizes[0]; 20 | const int jsize = domain->mysizes[1]; 21 | const int ksize = domain->mysizes[2]; 22 | double * psi = array->data; 23 | for(int k = 1; k <= ksize; k++){ 24 | for(int j = 1; j <= jsize; j++){ 25 | // Neumann 26 | PSI( 0, j, k) = PSI( 1, j, k); 27 | PSI(isize+1, j, k) = PSI(isize, j, k); 28 | } 29 | } 30 | } 31 | // communicate 32 | { 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 41 | return 1; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /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 | /** 9 | * @brief update boundary values of the scalar 10 | * @param[in] domain : information about domain decomposition and size 11 | * @param[in,out] t : scalar 12 | * @return : error code 13 | */ 14 | int fluid_update_boundaries_t( 15 | const domain_t * domain, 16 | array_t * array 17 | ){ 18 | // update boundary values 19 | { 20 | const int isize = domain->mysizes[0]; 21 | const int jsize = domain->mysizes[1]; 22 | const int ksize = domain->mysizes[2]; 23 | double * t = array->data; 24 | for(int k = 1; k <= ksize; k++){ 25 | for(int j = 1; j <= jsize; j++){ 26 | T( 0, j, k) = param_t_xm; 27 | T(isize+1, j, k) = param_t_xp; 28 | } 29 | } 30 | } 31 | // communicate 32 | { 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 41 | return 1; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /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 | /** 8 | * @brief update boundary values of x velocity 9 | * @param[in] domain : information about domain decomposition and size 10 | * @param[in,out] array : x velocity 11 | * @return : error code 12 | */ 13 | int fluid_update_boundaries_ux( 14 | const domain_t * domain, 15 | array_t * array 16 | ){ 17 | // update boundary values 18 | { 19 | const int isize = domain->mysizes[0]; 20 | const int jsize = domain->mysizes[1]; 21 | const int ksize = domain->mysizes[2]; 22 | double * ux = array->data; 23 | for(int k = 1; k <= ksize; k++){ 24 | for(int j = 1; j <= jsize; j++){ 25 | // impermeable 26 | UX( 1, j, k) = 0.; 27 | UX(isize+1, j, k) = 0.; 28 | } 29 | } 30 | } 31 | // communicate 32 | { 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 41 | return 1; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /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 | /** 9 | * @brief update boundary values of y velocity 10 | * @param[in] domain : information about domain decomposition and size 11 | * @param[in,out] uy : y velocity 12 | * @return : error code 13 | */ 14 | int fluid_update_boundaries_uy( 15 | const domain_t * domain, 16 | array_t * array 17 | ){ 18 | // update boundary values 19 | { 20 | const int isize = domain->mysizes[0]; 21 | const int jsize = domain->mysizes[1]; 22 | const int ksize = domain->mysizes[2]; 23 | double * uy = array->data; 24 | for(int k = 1; k <= ksize; k++){ 25 | for(int j = 1; j <= jsize; j++){ 26 | // no-slip 27 | UY( 0, j, k) = param_uy_xm; 28 | UY(isize+1, j, k) = param_uy_xp; 29 | } 30 | } 31 | } 32 | // communicate 33 | { 34 | static MPI_Datatype dtypes[NDIMS - 1] = { 35 | MPI_DOUBLE, 36 | MPI_DOUBLE, 37 | }; 38 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 39 | return 1; 40 | } 41 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 42 | return 1; 43 | } 44 | } 45 | return 0; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/fluid/boundary/uz.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/uz.h" 7 | 8 | /** 9 | * @brief update boundary values of z velocity 10 | * @param[in] domain : information about domain decomposition and size 11 | * @param[in,out] array : z velocity 12 | * @return : error code 13 | */ 14 | int fluid_update_boundaries_uz( 15 | const domain_t * domain, 16 | array_t * array 17 | ){ 18 | // update boundary values 19 | { 20 | const int isize = domain->mysizes[0]; 21 | const int jsize = domain->mysizes[1]; 22 | const int ksize = domain->mysizes[2]; 23 | double * uz = array->data; 24 | for(int k = 1; k <= ksize; k++){ 25 | for(int j = 1; j <= jsize; j++){ 26 | // no-slip 27 | UZ( 0, j, k) = 0.; 28 | UZ(isize+1, j, k) = 0.; 29 | } 30 | } 31 | } 32 | // communicate 33 | { 34 | static MPI_Datatype dtypes[NDIMS - 1] = { 35 | MPI_DOUBLE, 36 | MPI_DOUBLE, 37 | }; 38 | if(0 != halo_communicate_in_y(domain, dtypes + 0, array)){ 39 | return 1; 40 | } 41 | if(0 != halo_communicate_in_z(domain, dtypes + 1, array)){ 42 | return 1; 43 | } 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/fluid/compute_diffusivity.c: -------------------------------------------------------------------------------- 1 | #include "fluid.h" 2 | 3 | double fluid_compute_momentum_diffusivity ( 4 | const fluid_t * fluid 5 | ) { 6 | return 1. / fluid->Re; 7 | } 8 | 9 | double fluid_compute_scalar_diffusivity ( 10 | const fluid_t * fluid 11 | ) { 12 | return 1. / fluid->Re / fluid->Pr; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /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 | extern int fluid_correct_velocity_uz( 17 | const domain_t * domain, 18 | const double prefactor, 19 | fluid_t * fluid 20 | ); 21 | 22 | #endif // FLUID_CORRECT_VELOCITY_INTERNAL_H 23 | -------------------------------------------------------------------------------- /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][rk_g]; 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 | if(0 != fluid_correct_velocity_uz(domain, prefactor, fluid)) return 1; 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /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 k = 1; k <= ksize; k++){ \ 11 | for(int j = 1; j <= jsize; j++){ \ 12 | for(int i = 2; i <= isize; i++){ 13 | #define END \ 14 | } \ 15 | } \ 16 | } 17 | 18 | /** 19 | * @brief correct ux using scalar potential psi 20 | * @param[in] domain : information about domain decomposition and size 21 | * @param[in] prefactor : pre-factor in front of grad psi 22 | * @param[in,out] fluid : scalar potential psi (in), ux (out) 23 | * @return : error code 24 | */ 25 | int fluid_correct_velocity_ux( 26 | const domain_t * domain, 27 | const double prefactor, 28 | fluid_t * fluid 29 | ){ 30 | const int isize = domain->mysizes[0]; 31 | const int jsize = domain->mysizes[1]; 32 | const int ksize = domain->mysizes[2]; 33 | const double * restrict hxxf = domain->hxxf; 34 | const double * restrict psi = fluid->psi.data; 35 | double * restrict ux = fluid->ux.data; 36 | // correct x velocity 37 | BEGIN 38 | const double hx = HXXF(i ); 39 | const double psi_xm = PSI(i-1, j , k ); 40 | const double psi_xp = PSI(i , j , k ); 41 | double * vel = &UX(i, j, k); 42 | *vel -= prefactor / hx * ( 43 | - psi_xm 44 | + psi_xp 45 | ); 46 | END 47 | // update boundary and halo cells 48 | if(0 != fluid_update_boundaries_ux(domain, &fluid->ux)){ 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /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/domain/hyxc.h" 6 | #include "array_macros/fluid/uy.h" 7 | #include "array_macros/fluid/psi.h" 8 | 9 | #define BEGIN \ 10 | for(int k = 1; k <= ksize; k++){ \ 11 | for(int j = 1; j <= jsize; j++){ \ 12 | for(int i = 1; i <= isize; i++){ 13 | #define END \ 14 | } \ 15 | } \ 16 | } 17 | 18 | /** 19 | * @brief correct uy using scalar potential psi 20 | * @param[in] domain : information about domain decomposition and size 21 | * @param[in] prefactor : pre-factor in front of grad psi 22 | * @param[in,out] fluid : scalar potential psi (in), uy (out) 23 | * @return : error code 24 | */ 25 | int fluid_correct_velocity_uy( 26 | const domain_t * domain, 27 | const double prefactor, 28 | fluid_t * fluid 29 | ){ 30 | const int isize = domain->mysizes[0]; 31 | const int jsize = domain->mysizes[1]; 32 | const int ksize = domain->mysizes[2]; 33 | const double * restrict hyxc = domain->hyxc; 34 | const double * restrict psi = fluid->psi.data; 35 | double * restrict uy = fluid->uy.data; 36 | // correct y velocity 37 | BEGIN 38 | const double hy = HYXC(i ); 39 | const double psi_ym = PSI(i , j-1, k ); 40 | const double psi_yp = PSI(i , j , k ); 41 | double * vel = &UY(i, j, k); 42 | *vel -= prefactor / hy * ( 43 | - psi_ym 44 | + psi_yp 45 | ); 46 | END 47 | // update boundary and halo cells 48 | if(0 != fluid_update_boundaries_uy(domain, &fluid->uy)){ 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/fluid/correct/uz.c: -------------------------------------------------------------------------------- 1 | #include "domain.h" 2 | #include "fluid.h" 3 | #include "fluid_solver.h" 4 | #include "internal.h" 5 | #include "array_macros/fluid/uz.h" 6 | #include "array_macros/fluid/psi.h" 7 | 8 | /** 9 | * @brief correct uz using scalar potential psi 10 | * @param[in] domain : information about domain decomposition and size 11 | * @param[in] prefactor : pre-factor in front of grad psi 12 | * @param[in,out] fluid : scalar potential psi (in), uz (out) 13 | * @return : error code 14 | */ 15 | int fluid_correct_velocity_uz( 16 | const domain_t * domain, 17 | const double prefactor, 18 | fluid_t * fluid 19 | ){ 20 | const int isize = domain->mysizes[0]; 21 | const int jsize = domain->mysizes[1]; 22 | const int ksize = domain->mysizes[2]; 23 | const double hz = domain->hz; 24 | const double * restrict psi = fluid->psi.data; 25 | double * restrict uz = fluid->uz.data; 26 | // correct z velocity 27 | for(int k = 1; k <= ksize; k++){ 28 | for(int j = 1; j <= jsize; j++){ 29 | for(int i = 1; i <= isize; i++){ 30 | const double psi_zm = PSI(i , j , k-1); 31 | const double psi_zp = PSI(i , j , k ); 32 | UZ(i, j, k) -= prefactor / hz * ( 33 | - psi_zm 34 | + psi_zp 35 | ); 36 | } 37 | } 38 | } 39 | // update boundary and halo cells 40 | if(0 != fluid_update_boundaries_uz(domain, &fluid->uz)){ 41 | return 1; 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/fluid/predict/internal.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLUID_INTEGRATE_INTERNAL) 2 | #define FLUID_INTEGRATE_INTERNAL 3 | 4 | #include "linear_system.h" 5 | #include "fluid.h" 6 | 7 | // store approximation of laplacian 8 | typedef struct { 9 | double l; 10 | double c; 11 | double u; 12 | } laplacian_t; 13 | 14 | // store Laplacian for each directoin 15 | typedef struct { 16 | bool is_initialised; 17 | laplacian_t * restrict lapx; 18 | laplacian_t * restrict lapy; 19 | laplacian_t lapz; 20 | } laplacians_t; 21 | 22 | extern int compute_lxx( 23 | const domain_t * domain, 24 | fluid_t * fluid 25 | ); 26 | 27 | extern int compute_lxy( 28 | const domain_t * domain, 29 | fluid_t * fluid 30 | ); 31 | 32 | extern int compute_lxz( 33 | const domain_t * domain, 34 | fluid_t * fluid 35 | ); 36 | 37 | extern int compute_lyx( 38 | const domain_t * domain, 39 | fluid_t * fluid 40 | ); 41 | 42 | extern int compute_lyy( 43 | const domain_t * domain, 44 | fluid_t * fluid 45 | ); 46 | 47 | extern int compute_lyz( 48 | const domain_t * domain, 49 | fluid_t * fluid 50 | ); 51 | 52 | extern int compute_lzx( 53 | const domain_t * domain, 54 | fluid_t * fluid 55 | ); 56 | 57 | extern int compute_lzy( 58 | const domain_t * domain, 59 | fluid_t * fluid 60 | ); 61 | 62 | extern int compute_lzz( 63 | const domain_t * domain, 64 | fluid_t * fluid 65 | ); 66 | 67 | extern int compute_rhs_ux( 68 | const domain_t * domain, 69 | fluid_t * fluid 70 | ); 71 | 72 | extern int compute_rhs_uy( 73 | const domain_t * domain, 74 | fluid_t * fluid 75 | ); 76 | 77 | extern int compute_rhs_uz( 78 | const domain_t * domain, 79 | fluid_t * fluid 80 | ); 81 | 82 | extern int compute_rhs_t( 83 | const domain_t * domain, 84 | fluid_t * fluid 85 | ); 86 | 87 | extern int update_ux( 88 | const domain_t * domain, 89 | const size_t rkstep, 90 | const double dt, 91 | fluid_t * fluid 92 | ); 93 | 94 | extern int update_uy( 95 | const domain_t * domain, 96 | const size_t rkstep, 97 | const double dt, 98 | fluid_t * fluid 99 | ); 100 | 101 | extern int update_uz( 102 | const domain_t * domain, 103 | const size_t rkstep, 104 | const double dt, 105 | fluid_t * fluid 106 | ); 107 | 108 | extern int update_t( 109 | const domain_t * domain, 110 | const size_t rkstep, 111 | const double dt, 112 | fluid_t * fluid 113 | ); 114 | 115 | extern int solve_in_x( 116 | const double prefactor, 117 | const laplacian_t * lapx, 118 | linear_system_t * linear_system 119 | ); 120 | 121 | extern int solve_in_y( 122 | const double prefactor, 123 | const laplacian_t * lapy, 124 | linear_system_t * linear_system 125 | ); 126 | 127 | extern int solve_in_z( 128 | const double prefactor, 129 | const laplacian_t * lapz, 130 | linear_system_t * linear_system 131 | ); 132 | 133 | #endif // FLUID_INTEGRATE_INTERNAL 134 | -------------------------------------------------------------------------------- /src/fluid/predict/linear_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "linear_system.h" 3 | #include "tdm.h" 4 | #include "internal.h" 5 | 6 | int solve_in_x( 7 | const double prefactor, 8 | const laplacian_t * lapx, 9 | linear_system_t * linear_system 10 | ){ 11 | const size_t * mysizes = linear_system->x1pncl_mysizes; 12 | const size_t isize = mysizes[0]; 13 | const size_t jsize = mysizes[1]; 14 | const size_t ksize = mysizes[2]; 15 | tdm_info_t * tdm_info = linear_system->tdm_x; 16 | int tdm_size = 0; 17 | double * restrict tdm_l = NULL; 18 | double * restrict tdm_c = NULL; 19 | double * restrict tdm_u = NULL; 20 | tdm.get_size(tdm_info, &tdm_size); 21 | tdm.get_l(tdm_info, &tdm_l); 22 | tdm.get_c(tdm_info, &tdm_c); 23 | tdm.get_u(tdm_info, &tdm_u); 24 | assert((size_t)tdm_size == isize); 25 | double * restrict x1pncl = linear_system->x1pncl; 26 | for(size_t k = 0; k < ksize; k++){ 27 | for(size_t j = 0; j < jsize; j++){ 28 | for(size_t i = 0; i < isize; i++){ 29 | tdm_l[i] = - prefactor * lapx[i].l; 30 | tdm_c[i] = 1. - prefactor * lapx[i].c; 31 | tdm_u[i] = - prefactor * lapx[i].u; 32 | } 33 | tdm.solve(tdm_info, x1pncl + (k * jsize + j) * isize); 34 | } 35 | } 36 | return 0; 37 | } 38 | 39 | int solve_in_y( 40 | const double prefactor, 41 | const laplacian_t * lapy, 42 | linear_system_t * linear_system 43 | ){ 44 | const size_t * mysizes = linear_system->y1pncl_mysizes; 45 | const size_t isize = mysizes[0]; 46 | const size_t jsize = mysizes[1]; 47 | const size_t ksize = mysizes[2]; 48 | tdm_info_t * tdm_info = linear_system->tdm_y; 49 | int tdm_size = 0; 50 | double * restrict tdm_l = NULL; 51 | double * restrict tdm_c = NULL; 52 | double * restrict tdm_u = NULL; 53 | tdm.get_size(tdm_info, &tdm_size); 54 | tdm.get_l(tdm_info, &tdm_l); 55 | tdm.get_c(tdm_info, &tdm_c); 56 | tdm.get_u(tdm_info, &tdm_u); 57 | assert((size_t)tdm_size == jsize); 58 | double * restrict y1pncl = linear_system->y1pncl; 59 | for(size_t i = 0; i < isize; i++){ 60 | for(size_t k = 0; k < ksize; k++){ 61 | for(size_t j = 0; j < jsize; j++){ 62 | tdm_l[j] = - prefactor * lapy[i].l; 63 | tdm_c[j] = 1. - prefactor * lapy[i].c; 64 | tdm_u[j] = - prefactor * lapy[i].u; 65 | } 66 | tdm.solve(tdm_info, y1pncl + (i * ksize + k) * jsize); 67 | } 68 | } 69 | return 0; 70 | } 71 | 72 | int solve_in_z( 73 | const double prefactor, 74 | const laplacian_t * lapz, 75 | linear_system_t * linear_system 76 | ){ 77 | const size_t * mysizes = linear_system->z2pncl_mysizes; 78 | const size_t isize = mysizes[0]; 79 | const size_t jsize = mysizes[1]; 80 | const size_t ksize = mysizes[2]; 81 | tdm_info_t * tdm_info = linear_system->tdm_z; 82 | int tdm_size = 0; 83 | double * restrict tdm_l = NULL; 84 | double * restrict tdm_c = NULL; 85 | double * restrict tdm_u = NULL; 86 | tdm.get_size(tdm_info, &tdm_size); 87 | tdm.get_l(tdm_info, &tdm_l); 88 | tdm.get_c(tdm_info, &tdm_c); 89 | tdm.get_u(tdm_info, &tdm_u); 90 | assert((size_t)tdm_size == ksize); 91 | double * restrict z2pncl = linear_system->z2pncl; 92 | for(size_t j = 0; j < jsize; j++){ 93 | for(size_t i = 0; i < isize; i++){ 94 | for(size_t k = 0; k < ksize; k++){ 95 | tdm_l[k] = - prefactor * (*lapz).l; 96 | tdm_c[k] = 1. - prefactor * (*lapz).c; 97 | tdm_u[k] = - prefactor * (*lapz).u; 98 | } 99 | tdm.solve(tdm_info, z2pncl + (j * isize + i) * ksize); 100 | } 101 | } 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/fluid/predict/lxx.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hxxc.h" 6 | #include "array_macros/fluid/ux.h" 7 | #include "array_macros/fluid/lxx.h" 8 | #include "internal.h" 9 | 10 | #define BEGIN \ 11 | for(int k = 1; k <= ksize; k++){ \ 12 | for(int j = 1; j <= jsize; j++){ \ 13 | for(int i = 1; i <= isize; i++){ 14 | #define END \ 15 | } \ 16 | } \ 17 | } 18 | 19 | int compute_lxx( 20 | const domain_t * domain, 21 | fluid_t * fluid 22 | ){ 23 | const int isize = domain->mysizes[0]; 24 | const int jsize = domain->mysizes[1]; 25 | const int ksize = domain->mysizes[2]; 26 | const double * restrict hxxc = domain->hxxc; 27 | const double * restrict ux = fluid->ux.data; 28 | array_t * lxx_array = &fluid->lxx; 29 | double * restrict lxx = lxx_array->data; 30 | // compute lxx 31 | BEGIN 32 | const double hx = HXXC(i ); 33 | LXX(i, j, k) = 1. / hx * ( 34 | - UX(i , j , k ) 35 | + UX(i+1, j , k ) 36 | ); 37 | END 38 | static MPI_Datatype dtypes[NDIMS - 1] = { 39 | MPI_DOUBLE, 40 | MPI_DOUBLE, 41 | }; 42 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lxx_array)){ 43 | return 1; 44 | } 45 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lxx_array)){ 46 | return 1; 47 | } 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/fluid/predict/lxy.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hxxf.h" 6 | #include "array_macros/fluid/uy.h" 7 | #include "array_macros/fluid/lxy.h" 8 | #include "internal.h" 9 | 10 | #define BEGIN \ 11 | for(int k = 1; k <= ksize; k++){ \ 12 | for(int j = 1; j <= jsize; j++){ \ 13 | for(int i = 1; i <= isize + 1; i++){ 14 | #define END \ 15 | } \ 16 | } \ 17 | } 18 | 19 | int compute_lxy( 20 | const domain_t * domain, 21 | fluid_t * fluid 22 | ){ 23 | const int isize = domain->mysizes[0]; 24 | const int jsize = domain->mysizes[1]; 25 | const int ksize = domain->mysizes[2]; 26 | const double * restrict hxxf = domain->hxxf; 27 | const double * restrict uy = fluid->uy.data; 28 | array_t * lxy_array = &fluid->lxy; 29 | double * restrict lxy = lxy_array->data; 30 | // compute lxy 31 | BEGIN 32 | const double hx = HXXF(i ); 33 | LXY(i, j, k) = 1. / hx * ( 34 | - UY(i-1, j , k ) 35 | + UY(i , j , k ) 36 | ); 37 | END 38 | static MPI_Datatype dtypes[NDIMS - 1] = { 39 | MPI_DOUBLE, 40 | MPI_DOUBLE, 41 | }; 42 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lxy_array)){ 43 | return 1; 44 | } 45 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lxy_array)){ 46 | return 1; 47 | } 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/fluid/predict/lxz.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hxxf.h" 6 | #include "array_macros/fluid/uz.h" 7 | #include "array_macros/fluid/lxz.h" 8 | #include "internal.h" 9 | 10 | int compute_lxz( 11 | const domain_t * domain, 12 | fluid_t * fluid 13 | ){ 14 | const int isize = domain->mysizes[0]; 15 | const int jsize = domain->mysizes[1]; 16 | const int ksize = domain->mysizes[2]; 17 | const double * restrict hxxf = domain->hxxf; 18 | const double * restrict uz = fluid->uz.data; 19 | array_t * lxz_array = &fluid->lxz; 20 | double * restrict lxz = lxz_array->data; 21 | // compute lxz 22 | for(int k = 1; k <= ksize; k++){ 23 | for(int j = 1; j <= jsize; j++){ 24 | for(int i = 1; i <= isize + 1; i++){ 25 | const double hx = HXXF(i ); 26 | LXZ(i, j, k) = 1. / hx * ( 27 | - UZ(i-1, j , k ) 28 | + UZ(i , j , k ) 29 | ); 30 | } 31 | } 32 | } 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lxz_array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lxz_array)){ 41 | return 1; 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/fluid/predict/lyx.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hxxc.h" 6 | #include "array_macros/domain/hyxf.h" 7 | #include "array_macros/domain/jdxf.h" 8 | #include "array_macros/domain/jdxc.h" 9 | #include "array_macros/fluid/ux.h" 10 | #include "array_macros/fluid/uy.h" 11 | #include "array_macros/fluid/lyx0.h" 12 | #include "array_macros/fluid/lyx1.h" 13 | #include "internal.h" 14 | 15 | #define BEGIN \ 16 | for(int k = 1; k <= ksize; k++){ \ 17 | for(int j = 1; j <= jsize; j++){ \ 18 | for(int i = 1; i <= isize + 1; i++){ 19 | #define END \ 20 | } \ 21 | } \ 22 | } 23 | 24 | static int compute_lyx0( 25 | const domain_t * domain, 26 | fluid_t * fluid 27 | ){ 28 | const int isize = domain->mysizes[0]; 29 | const int jsize = domain->mysizes[1]; 30 | const int ksize = domain->mysizes[2]; 31 | const double * restrict hyxf = domain->hyxf; 32 | const double * restrict ux = fluid->ux.data; 33 | array_t * lyx0_array = &fluid->lyx0; 34 | double * restrict lyx0 = lyx0_array->data; 35 | // compute dominant term of lyx 36 | BEGIN 37 | const double hy = HYXF(i ); 38 | LYX0(i, j, k) = 1. / hy * ( 39 | - UX(i , j-1, k ) 40 | + UX(i , j , k ) 41 | ); 42 | END 43 | static MPI_Datatype dtypes[NDIMS - 1] = { 44 | MPI_DOUBLE, 45 | MPI_DOUBLE, 46 | }; 47 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lyx0_array)){ 48 | return 1; 49 | } 50 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lyx0_array)){ 51 | return 1; 52 | } 53 | return 0; 54 | } 55 | 56 | static int compute_lyx1( 57 | const domain_t * domain, 58 | fluid_t * fluid 59 | ){ 60 | const int isize = domain->mysizes[0]; 61 | const int jsize = domain->mysizes[1]; 62 | const int ksize = domain->mysizes[2]; 63 | const double * restrict hxxc = domain->hxxc; 64 | const double * restrict jdxf = domain->jdxf; 65 | const double * restrict jdxc = domain->jdxc; 66 | const double * restrict uy = fluid->uy.data; 67 | array_t * lyx1_array = &fluid->lyx1; 68 | double * restrict lyx1 = lyx1_array->data; 69 | // compute non-dominant term of lyx 70 | BEGIN 71 | const double hx_xm = HXXC(i-1); 72 | const double hx_xp = HXXC(i ); 73 | const double jd_xm = JDXC(i-1); 74 | const double jd_x0 = JDXF(i ); 75 | const double jd_xp = JDXC(i ); 76 | const double jdhx_xm = jd_xm / hx_xm; 77 | const double jdhx_xp = jd_xp / hx_xp; 78 | const double djdhx = - jdhx_xm + jdhx_xp; 79 | LYX1(i, j, k) = - 1. / jd_x0 * djdhx * ( 80 | + ( 1 == i ? 0. : 0.5) * UY(i-1, j , k ) 81 | + (isize + 1 == i ? 0. : 0.5) * UY(i , j , k ) 82 | ); 83 | END 84 | static MPI_Datatype dtypes[NDIMS - 1] = { 85 | MPI_DOUBLE, 86 | MPI_DOUBLE, 87 | }; 88 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lyx1_array)){ 89 | return 1; 90 | } 91 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lyx1_array)){ 92 | return 1; 93 | } 94 | return 0; 95 | } 96 | 97 | int compute_lyx( 98 | const domain_t * domain, 99 | fluid_t * fluid 100 | ){ 101 | compute_lyx0(domain, fluid); 102 | compute_lyx1(domain, fluid); 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/fluid/predict/lyy.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hxxf.h" 6 | #include "array_macros/domain/hyxc.h" 7 | #include "array_macros/domain/jdxf.h" 8 | #include "array_macros/domain/jdxc.h" 9 | #include "array_macros/fluid/ux.h" 10 | #include "array_macros/fluid/uy.h" 11 | #include "array_macros/fluid/lyy0.h" 12 | #include "array_macros/fluid/lyy1.h" 13 | #include "internal.h" 14 | 15 | #define BEGIN \ 16 | for(int k = 1; k <= ksize; k++){ \ 17 | for(int j = 1; j <= jsize; j++){ \ 18 | for(int i = 1; i <= isize; i++){ 19 | #define END \ 20 | } \ 21 | } \ 22 | } 23 | 24 | static int compute_lyy0( 25 | const domain_t * domain, 26 | fluid_t * fluid 27 | ){ 28 | const int isize = domain->mysizes[0]; 29 | const int jsize = domain->mysizes[1]; 30 | const int ksize = domain->mysizes[2]; 31 | const double * restrict hyxc = domain->hyxc; 32 | const double * restrict uy = fluid->uy.data; 33 | array_t * lyy0_array = &fluid->lyy0; 34 | double * restrict lyy0 = lyy0_array->data; 35 | // compute dominant term of lyy 36 | BEGIN 37 | const double hy = HYXC(i ); 38 | LYY0(i, j, k) = 1. / hy * ( 39 | - UY(i , j , k ) 40 | + UY(i , j+1, k ) 41 | ); 42 | END 43 | static MPI_Datatype dtypes[NDIMS - 1] = { 44 | MPI_DOUBLE, 45 | MPI_DOUBLE, 46 | }; 47 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lyy0_array)){ 48 | return 1; 49 | } 50 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lyy0_array)){ 51 | return 1; 52 | } 53 | return 0; 54 | } 55 | 56 | static int compute_lyy1( 57 | const domain_t * domain, 58 | fluid_t * fluid 59 | ){ 60 | const int isize = domain->mysizes[0]; 61 | const int jsize = domain->mysizes[1]; 62 | const int ksize = domain->mysizes[2]; 63 | const double * restrict hxxf = domain->hxxf; 64 | const double * restrict jdxf = domain->jdxf; 65 | const double * restrict jdxc = domain->jdxc; 66 | const double * restrict ux = fluid->ux.data; 67 | array_t * lyy1_array = &fluid->lyy1; 68 | double * restrict lyy1 = lyy1_array->data; 69 | // compute non-dominant term of lyy 70 | BEGIN 71 | const double hx_xm = HXXF(i ); 72 | const double hx_xp = HXXF(i+1); 73 | const double jd_xm = JDXF(i ); 74 | const double jd_x0 = JDXC(i ); 75 | const double jd_xp = JDXF(i+1); 76 | const double jdhx_xm = jd_xm / hx_xm; 77 | const double jdhx_xp = jd_xp / hx_xp; 78 | const double djdhx = - jdhx_xm + jdhx_xp; 79 | LYY1(i, j, k) = 1. / jd_x0 * djdhx * ( 80 | + 0.5 * UX(i , j , k ) 81 | + 0.5 * UX(i+1, j , k ) 82 | ); 83 | END 84 | static MPI_Datatype dtypes[NDIMS - 1] = { 85 | MPI_DOUBLE, 86 | MPI_DOUBLE, 87 | }; 88 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lyy1_array)){ 89 | return 1; 90 | } 91 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lyy1_array)){ 92 | return 1; 93 | } 94 | return 0; 95 | } 96 | 97 | int compute_lyy( 98 | const domain_t * domain, 99 | fluid_t * fluid 100 | ){ 101 | compute_lyy0(domain, fluid); 102 | compute_lyy1(domain, fluid); 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/fluid/predict/lyz.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/domain/hyxc.h" 6 | #include "array_macros/fluid/uz.h" 7 | #include "array_macros/fluid/lyz.h" 8 | #include "internal.h" 9 | 10 | int compute_lyz( 11 | const domain_t * domain, 12 | fluid_t * fluid 13 | ){ 14 | const int isize = domain->mysizes[0]; 15 | const int jsize = domain->mysizes[1]; 16 | const int ksize = domain->mysizes[2]; 17 | const double * restrict hyxc = domain->hyxc; 18 | const double * restrict uz = fluid->uz.data; 19 | array_t * lyz_array = &fluid->lyz; 20 | double * restrict lyz = lyz_array->data; 21 | // compute lyz 22 | for(int k = 1; k <= ksize; k++){ 23 | for(int j = 1; j <= jsize; j++){ 24 | for(int i = 1; i <= isize; i++){ 25 | const double hy = HYXC(i ); 26 | LYZ(i, j, k) = 1. / hy * ( 27 | - UZ(i , j-1, k ) 28 | + UZ(i , j , k ) 29 | ); 30 | } 31 | } 32 | } 33 | static MPI_Datatype dtypes[NDIMS - 1] = { 34 | MPI_DOUBLE, 35 | MPI_DOUBLE, 36 | }; 37 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lyz_array)){ 38 | return 1; 39 | } 40 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lyz_array)){ 41 | return 1; 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/fluid/predict/lzx.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/fluid/ux.h" 6 | #include "array_macros/fluid/lzx.h" 7 | #include "internal.h" 8 | 9 | int compute_lzx( 10 | const domain_t * domain, 11 | fluid_t * fluid 12 | ){ 13 | const int isize = domain->mysizes[0]; 14 | const int jsize = domain->mysizes[1]; 15 | const int ksize = domain->mysizes[2]; 16 | const double hz = domain->hz; 17 | const double * restrict ux = fluid->ux.data; 18 | array_t * lzx_array = &fluid->lzx; 19 | double * restrict lzx = lzx_array->data; 20 | // compute lzx 21 | for(int k = 1; k <= ksize; k++){ 22 | for(int j = 1; j <= jsize; j++){ 23 | for(int i = 1; i <= isize + 1; i++){ 24 | LZX(i, j, k) = 1. / hz * ( 25 | - UX(i , j , k-1) 26 | + UX(i , j , k ) 27 | ); 28 | } 29 | } 30 | } 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | MPI_DOUBLE, 34 | }; 35 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lzx_array)){ 36 | return 1; 37 | } 38 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lzx_array)){ 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /src/fluid/predict/lzy.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/fluid/uy.h" 6 | #include "array_macros/fluid/lzy.h" 7 | #include "internal.h" 8 | 9 | int compute_lzy( 10 | const domain_t * domain, 11 | fluid_t * fluid 12 | ){ 13 | const int isize = domain->mysizes[0]; 14 | const int jsize = domain->mysizes[1]; 15 | const int ksize = domain->mysizes[2]; 16 | const double hz = domain->hz; 17 | const double * restrict uy = fluid->uy.data; 18 | array_t * lzy_array = &fluid->lzy; 19 | double * restrict lzy = lzy_array->data; 20 | // compute lzy 21 | for(int k = 1; k <= ksize; k++){ 22 | for(int j = 1; j <= jsize; j++){ 23 | for(int i = 1; i <= isize; i++){ 24 | LZY(i, j, k) = 1. / hz * ( 25 | - UY(i , j , k-1) 26 | + UY(i , j , k ) 27 | ); 28 | } 29 | } 30 | } 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | MPI_DOUBLE, 34 | }; 35 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lzy_array)){ 36 | return 1; 37 | } 38 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lzy_array)){ 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /src/fluid/predict/lzz.c: -------------------------------------------------------------------------------- 1 | #include "array.h" 2 | #include "domain.h" 3 | #include "halo.h" 4 | #include "fluid.h" 5 | #include "array_macros/fluid/uz.h" 6 | #include "array_macros/fluid/lzz.h" 7 | #include "internal.h" 8 | 9 | int compute_lzz( 10 | const domain_t * domain, 11 | fluid_t * fluid 12 | ){ 13 | const int isize = domain->mysizes[0]; 14 | const int jsize = domain->mysizes[1]; 15 | const int ksize = domain->mysizes[2]; 16 | const double hz = domain->hz; 17 | const double * restrict uz = fluid->uz.data; 18 | array_t * lzz_array = &fluid->lzz; 19 | double * restrict lzz = lzz_array->data; 20 | // compute lzz 21 | for(int k = 1; k <= ksize; k++){ 22 | for(int j = 1; j <= jsize; j++){ 23 | for(int i = 1; i <= isize; i++){ 24 | LZZ(i, j, k) = 1. / hz * ( 25 | - UZ(i , j , k ) 26 | + UZ(i , j , k+1) 27 | ); 28 | } 29 | } 30 | } 31 | static MPI_Datatype dtypes[NDIMS - 1] = { 32 | MPI_DOUBLE, 33 | MPI_DOUBLE, 34 | }; 35 | if(0 != halo_communicate_in_y(domain, dtypes + 0, lzz_array)){ 36 | return 1; 37 | } 38 | if(0 != halo_communicate_in_z(domain, dtypes + 1, lzz_array)){ 39 | return 1; 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /src/fluid/predict/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "runge_kutta.h" 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fluid_solver.h" 6 | #include "internal.h" 7 | 8 | static int reset_srcs( 9 | array_t * restrict srca, 10 | array_t * restrict srcb, 11 | array_t * restrict srcg 12 | ){ 13 | // stash previous RK source term, 14 | // which is achieved by swapping 15 | // the pointers to "data" 16 | double * tmp = srca->data; 17 | srca->data = srcb->data; 18 | srcb->data = tmp; 19 | // zero-clear current RK source terms (exp/imp) 20 | // NOTE: when 0 == rkstep, rkcoef for "beta" is zero 21 | // and thus zero-clearing"beta" buffers is not needed 22 | memset(srca->data, 0, srca->datasize); 23 | memset(srcg->data, 0, srcg->datasize); 24 | return 0; 25 | } 26 | 27 | /** 28 | * @brief update fields using the previously-computed RK source terms 29 | * @param[in] domain : information related to MPI domain decomposition 30 | * @param[in] rkstep : Runge-Kutta step 31 | * @param[in] dt : time step size 32 | * @param[in,out] fluid : RK source terms (in), flow field (out) 33 | * @return : error code 34 | */ 35 | int fluid_predict_field( 36 | const domain_t * domain, 37 | const size_t rkstep, 38 | const double dt, 39 | fluid_t * fluid 40 | ){ 41 | // reset buffers 42 | // copy previous k-step source term and reset 43 | if(0 != reset_srcs(fluid->srcux + rk_a, fluid->srcux + rk_b, fluid->srcux + rk_g)){ 44 | return 1; 45 | } 46 | if(0 != reset_srcs(fluid->srcuy + rk_a, fluid->srcuy + rk_b, fluid->srcuy + rk_g)){ 47 | return 1; 48 | } 49 | if(0 != reset_srcs(fluid->srcuz + rk_a, fluid->srcuz + rk_b, fluid->srcuz + rk_g)){ 50 | return 1; 51 | } 52 | if(0 != reset_srcs(fluid->srct + rk_a, fluid->srct + rk_b, fluid->srct + rk_g)){ 53 | return 1; 54 | } 55 | // pre-calculate velocity-gradient tensor components 56 | if(0 != compute_lxx(domain, fluid)){ 57 | return 1; 58 | } 59 | if(0 != compute_lxy(domain, fluid)){ 60 | return 1; 61 | } 62 | if(0 != compute_lxz(domain, fluid)){ 63 | return 1; 64 | } 65 | if(0 != compute_lyx(domain, fluid)){ 66 | return 1; 67 | } 68 | if(0 != compute_lyy(domain, fluid)){ 69 | return 1; 70 | } 71 | if(0 != compute_lyz(domain, fluid)){ 72 | return 1; 73 | } 74 | if(0 != compute_lzx(domain, fluid)){ 75 | return 1; 76 | } 77 | if(0 != compute_lzy(domain, fluid)){ 78 | return 1; 79 | } 80 | if(0 != compute_lzz(domain, fluid)){ 81 | return 1; 82 | } 83 | // update buffers 84 | if(0 != compute_rhs_ux(domain, fluid)){ 85 | return 1; 86 | } 87 | if(0 != compute_rhs_uy(domain, fluid)){ 88 | return 1; 89 | } 90 | if(0 != compute_rhs_uz(domain, fluid)){ 91 | return 1; 92 | } 93 | if(0 != compute_rhs_t(domain, fluid)){ 94 | return 1; 95 | } 96 | // update fleids using right-hand-side terms 97 | if(0 != update_ux(domain, rkstep, dt, fluid)){ 98 | return 1; 99 | } 100 | if(0 != update_uy(domain, rkstep, dt, fluid)){ 101 | return 1; 102 | } 103 | if(0 != update_uz(domain, rkstep, dt, fluid)){ 104 | return 1; 105 | } 106 | if(0 != update_t(domain, rkstep, dt, fluid)){ 107 | return 1; 108 | } 109 | return 0; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /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, "Re", 0, NULL, fileio.npy_double, sizeof(double), &fluid->Re); 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, "uz", fileio.npy_double, &fluid->uz); 25 | array.dump(domain, dirname, "p", fileio.npy_double, &fluid-> p); 26 | array.dump(domain, dirname, "t", fileio.npy_double, &fluid-> t); 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /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 | if(0 != fluid_predict_field(domain, rkstep, *dt, fluid)){ 22 | return 1; 23 | } 24 | if(0 != fluid_compute_potential(domain, rkstep, *dt, fluid)){ 25 | return 1; 26 | } 27 | if(0 != fluid_correct_velocity(domain, rkstep, *dt, fluid)){ 28 | return 1; 29 | } 30 | if(0 != fluid_update_pressure(domain, rkstep, *dt, fluid)){ 31 | return 1; 32 | } 33 | } 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/logging/divergence.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fileio.h" 6 | #include "array_macros/domain/hxxf.h" 7 | #include "array_macros/domain/hyxc.h" 8 | #include "array_macros/domain/jdxf.h" 9 | #include "array_macros/domain/jdxc.h" 10 | #include "array_macros/fluid/ux.h" 11 | #include "array_macros/fluid/uy.h" 12 | #include "array_macros/fluid/uz.h" 13 | #include "internal.h" 14 | 15 | #define BEGIN \ 16 | for(int cnt = 0, k = 1; k <= ksize; k++){ \ 17 | for(int j = 1; j <= jsize; j++){ \ 18 | for(int i = 1; i <= isize; i++, cnt++){ 19 | #define END \ 20 | } \ 21 | } \ 22 | } 23 | 24 | /** 25 | * @brief check divergence and write the maximum value 26 | * @param[in] fname : file name to which the log is written 27 | * @param[in] domain : domain information 28 | * @param[in] time : current simulation time 29 | * @param[in] fluid : velocity 30 | * @return : error code 31 | */ 32 | int logging_check_divergence( 33 | const char fname[], 34 | const domain_t * domain, 35 | const double time, 36 | const fluid_t * fluid 37 | ){ 38 | const int root = 0; 39 | int myrank = root; 40 | MPI_Comm comm_cart = MPI_COMM_NULL; 41 | sdecomp.get_comm_rank(domain->info, &myrank); 42 | sdecomp.get_comm_cart(domain->info, &comm_cart); 43 | const int isize = domain->mysizes[0]; 44 | const int jsize = domain->mysizes[1]; 45 | const int ksize = domain->mysizes[2]; 46 | const double * restrict hxxf = domain->hxxf; 47 | const double * restrict hyxc = domain->hyxc; 48 | const double hz = domain->hz; 49 | const double * restrict jdxf = domain->jdxf; 50 | const double * restrict jdxc = domain->jdxc; 51 | const double * restrict ux = fluid->ux.data; 52 | const double * restrict uy = fluid->uy.data; 53 | const double * restrict uz = fluid->uz.data; 54 | double divmax = 0.; 55 | // local divergence 56 | BEGIN 57 | const double hx_xm = HXXF(i ); 58 | const double hx_xp = HXXF(i+1); 59 | const double hy = HYXC(i ); 60 | const double jd_xm = JDXF(i ); 61 | const double jd_x0 = JDXC(i ); 62 | const double jd_xp = JDXF(i+1); 63 | const double ux_xm = UX(i , j , k ); 64 | const double ux_xp = UX(i+1, j , k ); 65 | const double uy_ym = UY(i , j , k ); 66 | const double uy_yp = UY(i , j+1, k ); 67 | const double uz_zm = UZ(i , j , k ); 68 | const double uz_zp = UZ(i , j , k+1); 69 | const double div = 1. / jd_x0 * ( 70 | - jd_xm / hx_xm * ux_xm + jd_xp / hx_xp * ux_xp 71 | - jd_x0 / hy * uy_ym + jd_x0 / hy * uy_yp 72 | - jd_x0 / hz * uz_zm + jd_x0 / hz * uz_zp 73 | ); 74 | // check maximum 75 | divmax = fmax(divmax, fabs(div)); 76 | END 77 | // collect information among all processes 78 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : &divmax; 79 | void * recvbuf = &divmax; 80 | MPI_Reduce(sendbuf, recvbuf, 1, MPI_DOUBLE, MPI_MAX, root, comm_cart); 81 | // result is written to a file from the main process 82 | if(root == myrank){ 83 | FILE * fp = fileio.fopen(fname, "a"); 84 | if(NULL == fp){ 85 | return 1; 86 | } 87 | fprintf(fp, "%8.2f % .1e\n", time, divmax); 88 | fileio.fclose(fp); 89 | } 90 | return 0; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /src/logging/injection.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fluid_solver.h" 6 | #include "fileio.h" 7 | #include "array_macros/domain/hxxf.h" 8 | #include "array_macros/domain/jdxf.h" 9 | #include "array_macros/fluid/uy.h" 10 | #include "array_macros/fluid/t.h" 11 | #include "array_macros/fluid/lyx0.h" 12 | #include "array_macros/fluid/lyx1.h" 13 | #include "array_macros/fluid/lxy.h" 14 | #include "internal.h" 15 | 16 | #define BEGIN \ 17 | for(int k = 1; k <= ksize; k++){ \ 18 | for(int j = 1; j <= jsize; j++){ 19 | #define END \ 20 | } \ 21 | } 22 | 23 | /** 24 | * @brief compute injected energy 25 | * @param[in] fname : file name to which the log is written 26 | * @param[in] domain : information related to MPI domain decomposition 27 | * @param[in] time : current simulation time 28 | * @param[in] fluid : velocity 29 | * @return : error code 30 | */ 31 | int logging_check_injection( 32 | const char fname[], 33 | const domain_t * domain, 34 | const double time, 35 | const fluid_t * fluid 36 | ){ 37 | const int root = 0; 38 | int myrank = root; 39 | MPI_Comm comm_cart = MPI_COMM_NULL; 40 | sdecomp.get_comm_rank(domain->info, &myrank); 41 | sdecomp.get_comm_cart(domain->info, &comm_cart); 42 | const int isize = domain->mysizes[0]; 43 | const int jsize = domain->mysizes[1]; 44 | const int ksize = domain->mysizes[2]; 45 | const double * restrict hxxf = domain->hxxf; 46 | const double * restrict jdxf = domain->jdxf; 47 | const double * restrict uy = fluid->uy.data; 48 | const double * restrict t = fluid->t.data; 49 | const double * restrict lyx0 = fluid->lyx0.data; 50 | const double * restrict lyx1 = fluid->lyx1.data; 51 | const double * restrict lxy = fluid->lxy.data; 52 | // kinetic energy (0) and squared scalar (1) 53 | double values[2] = {0., 0.}; 54 | // kinetic energy 55 | BEGIN 56 | const double hx_xm = HXXF( 1); 57 | const double hx_xp = HXXF(isize+1); 58 | const double jd_xm = JDXF( 1); 59 | const double jd_xp = JDXF(isize+1); 60 | const double lyx0_xm = LYX0( 1, j, k); 61 | const double lyx0_xp = LYX0(isize+1, j, k); 62 | const double lyx1_xm = LYX1( 1, j, k); 63 | const double lyx1_xp = LYX1(isize+1, j, k); 64 | const double lxy_xm = LXY( 1, j, k); 65 | const double lxy_xp = LXY(isize+1, j, k); 66 | const double uy_xm = UY( 0, j, k); 67 | const double uy_xp = UY(isize+1, j, k); 68 | const double tyx_xm = lyx0_xm + lyx1_xm + lxy_xm; 69 | const double tyx_xp = lyx0_xp + lyx1_xp + lxy_xp; 70 | values[0] += 71 | - jd_xm / hx_xm * uy_xm * tyx_xm 72 | + jd_xp / hx_xp * uy_xp * tyx_xp; 73 | END 74 | // squared scalar 75 | BEGIN 76 | const double hx_xm = HXXF( 1); 77 | const double hx_xp = HXXF(isize+1); 78 | const double jd_xm = JDXF( 1); 79 | const double jd_xp = JDXF(isize+1); 80 | const double t_xm = T( 0, j, k); 81 | const double t_xp = T(isize+1, j, k); 82 | const double dt_xm = - T( 0, j, k) + T( 1, j, k); 83 | const double dt_xp = - T(isize, j, k) + T(isize+1, j, k); 84 | values[1] += 85 | - jd_xm / hx_xm * t_xm / hx_xm * dt_xm 86 | + jd_xp / hx_xp * t_xp / hx_xp * dt_xp; 87 | END 88 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : values; 89 | void * recvbuf = values; 90 | MPI_Reduce(sendbuf, recvbuf, sizeof(values) / sizeof(values[0]), MPI_DOUBLE, MPI_SUM, root, comm_cart); 91 | if(root == myrank){ 92 | FILE * fp = fileio.fopen(fname, "a"); 93 | if(NULL == fp){ 94 | return 1; 95 | } 96 | fprintf(fp, "%8.2f ", time); 97 | fprintf(fp, "% 18.15e ", fluid_compute_momentum_diffusivity(fluid) * values[0]); 98 | fprintf(fp, "% 18.15e ", fluid_compute_scalar_diffusivity (fluid) * values[1]); 99 | fprintf(fp, "\n"); 100 | fileio.fclose(fp); 101 | } 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/logging/internal.h: -------------------------------------------------------------------------------- 1 | #if !defined(LOGGING_INTERNAL_H) 2 | #define LOGGING_INTERNAL_H 3 | 4 | extern int logging_check_divergence( 5 | const char fname[], 6 | const domain_t * domain, 7 | const double time, 8 | const fluid_t * fluid 9 | ); 10 | 11 | extern int logging_check_injection( 12 | const char fname[], 13 | const domain_t * domain, 14 | const double time, 15 | const fluid_t * fluid 16 | ); 17 | 18 | extern int logging_check_dissipation( 19 | const char fname[], 20 | const domain_t * domain, 21 | const double time, 22 | const fluid_t * fluid 23 | ); 24 | 25 | extern int logging_check_total_energy( 26 | const char fname[], 27 | const domain_t * domain, 28 | const double time, 29 | const fluid_t * fluid 30 | ); 31 | 32 | #endif // LOGGING_INTERNAL_H 33 | -------------------------------------------------------------------------------- /src/logging/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "memory.h" 5 | #include "config.h" 6 | #include "domain.h" 7 | #include "fluid.h" 8 | #include "fileio.h" 9 | #include "logging.h" 10 | #include "internal.h" 11 | 12 | static double g_rate = 0.; 13 | static double g_next = 0.; 14 | 15 | /** 16 | * @brief constructor - schedule logging 17 | * @param[in] domain : MPI communicator 18 | * @param[in] time : current time (hereafter in free-fall time units) 19 | */ 20 | static int init( 21 | const domain_t * domain, 22 | const double time 23 | ){ 24 | if(0 != config.get_double("log_rate", &g_rate)){ 25 | return 1; 26 | } 27 | g_next = g_rate * ceil( 28 | fmax(DBL_EPSILON, time) / g_rate 29 | ); 30 | const int root = 0; 31 | int myrank = root; 32 | sdecomp.get_comm_rank(domain->info, &myrank); 33 | if(root == myrank){ 34 | printf("LOGGING\n"); 35 | printf("\tnext: % .3e\n", g_next); 36 | printf("\trate: % .3e\n", g_rate); 37 | fflush(stdout); 38 | } 39 | return 0; 40 | } 41 | 42 | /** 43 | * @brief show current step, time, time step size, diffusive treatments 44 | * @param[in] domain : information related to MPI domain decomposition 45 | * @param[in] fname : file name to which the log is written 46 | * @param[in] time : current simulation time 47 | * @param[in] step : current time step 48 | * @param[in] dt : time step size 49 | * @param[in] wtime : current wall time 50 | */ 51 | static void show_progress( 52 | const char fname[], 53 | const domain_t * domain, 54 | const double time, 55 | const size_t step, 56 | const double dt, 57 | const double wtime 58 | ){ 59 | const int root = 0; 60 | int myrank = root; 61 | sdecomp.get_comm_rank(domain->info, &myrank); 62 | if(root == myrank){ 63 | FILE * fp = fileio.fopen(fname, "a"); 64 | if(NULL != fp){ 65 | // show progress to standard output and file 66 | // output to stdout and file 67 | #define MPRINT(...) { \ 68 | fprintf(fp, __VA_ARGS__); \ 69 | fprintf(stdout, __VA_ARGS__); \ 70 | } 71 | MPRINT("step %zu, time %.1f, dt %.2e, elapsed %.1f [sec]\n", step, time, dt, wtime); 72 | #undef MPRINT 73 | fileio.fclose(fp); 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * @brief output log files to be monitored during simulation 80 | * @param[in] domain : information related to MPI domain decomposition 81 | * @param[in] step : current time step 82 | * @param[in] time : current simulation time 83 | * @param[in] dt : time step size 84 | * @param[in] wtime : current wall time 85 | * @param[in] fluid : velocity 86 | */ 87 | static void check_and_output( 88 | const domain_t * domain, 89 | const size_t step, 90 | const double time, 91 | const double dt, 92 | const double wtime, 93 | const fluid_t * fluid 94 | ){ 95 | show_progress ("output/log/progress.dat", domain, time, step, dt, wtime); 96 | logging_check_divergence ("output/log/divergence.dat", domain, time, fluid); 97 | logging_check_injection ("output/log/injection.dat", domain, time, fluid); 98 | logging_check_dissipation ("output/log/dissipation.dat", domain, time, fluid); 99 | logging_check_total_energy("output/log/total_energy.dat", domain, time, fluid); 100 | g_next += g_rate; 101 | } 102 | 103 | /** 104 | * @brief getter of a member: g_next 105 | * @return : g_next 106 | */ 107 | static double get_next_time( 108 | void 109 | ){ 110 | return g_next; 111 | } 112 | 113 | const logging_t logging = { 114 | .init = init, 115 | .check_and_output = check_and_output, 116 | .get_next_time = get_next_time, 117 | }; 118 | 119 | -------------------------------------------------------------------------------- /src/logging/total_energy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "domain.h" 4 | #include "fluid.h" 5 | #include "fileio.h" 6 | #include "array_macros/domain/jdxf.h" 7 | #include "array_macros/domain/jdxc.h" 8 | #include "array_macros/fluid/ux.h" 9 | #include "array_macros/fluid/uy.h" 10 | #include "array_macros/fluid/uz.h" 11 | #include "array_macros/fluid/t.h" 12 | #include "internal.h" 13 | 14 | /** 15 | * @brief compute total quadratic quantities 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 : velocity 20 | * @return : error code 21 | */ 22 | int logging_check_total_energy( 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 int ksize = domain->mysizes[2]; 36 | const double * restrict jdxf = domain->jdxf; 37 | const double * restrict jdxc = domain->jdxc; 38 | const double * restrict ux = fluid->ux.data; 39 | const double * restrict uy = fluid->uy.data; 40 | const double * restrict uz = fluid->uz.data; 41 | const double * restrict t = fluid->t.data; 42 | // velocity for each dimension and scalar 43 | double quantities[NDIMS + 1] = {0.}; 44 | // compute quadratic quantity in x direction 45 | for (int k = 1; k <= ksize; k++) { 46 | for (int j = 1; j <= jsize; j++) { 47 | for (int i = 2; i <= isize; i++) { 48 | quantities[0] += JDXF(i ) * 0.5 * pow(UX(i, j, k), 2.); 49 | } 50 | } 51 | } 52 | // compute quadratic quantity in y direction 53 | for (int k = 1; k <= ksize; k++) { 54 | for (int j = 1; j <= jsize; j++) { 55 | for (int i = 1; i <= isize; i++) { 56 | quantities[1] += JDXC(i ) * 0.5 * pow(UY(i, j, k), 2.); 57 | } 58 | } 59 | } 60 | // compute quadratic quantity in z direction 61 | for (int k = 1; k <= ksize; k++) { 62 | for (int j = 1; j <= jsize; j++) { 63 | for (int i = 1; i <= isize; i++) { 64 | quantities[2] += JDXC(i ) * 0.5 * pow(UZ(i, j, k), 2.); 65 | } 66 | } 67 | } 68 | // compute quadratic quantity of scalar 69 | for (int k = 1; k <= ksize; k++) { 70 | for (int j = 1; j <= jsize; j++) { 71 | for (int i = 1; i <= isize; i++) { 72 | quantities[NDIMS] += JDXC(i ) * 0.5 * pow(T(i, j, k), 2.); 73 | } 74 | } 75 | } 76 | // output information 77 | const size_t nitems = sizeof(quantities) / sizeof(quantities[0]); 78 | const void * sendbuf = root == myrank ? MPI_IN_PLACE : quantities; 79 | void * recvbuf = quantities; 80 | MPI_Reduce(sendbuf, recvbuf, nitems, MPI_DOUBLE, MPI_SUM, root, comm_cart); 81 | if (root == myrank) { 82 | FILE * fp = fileio.fopen(fname, "a"); 83 | if (NULL == fp) { 84 | return 1; 85 | } 86 | fprintf(fp, "%8.2f ", time); 87 | for (size_t n = 0; n < nitems; n++) { 88 | fprintf(fp, "% 18.15e%c", quantities[n], nitems - 1 == n ? '\n' : ' '); 89 | } 90 | fileio.fclose(fp); 91 | } 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "sdecomp.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 = 1.; 4 | const double param_uy_xp = 0.; 5 | 6 | const double param_t_xm = + 0.5; 7 | const double param_t_xp = - 0.5; 8 | 9 | -------------------------------------------------------------------------------- /src/param/implicit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "param.h" 3 | 4 | const bool param_implicit_x = true; 5 | const bool param_implicit_y = false; 6 | const bool param_implicit_z = false; 7 | 8 | -------------------------------------------------------------------------------- /src/runge_kutta.c: -------------------------------------------------------------------------------- 1 | #include "runge_kutta.h" 2 | 3 | const uint_fast8_t rk_a = 0; 4 | const uint_fast8_t rk_b = 1; 5 | const uint_fast8_t rk_g = 2; 6 | 7 | // coefficients of three-stage Runge-Kutta scheme 8 | static const double a0 = +32. / 60., b0 = 0. / 60.; 9 | static const double a1 = +25. / 60., b1 = -17. / 60.; 10 | static const double a2 = +45. / 60., b2 = -25. / 60.; 11 | const rkcoef_t rkcoefs[RKSTEPMAX] = { 12 | {a0, b0, a0 + b0}, 13 | {a1, b1, a1 + b1}, 14 | {a2, b2, a2 + b2}, 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /src/save.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "sdecomp.h" 6 | #include "param.h" 7 | #include "memory.h" 8 | #include "domain.h" 9 | #include "fluid_solver.h" 10 | #include "save.h" 11 | #include "fileio.h" 12 | #include "config.h" 13 | 14 | // parameters to specify directory name 15 | static const char g_dirname_prefix[] = {"output/save/step"}; 16 | static const int g_dirname_ndigits = 10; 17 | 18 | // name of directory 19 | static char * g_dirname = NULL; 20 | static size_t g_dirname_nchars = 0; 21 | 22 | // scheduler 23 | static double g_rate = 0.; 24 | static double g_next = 0.; 25 | 26 | /** 27 | * @brief constructor - schedule saving flow fields 28 | * @param[in] domain : MPI communicator 29 | * @param[in] time : current time (hereafter in free-fall time units) 30 | */ 31 | static int init( 32 | const domain_t * domain, 33 | const double time 34 | ){ 35 | // fetch timings 36 | if(0 != config.get_double("save_rate", &g_rate)){ 37 | return 1; 38 | } 39 | double after = 0.; 40 | if(0 != config.get_double("save_after", &after)){ 41 | return 1; 42 | } 43 | // schedule next event 44 | g_next = g_rate * ceil( 45 | fmax(DBL_EPSILON, fmax(time, after)) / g_rate 46 | ); 47 | // allocate directory name 48 | g_dirname_nchars = 49 | + strlen(g_dirname_prefix) 50 | + g_dirname_ndigits; 51 | g_dirname = memory_calloc(g_dirname_nchars + 2, sizeof(char)); 52 | // report 53 | const int root = 0; 54 | int myrank = root; 55 | sdecomp.get_comm_rank(domain->info, &myrank); 56 | if(root == myrank){ 57 | FILE * stream = stdout; 58 | fprintf(stream, "SAVE\n"); 59 | fprintf(stream, "\tdest: %s\n", g_dirname_prefix); 60 | fprintf(stream, "\tnext: % .3e\n", g_next); 61 | fprintf(stream, "\trate: % .3e\n", g_rate); 62 | fflush(stream); 63 | } 64 | return 0; 65 | } 66 | 67 | /** 68 | * @brief output an instantaneous flow field 69 | * @param[in] domain : information related to MPI domain decomposition 70 | * @param[in] step : time step 71 | * @param[in] time : current simulation time 72 | * @param[in] fluid : flow field 73 | */ 74 | static int output ( 75 | const domain_t * domain, 76 | const size_t step, 77 | const double time, 78 | const fluid_t * fluid 79 | ){ 80 | // set directory name 81 | snprintf( 82 | g_dirname, 83 | g_dirname_nchars + 1, 84 | "%s%0*zu", 85 | g_dirname_prefix, 86 | g_dirname_ndigits, 87 | step 88 | ); 89 | // get communicator to identify the main process 90 | const int root = 0; 91 | int myrank = root; 92 | sdecomp.get_comm_rank(domain->info, &myrank); 93 | // create directory 94 | if(root == myrank){ 95 | // although it may fail, anyway continue, which is designed to be safe 96 | fileio.mkdir(g_dirname); 97 | } 98 | // wait for the main process to complete making directory 99 | MPI_Barrier(MPI_COMM_WORLD); 100 | // save quantities 101 | if(root == myrank){ 102 | fileio.w_serial(g_dirname, "step", 0, NULL, fileio.npy_size_t, sizeof(size_t), &step); 103 | fileio.w_serial(g_dirname, "time", 0, NULL, fileio.npy_double, sizeof(double), &time); 104 | } 105 | domain_save(g_dirname, domain); 106 | fluid_save(g_dirname, domain, fluid); 107 | // schedule next saving event 108 | g_next += g_rate; 109 | return 0; 110 | } 111 | 112 | /** 113 | * @brief getter of a member: g_next 114 | * @return : g_next 115 | */ 116 | static double get_next_time( 117 | void 118 | ){ 119 | return g_next; 120 | } 121 | 122 | const save_t save = { 123 | .init = init, 124 | .output = output, 125 | .get_next_time = get_next_time, 126 | }; 127 | 128 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------