diff --git a/.appveyor.yml b/.appveyor.yml index 11a0635..f091cc5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,6 +9,7 @@ platform: x64 environment: PYTHON: C:\Python35-x64 PATH: C:\Program Files\Project\bin;C:\Program Files\Microsoft MPI\Bin;%PATH% + AITHER_FLUID_DATABASE: C:\Program Files\Project\fluidDatabase build_script: - ps: >- powershell ci\appveyor\installMPI.ps1 @@ -18,4 +19,4 @@ test_script: - cmd: >- cd testCases - %PYTHON%\python.exe regressionTests.py --mpirunPath=mpiexec.exe --aitherPath=aither.exe \ No newline at end of file + %PYTHON%\python.exe regressionTests.py --mpirunPath=mpiexec.exe --aitherPath=aither.exe --operatingSystem=windows \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..5f019ac --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,11 @@ +## Issue Type (bug, feature request, other) + + +## Description of Issue + + +## Steps to Reproduce Issue + + +## System Details (OS, compiler, number of processors, etc) + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f2eef47 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +## Fixes Issue # + + +## Description of Changes + + +## Suggested Reviewers +@mnucci32 diff --git a/.travis.yml b/.travis.yml index 142c6af..77e4540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ matrix: - CXX_COMPILER=g++-5 - C_COMPILER=gcc-5 - BUILD_TYPE=release + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase - os: linux dist: trusty sudo: required @@ -41,6 +42,22 @@ matrix: - CXX_COMPILER=g++-6 - C_COMPILER=gcc-6 - BUILD_TYPE=debug + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase + - os: linux + dist: trusty + sudo: required + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 gcc-7 libstdc++-7-dev + env: + - CXX_COMPILER=g++-7 + - C_COMPILER=gcc-7 + - BUILD_TYPE=release + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase - os: linux dist: trusty sudo: required @@ -56,6 +73,7 @@ matrix: - CXX_COMPILER=clang++-3.8 - C_COMPILER=clang-3.8 - BUILD_TYPE=release + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase - os: osx osx_image: xcode8 compiler: gcc @@ -65,6 +83,7 @@ matrix: - HOMEBREW_CC=gcc-7 - HOMEBREW_CXX=g++-7 - BUILD_TYPE=release + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase - os: osx osx_image: xcode8 compiler: clang @@ -74,6 +93,7 @@ matrix: - HOMEBREW_CC=clang - HOMEBREW_CXX=clang++ - BUILD_TYPE=release + - AITHER_FLUID_DATABASE=$TRAVIS_BUILD_DIR/build/install/fluidDatabase # upgrade packages before_install: @@ -100,10 +120,10 @@ before_script: # build instructions script: - cmake -G "Unix Makefiles" -DCMAKE_CXX_COMPILER=$CXX_COMPILER -DCMAKE_C_COMPILER=$C_COMPILER -DMPI_DIR=$TRAVIS_BUILD_DIR/openmpi -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=install .. - - make -j2 + - make -j 4 - make install - cd ../testCases - - python3 regressionTests.py --aitherPath=$TRAVIS_BUILD_DIR/build/install/bin/aither --operatingSystem=$TRAVIS_OS_NAME --mpirunPath=$TRAVIS_BUILD_DIR/openmpi/bin/mpirun + - python3 regressionTests.py --aitherPath=$TRAVIS_BUILD_DIR/build/install/bin/aither --operatingSystem=$TRAVIS_OS_NAME --mpirunPath=$TRAVIS_BUILD_DIR/openmpi/bin/mpirun --build $BUILD_TYPE - cd $TRAVIS_BUILD_DIR/build after_success: diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..61814c7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at michael.nucci@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..910a713 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# How to Contribute +Thank you for contributing to aither! Check out the aither [blog](http://aithercfd.com) for more information. Aither +uses the git flow branching method. The **master** branch is a permanent branch containing stable code with releases +coming off of this branch. The default branch is the **develop** branch. This is a permanent branch containing the most +up-to-date code and is therefore not guaranteed to be working. Bug fixes and feature additions branch off of **develop** and +are merged back in when complete. Aither uses continuous integration services [TravisCI](https://travis-ci.org/mnucci32/aither) +and [Appveyor](https://ci.appveyor.com/project/mnucci32/aither/branch/develop) to test builds on Linux, macOS, and +Windows. The code is built on each platform and a suite of tests are run to ensure that the residuals have not +changed due to a commit. There are a few ways to get involved with this project including reporting or fixing a bug, +requesting or adding a feature, and adding documentation. + +### Reporting a Bug +Bugs should be reported via [Github Issues](https://github.com/mnucci32/aither/issues). + +### Fixing a Bug +A list of known bugs can be found on the [Issues](https://github.com/mnucci32/aither/issues) page. A fix can be submitted +by creating a new branch off of the **develop** branch with a descriptive name starting with **hotfix_**. When the bug has +been fixed and and all continuous integration tests are passing, a pull request can be submitted to merge the fix back into +**develop**. + +### Requesting a Feature +New features should be requested via [Github Issues](https://github.com/mnucci32/aither/issues). Not all requests will be +accepted. + +### Adding a Feature +A list of features to be added can be found on the [Issues](https://github.com/mnucci32/aither/issues) page. If you want +to add a feature not listed, first submit an issue requesting that it be added. New features should be implemented by +creating a branch off of **develop** with a descriptive name starting with **feature_**. When the feature has been fixed +and all continuous integreation tests are passing, a pull request can be submitted to merge the feature back into **develop**. +If it is a fairly significant addition, an additional test case should be added as well. + +### Adding Documentation +Documentation can be added by editing the [Wiki](https://github.com/mnucci32/aither/wiki) page. + +# Coding Style +* Aither conforms to the [Google Style Guide](https://google.github.io/styleguide/cppguide.html) +* Variable names should use camelCase starting with a lower case letter +* Function names should use CamelCase starting with an upper case letter +* Class member variables should be appended with a _ +* Modern C++ features should be used when possible diff --git a/Makefile b/Makefile deleted file mode 100644 index ac8bf0d..0000000 --- a/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -OBJS = main.o plot3d.o input.o boundaryConditions.o eos.o primVars.o procBlock.o output.o matrix.o parallel.o slices.o turbulence.o inviscidFlux.o viscousFlux.o source.o resid.o kdtree.o genArray.o fluxJacobian.o uncoupledScalar.o utility.o -CC = mpic++ -DEBUG = -O0 -ggdb -pg -OPTIM = -O3 -march=native -PROF = -O3 -march=native -pg -CODENAME = aither -CFLAGS = -std=c++14 -Wall -pedantic -c $(OPTIM) -LFLAGS = -std=c++14 -Wall -pedantic $(OPTIM) -o $(CODENAME) - -$(CODENAME) : $(OBJS) - $(CC) $(LFLAGS) $(OBJS) - -plot3d.o : plot3d.cpp plot3d.hpp vector3d.hpp multiArray3d.hpp - $(CC) $(CFLAGS) plot3d.cpp - -main.o : main.cpp plot3d.hpp vector3d.hpp input.hpp procBlock.hpp eos.hpp primVars.hpp boundaryConditions.hpp inviscidFlux.hpp tensor.hpp viscousFlux.hpp output.hpp parallel.hpp turbulence.hpp resid.hpp multiArray3d.hpp genArray.hpp fluxJacobian.hpp utility.hpp - $(CC) $(CFLAGS) main.cpp - -input.o : input.cpp input.hpp boundaryConditions.hpp - $(CC) $(CFLAGS) input.cpp - -primVars.o : primVars.cpp primVars.hpp vector3d.hpp eos.hpp inviscidFlux.hpp boundaryConditions.hpp input.hpp macros.hpp genArray.hpp - $(CC) $(CFLAGS) primVars.cpp - -procBlock.o : procBlock.cpp procBlock.hpp vector3d.hpp plot3d.hpp eos.hpp primVars.hpp inviscidFlux.hpp input.hpp genArray.hpp viscousFlux.hpp boundaryConditions.hpp macros.hpp turbulence.hpp kdtree.hpp uncoupledScalar.hpp fluxJacobian.hpp matrix.hpp utility.hpp - $(CC) $(CFLAGS) procBlock.cpp - -inviscidFlux.o : inviscidFlux.cpp vector3d.hpp eos.hpp primVars.hpp inviscidFlux.hpp input.hpp macros.hpp genArray.hpp turbulence.hpp matrix.hpp - $(CC) $(CFLAGS) inviscidFlux.cpp - -boundaryConditions.o : boundaryConditions.cpp boundaryConditions.hpp plot3d.hpp vector3d.hpp - $(CC) $(CFLAGS) boundaryConditions.cpp - -eos.o : eos.cpp eos.hpp vector3d.hpp - $(CC) $(CFLAGS) eos.cpp - -slices.o : slices.cpp slices.hpp procBlock.hpp - $(CC) $(CFLAGS) slices.cpp - -viscousFlux.o : viscousFlux.cpp vector3d.hpp tensor.hpp eos.hpp primVars.hpp viscousFlux.hpp input.hpp turbulence.hpp macros.hpp - $(CC) $(CFLAGS) viscousFlux.cpp - -output.o : output.cpp output.hpp procBlock.hpp tensor.hpp vector3d.hpp plot3d.hpp eos.hpp primVars.hpp inviscidFlux.hpp input.hpp turbulence.hpp genArray.hpp - $(CC) $(CFLAGS) output.cpp - -parallel.o : parallel.cpp parallel.hpp primVars.hpp procBlock.hpp vector3d.hpp plot3d.hpp boundaryConditions.hpp resid.hpp - $(CC) $(CFLAGS) parallel.cpp - -matrix.o : matrix.cpp matrix.hpp macros.hpp genArray.hpp - $(CC) $(CFLAGS) matrix.cpp - -genArray.o : genArray.cpp genArray.hpp macros.hpp - $(CC) $(CFLAGS) genArray.cpp - -turbulence.o : turbulence.cpp turbulence.hpp matrix.hpp vector3d.hpp tensor.hpp primVars.hpp eos.hpp - $(CC) $(CFLAGS) turbulence.cpp - -source.o : source.cpp source.hpp macros.hpp turbulence.hpp primVars.hpp matrix.hpp - $(CC) $(CFLAGS) source.cpp - -resid.o : resid.cpp resid.hpp - $(CC) $(CFLAGS) resid.cpp - -kdtree.o : kdtree.cpp kdtree.hpp vector3d.hpp - $(CC) $(CFLAGS) kdtree.cpp - -fluxJacobian.o : fluxJacobian.cpp fluxJacobian.hpp turbulence.hpp vector3d.hpp primVars.hpp eos.hpp input.hpp genArray.hpp matrix.hpp inviscidFlux.hpp uncoupledScalar.hpp tensor.hpp utility.hpp - $(CC) $(CFLAGS) fluxJacobian.cpp - -uncoupledScalar.o : uncoupledScalar.cpp uncoupledScalar.hpp genArray.hpp - $(CC) $(CFLAGS) uncoupledScalar.cpp - -utility.o : utility.cpp utility.hpp genArray.hpp vector3d.hpp multiArray3d.hpp procBlock.hpp eos.hpp input.hpp turbulence.hpp slices.hpp fluxJacobian.hpp kdtree.hpp resid.hpp - $(CC) $(CFLAGS) utility.cpp - -clean: - rm *.o *~ $(CODENAME) diff --git a/README.md b/README.md index e23163e..8093bca 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ | Master | [![Build Status](https://travis-ci.org/mnucci32/aither.svg?branch=master)](https://travis-ci.org/mnucci32/aither) | [![Build status](https://ci.appveyor.com/api/projects/status/o7fc231lp9jxlsib/branch/master?svg=true)](https://ci.appveyor.com/project/mnucci32/aither/branch/master) | [![Coverage Status](https://codecov.io/github/mnucci32/aither/coverage.svg?branch=master)](https://codecov.io/github/mnucci32/aither?branch=master) | | Develop | [![Build Status](https://travis-ci.org/mnucci32/aither.svg?branch=develop)](https://travis-ci.org/mnucci32/aither) | [![Build status](https://ci.appveyor.com/api/projects/status/o7fc231lp9jxlsib/branch/develop?svg=true)](https://ci.appveyor.com/project/mnucci32/aither/branch/develop) | [![Coverage Status](https://codecov.io/github/mnucci32/aither/coverage.svg?branch=develop)](https://codecov.io/github/mnucci32/aither?branch=develop) | -### About The code +### About The Code This code is for a 3D Navier-Stokes computational fluid dynamics solver. It is a cell centered, structured solver, using multi-block structured grids in Plot3D format. It uses explicit and implicit time integration methods. It uses MUSCL -extrapolation to reconstruct the primative variables from the cell centers to +extrapolation to reconstruct the primitive variables from the cell centers to the cell faces for 2nd order accuracy. Higher order reconstruction is acheived with a 5th order WENO reconstruction for the inviscid fluxes, and a 4th order central reconstruction for the viscous fluxes. The code uses the Roe @@ -28,31 +28,39 @@ are the implicit euler (1st order), Crank-Nicholson (2nd order), and BDF2 parallel using MPI. For RANS simulations the Wilcox K-Omega 2006 and SST 2003 turbulence models are available. Wall functions are supported for both models. For detatched eddy simulations, the SST-DES turbulence model is available. For -large eddy simulations, the WALE subgrid scale model is available. +large eddy simulations, the WALE subgrid scale model is available. A +Multi-species flow capability is in progress. Supported diffusion models will be +Schmidt number based diffusion. ### To Do List -* Add non-reflecting boundary conditions * Add multigrid scheme for improved convergence -* Add multi-species flow capability +* Add reacting flow capability +* Performance improvements ### Dependencies * MPI - OpenMPI, MPICH, & MS-MPI have been used * C++ compiler with C++14 support * Cmake - Cmake only depends on a C++ compiler -### How To compile +### How To Compile And Install Aither is compiled and installed with the standard cmake process. ```bash cmake -DCMAKE_INSTALL_PREFIX=/path/to/installation -DCMAKE_BUILD_TYPE=release /path/to/source make make install + +export AITHER_FLUID_DATABASE=/path/to/installation/fluidDatabase ``` Cmake will automatically look for an MPI package. To specify a specific -installation, set *-DMPI_DIR* to the MPI installation directory. In addition -to *release*, other supported build types are *debug*, *profile*, -*relwithdebinfo*, and *minsizerel*. +installation, set **-DMPI_DIR** to the MPI installation directory. In addition +to **release**, other supported build types are **debug**, **profile**, +**relwithdebinfo**, and **minsizerel**. + +The **AITHER_FLUID_DATABASE** environment variable should be set to the +**fluidDatabase** folder inside of the installation directory. This tells aither +where to look for fluid properties. ### How To Run ```bash diff --git a/ci/appveyor/buildAither.ps1 b/ci/appveyor/buildAither.ps1 index e221507..1da5ca5 100644 --- a/ci/appveyor/buildAither.ps1 +++ b/ci/appveyor/buildAither.ps1 @@ -4,7 +4,7 @@ function BuildAither() { md build cd build cmake -G "Visual Studio 14 2015 Win64" -DMPI_DIR="C:\Program Files (x86)\Microsoft SDKs\MPI" .. - cmake --build . --target INSTALL --config Release + cmake --build . --target INSTALL --config release cd .. } diff --git a/ci/appveyor/installMPI.ps1 b/ci/appveyor/installMPI.ps1 index d2046db..5dfc293 100644 --- a/ci/appveyor/installMPI.ps1 +++ b/ci/appveyor/installMPI.ps1 @@ -9,11 +9,24 @@ function InstallMPI() { Write-Host "Installing Microsoft MPI Runtime..." appveyor DownloadFile http://download.microsoft.com/download/B/2/E/B2EB83FE-98C2-4156-834A-E1711E6884FB/MSMpiSetup.exe Start-Process -FilePath MSMpiSetup.exe -ArgumentList -unattend -Wait + Write-Host "Microsoft MPI Runtime installation complete..." cd .. } +function InstallCmake() { + Write-Host "Installing CMake 3.4.0 ..." -ForegroundColor Cyan + $exePath = "$($env:USERPROFILE)\cmake-3.4.0-rc2-win32-x86.exe" + Write-Host "Downloading..." + (New-Object Net.WebClient).DownloadFile('https://cmake.org/files/v3.4/cmake-3.4.0-rc2-win32-x86.exe', $exePath) + Write-Host "Installing..." + cmd /c start /wait $exePath /S + cmake --version + Write-Host "CMake 3.4.0 installed" -ForegroundColor Green +} + function main() { InstallMPI + InstallCmake } main \ No newline at end of file diff --git a/fluidDatabase/Ar.dat b/fluidDatabase/Ar.dat new file mode 100644 index 0000000..a3f1412 --- /dev/null +++ b/fluidDatabase/Ar.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 1.5 +molarMass: 39.948 +vibrationalTemperature: [] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 2.0343E-06 +sutherlandViscosityS: 1.6053E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 1.5877E-03 +sutherlandConductivityS: 1.6053E+02 \ No newline at end of file diff --git a/fluidDatabase/CH4.dat b/fluidDatabase/CH4.dat new file mode 100644 index 0000000..623df33 --- /dev/null +++ b/fluidDatabase/CH4.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 3.0 +molarMass: 16.0425 +vibrationalTemperature: [4196.38, 2207.18, 2207.18, 4343.43, 4343.43, 4343.43, 1879.13, 1879.13, 1879.13] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.0166E-06 +sutherlandViscosityS: 1.6471E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 1.7680E-02 +sutherlandConductivityS: 2.3083E+03 \ No newline at end of file diff --git a/fluidDatabase/CO.dat b/fluidDatabase/CO.dat new file mode 100644 index 0000000..7ef4cfa --- /dev/null +++ b/fluidDatabase/CO.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 28.0101 +vibrationalTemperature: [3121.5] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.4500E-06 +sutherlandViscosityS: 1.2882E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 2.6880E-03 +sutherlandConductivityS: 2.7617E+02 \ No newline at end of file diff --git a/fluidDatabase/CO2.dat b/fluidDatabase/CO2.dat new file mode 100644 index 0000000..3ed321a --- /dev/null +++ b/fluidDatabase/CO2.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 44.0095 +vibrationalTemperature: [960.1, 960.1, 1932.1, 3380.1] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.6491E-06 +sutherlandViscosityS: 2.6968E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 4.1247E-03 +sutherlandConductivityS: 8.8020E+02 \ No newline at end of file diff --git a/fluidDatabase/H.dat b/fluidDatabase/H.dat new file mode 100644 index 0000000..67e72c5 --- /dev/null +++ b/fluidDatabase/H.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 1.5 +molarMass: 1.00794 +vibrationalTemperature: [] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 8.4958E-07 +sutherlandViscosityS: 1.6775E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 2.6278E-02 +sutherlandConductivityS: 1.6775E+02 \ No newline at end of file diff --git a/fluidDatabase/H2.dat b/fluidDatabase/H2.dat new file mode 100644 index 0000000..b7152a7 --- /dev/null +++ b/fluidDatabase/H2.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 2.01588 +vibrationalTemperature: [6338.3] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 6.8021E-07 +sutherlandViscosityS: 1.0031E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 1.5056E-02 +sutherlandConductivityS: 1.3207E+02 \ No newline at end of file diff --git a/fluidDatabase/H2O.dat b/fluidDatabase/H2O.dat new file mode 100644 index 0000000..00d09a2 --- /dev/null +++ b/fluidDatabase/H2O.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 3.0 +molarMass: 18.0153 +vibrationalTemperature: [2294.3, 5261.7, 5403.8] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.9293E-06 +sutherlandViscosityS: 7.0274E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 1.1200E-02 +sutherlandConductivityS: 2.0728E+03 \ No newline at end of file diff --git a/fluidDatabase/He.dat b/fluidDatabase/He.dat new file mode 100644 index 0000000..2515fde --- /dev/null +++ b/fluidDatabase/He.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 1.5 +molarMass: 4.002602 +vibrationalTemperature: [] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.4872E-06 +sutherlandViscosityS: 9.7629E+01 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 1.1584E-02 +sutherlandConductivityS: 9.7629E+01 \ No newline at end of file diff --git a/fluidDatabase/N.dat b/fluidDatabase/N.dat new file mode 100644 index 0000000..3ea3374 --- /dev/null +++ b/fluidDatabase/N.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 1.5 +molarMass: 14.0067 +vibrationalTemperature: [] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.2953E-06 +sutherlandViscosityS: 1.1190E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 2.8831E-03 +sutherlandConductivityS: 1.1190E+02 \ No newline at end of file diff --git a/fluidDatabase/N2.dat b/fluidDatabase/N2.dat new file mode 100644 index 0000000..bd40d1c --- /dev/null +++ b/fluidDatabase/N2.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 28.0134 +vibrationalTemperature: [3392] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.4742E-06 +sutherlandViscosityS: 1.2846E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 2.6834E-03 +sutherlandConductivityS: 2.5615E+02 \ No newline at end of file diff --git a/fluidDatabase/NO.dat b/fluidDatabase/NO.dat new file mode 100644 index 0000000..86c3022 --- /dev/null +++ b/fluidDatabase/NO.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 30.0061 +vibrationalTemperature: [2739] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.5257E-06 +sutherlandViscosityS: 1.2846E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 2.7255E-03 +sutherlandConductivityS: 2.7027E+02 \ No newline at end of file diff --git a/fluidDatabase/O.dat b/fluidDatabase/O.dat new file mode 100644 index 0000000..cfacf50 --- /dev/null +++ b/fluidDatabase/O.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 1.5 +molarMass: 15.9994 +vibrationalTemperature: [] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.9664E-06 +sutherlandViscosityS: 1.1649E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 3.8319E-03 +sutherlandConductivityS: 1.1649E+02 \ No newline at end of file diff --git a/fluidDatabase/O2.dat b/fluidDatabase/O2.dat new file mode 100644 index 0000000..46a789d --- /dev/null +++ b/fluidDatabase/O2.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 31.9988 +vibrationalTemperature: [2273] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 1.7146E-06 +sutherlandViscosityS: 1.3610E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 3.0048E-03 +sutherlandConductivityS: 3.0610E+02 \ No newline at end of file diff --git a/fluidDatabase/OH.dat b/fluidDatabase/OH.dat new file mode 100644 index 0000000..0560df1 --- /dev/null +++ b/fluidDatabase/OH.dat @@ -0,0 +1,17 @@ +# general fluid properties +n: 2.5 +molarMass: 17.0073 +vibrationalTemperature: [5374.2] + +# Sutherland's coefficients for transport properties +# ----- viscosity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandViscosityC1: 2.0274E-06 +sutherlandViscosityS: 1.1649E+02 + +# ----- thermal conductivity ----- +# values obtained from least squares curve fit of data +# from [250.0 K - 1000.0 K] +sutherlandConductivityC1: 4.8939E-03 +sutherlandConductivityS: 1.4471E+02 \ No newline at end of file diff --git a/fluidDatabase/air.dat b/fluidDatabase/air.dat new file mode 100644 index 0000000..e3cd205 --- /dev/null +++ b/fluidDatabase/air.dat @@ -0,0 +1,12 @@ +# general fluid properties +n: 2.5 +molarMass: 28.97 +vibrationalTemperature: [3056.0] + +# transport properties -- viscosity +sutherlandViscosityC1: 1.458e-6 +sutherlandViscosityS: 110.4 + +# transport properties -- thermal conductivity +sutherlandConductivityC1: 2.495e-3 +sutherlandConductivityS: 194.0 \ No newline at end of file diff --git a/include/arrayView.hpp b/include/arrayView.hpp new file mode 100644 index 0000000..b47bf3d --- /dev/null +++ b/include/arrayView.hpp @@ -0,0 +1,451 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef ARRAYVIEWHEADERDEF +#define ARRAYVIEWHEADERDEF + +#include +#include +#include +#include +#include +#include +#include +#include +#include "macros.hpp" +#include "varArray.hpp" +#include "vector3d.hpp" +#include "physicsModels.hpp" +#include "conserved.hpp" + +using std::ostream; +using std::vector; +using std::endl; +using std::unique_ptr; + +/* class to store a view of an array. This is useful to slice out data from a + * std::vector. + */ + +// forward class declarations +class primitive; +class residual; + +template +class arrayView { + static_assert(std::is_base_of::value, + "arrayView requires T1 to be varArray type!"); + static_assert(std::is_arithmetic::value, + "arrayView requires T2 to be an arithmetic type!"); + + typename vector::const_iterator begin_; + typename vector::const_iterator end_; + int momentumIndex_; + int energyIndex_; + int turbulenceIndex_; + + public: + // constructor + arrayView(const typename vector::const_iterator &b, + const typename vector::const_iterator &e, const int &numSpecies) + : begin_(b), + end_(e), + momentumIndex_(numSpecies), + energyIndex_(momentumIndex_ + 3), + turbulenceIndex_(energyIndex_ + 1) {} + + // move constructor and assignment operator + arrayView(arrayView&&) noexcept = default; + arrayView& operator=(arrayView&&) noexcept = default; + + // copy constructor and assignment operator + arrayView(const arrayView &) = default; + arrayView &operator=(const arrayView &) = default; + + // member functions + T2 Sum() const { return std::accumulate(begin_, end_, T2(0)); } + T1 CopyData() const { return {begin_, end_, this->NumSpecies()}; } + T1 GetViewType() const { return T1(this->Size(), this->NumSpecies(), 0.0); } + T1 Squared() const { return (*this) * (*this); } + auto Size() const { return std::distance(begin_, end_); } + auto begin() const { return begin_; } + auto end() const { return end_; } + int NumSpecies() const { return momentumIndex_; } + int NumTurbulence() const { return this->Size() - turbulenceIndex_; } + bool IsMultiSpecies() const { return this->NumSpecies() > 1; } + bool HasTurbulenceData() const { return this->Size() != turbulenceIndex_; } + int MomentumXIndex() const { return momentumIndex_; } + int MomentumYIndex() const { return momentumIndex_ + 1; } + int MomentumZIndex() const { return momentumIndex_ + 2; } + int EnergyIndex() const { return energyIndex_; } + int TurbulenceIndex() const { return turbulenceIndex_; } + T2 SpeciesSum() const { + return std::accumulate(begin_, begin_ + this->NumSpecies(), T2(0)); + } + const T2 &SpeciesN(const int &ii) const { + MSG_ASSERT(ii < momentumIndex_, "requesting species variable out of range"); + return (*this)[ii]; + } + const T2 &MomentumX() const { return (*this)[momentumIndex_]; } + const T2 &MomentumY() const { return (*this)[momentumIndex_ + 1]; } + const T2 &MomentumZ() const { return (*this)[momentumIndex_ + 2]; } + const T2 &Energy() const { return (*this)[energyIndex_]; } + const T2 &TurbulenceN(const int &ii) const { + MSG_ASSERT(turbulenceIndex_ + ii < this->Size(), + "requesting turbulence variable out of range"); + return (*this)[turbulenceIndex_ + ii]; + } + + arrayView GetView() const { return *this; } + + // -------------------------------------------------------------------------- + // getters for primitives --------------------------------------------------- + const T2 &RhoN(const int &ii) const { + static_assert(std::is_same::value || + std::is_same::value, + "getter only valid for primitive/conserved type!"); + return this->SpeciesN(ii); + } + T2 Rho() const { + static_assert(std::is_same::value || + std::is_same::value, + "getter only valid for primitive/conserved type!"); + return this->SpeciesSum(); + } + T2 MassFractionN(const int &ii) const { + static_assert(std::is_same::value || + std::is_same::value, + "getter only valid for primitive/conserved type!"); + return this->RhoN(ii) / this->Rho(); + } + vector RhoVec() const { + static_assert(std::is_same::value || + std::is_same::value, + "getter only valid for primitive/conserved type!"); + return {this->begin(), this->begin() + this->NumSpecies()}; + } + vector MassFractions() const { + static_assert(std::is_same::value || + std::is_same::value, + "getter only valid for primitive/conserved type!"); + vector mf(this->NumSpecies()); + const auto totalRho = this->Rho(); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = this->RhoN(ii) / totalRho; + } + return mf; + } + vector VolumeFractions(const unique_ptr &trans) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + // volume fractions equal to mole fractions + return trans->MoleFractions(this->MassFractions()); + } + const T2 &U() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->MomentumX(); + } + const T2 &V() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->MomentumY(); + } + const T2 &W() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->MomentumZ(); + } + const T2 &P() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->Energy(); + } + const T2 &Tke() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->TurbulenceN(0); + } + const T2 &Omega() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->TurbulenceN(1); + } + const T2 &TurbN(const int &ii) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return this->TurbulenceN(ii); + } + vector3d Velocity() const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return {this->U(), this->V(), this->W()}; + } + T2 SoS(const physics &phys) const; + T2 Energy(const physics &phys) const; + T2 SpeciesEnthalpy(const physics &phys, const int &ss) const; + T2 Enthalpy(const physics &phys) const; + T2 Temperature(const unique_ptr &eqnState) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return eqnState->Temperature(this->P(), this->RhoVec()); + } + conserved ConsVars(const physics &phys) const { + static_assert(std::is_same::value, + "function only valid for primitive type!"); + return PrimToCons((*this), phys); + } + T1 UpdateWithConsVars(const physics &phys, + const arrayView &du) const { + static_assert(std::is_same::value, + "function only valid for primitive type!"); + return UpdatePrimWithCons((*this), phys, du); + } + + // -------------------------------------------------------------------------- + // operator overloads + const T2 & operator[](const int &r) const { return *(begin_ + r); } + + inline T1 operator+(const T2 &s) const { + auto lhs = this->CopyData(); + return lhs += s; + } + inline T1 operator-(const T2 &s) const { + auto lhs = this->CopyData(); + return lhs -= s; + } + inline T1 operator*(const T2 &s) const { + auto lhs = this->CopyData(); + return lhs *= s; + } + inline T1 operator/(const T2 &s) const { + auto lhs = this->CopyData(); + return lhs /= s; + } + + // destructor + ~arrayView() noexcept {} +}; + +// function declarations -------------------------------------- +template +inline const T1 operator+(const arrayView &lhs, + const arrayView &rhs) { + auto ll = lhs.CopyData(); + return ll + rhs; +} + +template +inline const T1 operator-(const arrayView &lhs, + const arrayView &rhs) { + auto ll = lhs.CopyData(); + return ll - rhs; +} + +template +inline const T1 operator*(const arrayView &lhs, + const arrayView &rhs) { + auto ll = lhs.CopyData(); + return ll * rhs; +} + +template +inline const T1 operator/(const arrayView &lhs, + const arrayView &rhs) { + auto ll = lhs.CopyData(); + return ll / rhs; +} + +// operator overloads for type T ------------------------------------- +template +inline const T1 operator+(const T2 &lhs, const arrayView &rhs) { + auto result = rhs.CopyData(); + return result += lhs; +} + +template +inline const T1 operator-(const T2 &lhs, const arrayView &rhs) { + auto result = rhs.CopyData(); + return lhs - result; +} + +template +inline const T1 operator*(const T2 &lhs, const arrayView &rhs) { + auto result = rhs.CopyData(); + return result *= lhs; +} + +template +inline const T1 operator/(const T2 &lhs, const arrayView &rhs) { + auto result = rhs.CopyData(); + return lhs / rhs; +} + +// operator overloads for varArray type T ------------------------------------- +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator+(const T3 &lhs, const arrayView &rhs) { + T3 result(rhs.begin(), rhs.end(), rhs.NumSpecies()); + return lhs + result; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator-(const T3 &lhs, const arrayView &rhs) { + T3 result(rhs.begin(), rhs.end(), rhs.NumSpecies()); + return lhs - result; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator*(const T3 &lhs, const arrayView &rhs) { + T3 result(rhs.begin(), rhs.end(), rhs.NumSpecies()); + return lhs * result; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator/(const T3 &lhs, const arrayView &rhs) { + T3 result(rhs.begin(), rhs.end(), rhs.NumSpecies()); + return lhs / result; +} + +// --------------------------------------------------------------------------- +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator+(const arrayView &lhs, const T3 &rhs) { + T3 result(lhs.begin(), lhs.end(), lhs.NumSpecies()); + return result += rhs; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator-(const arrayView &lhs, const T3 &rhs) { + T3 result(lhs.begin(), lhs.end(), lhs.NumSpecies()); + return result -= rhs; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator*(const arrayView &lhs, const T3 &rhs) { + T3 result(lhs.begin(), lhs.end(), lhs.NumSpecies()); + return result *= rhs; +} + +template +inline const typename std::enable_if_t< + std::is_base_of::value, T3> +operator/(const arrayView &lhs, const T3 &rhs) { + T3 result(lhs.begin(), lhs.end(), lhs.NumSpecies()); + return result /= rhs; +} + + +// --------------------------------------------------------------------------- +// operation overload for << - allows use of cout, cerr, etc. +template +ostream &operator<<(ostream &os, const arrayView &m) { + for (auto rr = 0; rr < m.Size(); rr++) { + os << m[rr] << endl; + } + return os; +} + +// using typedefs +using varArrayView = arrayView; +using primitiveView = arrayView; +using conservedView = arrayView; +using residualView = arrayView; + + +template +double SpeedOfSound(const T &state, const physics &phys) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + return sqrt(phys.Thermodynamic()->Gamma(state.Temperature(phys.EoS()), + state.MassFractions()) * + state.P() / state.Rho()); +} + +template +T2 arrayView::SoS(const physics &phys) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return SpeedOfSound(*this, phys); +} + +template +double EnthalpyFunc(const T &state, const physics &phys) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + const auto t = state.Temperature(phys.EoS()); + return phys.EoS()->Enthalpy(phys.Thermodynamic(), t, state.Velocity().Mag(), + state.MassFractions()); +} + +template +double SpeciesEnthalpyFunc(const T &state, const physics &phys, const int &ss) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + const auto t = state.Temperature(phys.EoS()); + return phys.EoS()->SpeciesEnthalpy(phys.Thermodynamic(), t, + state.Velocity().Mag(), ss); +} + +template +T2 arrayView::Enthalpy(const physics &phys) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return EnthalpyFunc(*this, phys); +} + +template +T2 arrayView::SpeciesEnthalpy(const physics &phys, + const int &ss) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return SpeciesEnthalpyFunc(*this, phys, ss); +} + +template +double InternalEnergy(const T &state, const physics &phys) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + const auto t = state.Temperature(phys.EoS()); + return phys.EoS()->Energy( + phys.EoS()->SpecEnergy(phys.Thermodynamic(), t, state.MassFractions()), + state.Velocity().Mag()); +} + +template +T2 arrayView::Energy(const physics &phys) const { + static_assert(std::is_same::value, + "getter only valid for primitive type!"); + return InternalEnergy(*this, phys); +} + +#endif diff --git a/include/blkMultiArray3d.hpp b/include/blkMultiArray3d.hpp new file mode 100644 index 0000000..012d4e8 --- /dev/null +++ b/include/blkMultiArray3d.hpp @@ -0,0 +1,432 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef BLKMULTIARRAY3DHEADERDEF +#define BLKMULTIARRAY3DHEADERDEF + +/* This file contains the header and implementation for a multidimensional (3D) + array class. The class is to act as a container to store all data types, + and provide easy access to elements with i, j, k indexing. + */ + +#include // ostream +#include // vector +#include // string +#include // unique_ptr +#include "mpi.h" +#include "vector3d.hpp" +#include "boundaryConditions.hpp" // connection +#include "range.hpp" // range +#include "multiArray3d.hpp" +#include "varArray.hpp" +#include "arrayView.hpp" + +using std::ostream; +using std::endl; +using std::cout; +using std::cerr; +using std::vector; +using std::string; +using std::unique_ptr; + +template +class blkMultiArray3d : public multiArray3d { + static_assert(std::is_base_of::value, + "blkMultiArray3d requires a varArray based type"); + + int numSpecies_; + + public: + // constructor + blkMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const T &init) + : multiArray3d(ii, jj, kk, ng, init.Size()), + numSpecies_(init.NumSpecies()) { + for (auto kk = this->StartK(); kk < this->EndK(); kk++) { + for (auto jj = this->StartJ(); jj < this->EndJ(); jj++) { + for (auto ii = this->StartI(); ii < this->EndI(); ii++) { + for (auto bb = 0; bb < this->BlockSize(); ++bb) { + (*this)(ii, jj, kk, bb) = init[bb]; + } + } + } + } + } + blkMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs, const int &ns, const double &init) + : multiArray3d(ii, jj, kk, ng, bs, init), numSpecies_(ns) {} + blkMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs, const int &ns) + : multiArray3d(ii, jj, kk, ng, bs), numSpecies_(ns) {} + blkMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const std::pair &info) + : multiArray3d(ii, jj, kk, ng, info), + numSpecies_(info.second) {} + blkMultiArray3d() : multiArray3d(), numSpecies_(0) {} + + // move constructor and assignment operator + blkMultiArray3d(blkMultiArray3d &&) noexcept = default; + blkMultiArray3d &operator=(blkMultiArray3d &&) noexcept = default; + + // copy constructor and assignment operator + blkMultiArray3d(const blkMultiArray3d &) = default; + blkMultiArray3d &operator=(const blkMultiArray3d &) = default; + + // member functions + std::pair BlockInfo() const override { + return std::make_pair(this->BlockSize(), numSpecies_); + } + + template + void InsertBlock(const int &ii, const int &jj, const int &kk, const T2 &arr) { + static_assert(std::is_same::value || + std::is_same, T2>::value, + "blkMultiArray3d requires a varArray based type!"); + MSG_ASSERT(arr.Size() == this->BlockSize(), "block size must match"); + auto start = this->GetLoc1D(ii, jj, kk); + std::copy(arr.begin(), arr.end(), this->begin() + start); + } + + template + void InsertBlock(const string &dir, const int &d1, const int &d2, + const int &d3, const T2 &arr) { + static_assert(std::is_same::value || + std::is_same, T2>::value, + "blkMultiArray3d requires a varArray based type!"); + MSG_ASSERT(arr.Size() == this->BlockSize(), "block size must match"); + + auto start = 0; + if (dir == "i") { // direction 1 is i + start = this->GetLoc1D(d1, d2, d3); + } else if (dir == "j") { // direction 1 is j + start = this->GetLoc1D(d3, d1, d2); + } else if (dir == "k") { // direction 1 is k + start = this->GetLoc1D(d2, d3, d1); + } else { + cerr << "ERROR: Direction " << dir << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } + std::copy(arr.begin(), arr.end(), this->begin() + start); + } + + blkMultiArray3d Slice(const range &, const range &, const range &) const; + blkMultiArray3d Slice(const string &, const range &, + const bool = false) const; + blkMultiArray3d Slice(const string &, int, int, const bool = false, + const string = "cell", const bool = false, + const bool = false) const; + blkMultiArray3d Slice(const string &, int, range, range, + const string = "cell", const int = 0) const; + + template + void Insert(const range &, const range &, const range &, const TT &); + template + void Insert(const string &, const range &, const TT &, const bool = false); + template + void Insert(const string &, int, int, const TT &, const bool = false, + const string = "cell", const bool = false, const bool = false); + template + void Insert(const string &, int, range, range, const TT &, + const string = "cell", const int = 0); + + template + void SwapSlice(const connection &conn, TT &array); + void SwapSliceMPI(const connection &conn, const int &rank, + const MPI_Datatype &MPI_arrData, const int tag = 1); + template + void PutSlice(const TT &, const connection &, const int &); + + T GetCopy(const int &ii, const int &jj, const int &kk) const { + auto start = this->GetLoc1D(ii, jj, kk); + return {this->begin() + start, this->begin() + start + this->BlockSize(), + numSpecies_}; + } + + // operator overloads + arrayView operator()(const int &ii, const int &jj, + const int &kk) const { + auto start = this->GetLoc1D(ii, jj, kk); + return {this->begin() + start, this->begin() + start + this->BlockSize(), + numSpecies_}; + } + arrayView operator()(const int &ind) const { + auto start = ind * this->BlockSize(); + return {this->begin() + start, this->begin() + start + this->BlockSize(), + numSpecies_}; + } + arrayView operator()(const string &dir, const int &d1, + const int &d2, const int &d3) const { + auto start = 0; + if (dir == "i") { // direction 1 is i + start = this->GetLoc1D(d1, d2, d3); + } else if (dir == "j") { // direction 1 is j + start = this->GetLoc1D(d3, d1, d2); + } else if (dir == "k") { // direction 1 is k + start = this->GetLoc1D(d2, d3, d1); + } else { + cerr << "ERROR: Direction " << dir << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } + return {this->begin() + start, this->begin() + start + this->BlockSize(), + numSpecies_}; + } + double &operator()(const int &ii, const int &jj, const int &kk, + const int &bb) { + MSG_ASSERT(bb <= this->BlockSize(), "accessing data out of block index"); + return (*this)[this->GetLoc1D(ii, jj, kk) + bb]; + } + const double &operator()(const int &ii, const int &jj, const int &kk, + const int &bb) const { + MSG_ASSERT(bb <= this->BlockSize(), "accessing data out of block index"); + return (*this)[this->GetLoc1D(ii, jj, kk) + bb]; + } + + void ClearResize(const int &ii, const int &jj, const int &kk, + const int &ng, const int &bs, const int &ns) { + *this = blkMultiArray3d(ii, jj, kk, ng, bs, ns); + } + void ClearResize(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs, const int &ns, const T &val) { + *this = blkMultiArray3d(ii, jj, kk, ng, bs, ns, val); + } + + blkMultiArray3d GrowI() const; + blkMultiArray3d GrowJ() const; + blkMultiArray3d GrowK() const; + + // destructor + ~blkMultiArray3d() noexcept {} +}; + +// --------------------------------------------------------------------------- +// member function definitions + +// operation overload for << - allows use of cout, cerr, etc. +template +ostream &operator<<(ostream &os, const blkMultiArray3d &arr) { + os << "Size: " << arr.NumI() << ", " << arr.NumJ() << ", " << arr.NumK() + << endl; + os << "Number of ghost layers: " << arr.GhostLayers() << endl; + + for (auto kk = arr.StartK(); kk < arr.EndK(); ++kk) { + for (auto jj = arr.StartJ(); jj < arr.EndJ(); ++jj) { + for (auto ii = arr.StartI(); ii < arr.EndI(); ++ii) { + os << ii << ", " << jj << ", " << kk << ": " << arr(ii, jj, kk) << endl; + } + } + } + return os; +} + +// member function to return a slice of the array +// this is the main slice function that all other overloaded slice functions call +template +blkMultiArray3d blkMultiArray3d::Slice(const range &ir, const range &jr, + const range &kr) const { + // ir -- i-index range to take slice [inclusive, exclusive) + // jr -- j-index range to take slice [inclusive, exclusive) + // kr -- k-index range to take slice [inclusive, exclusive) + return SliceArray((*this), ir, jr, kr); +} + +// member function to return a slice of the array +// Overload to slice only in one direction. Given a 3D array, this slice returns +// a plane with normal direction dir, or a smaller 3D array where the direction +// dir is sliced over dirRange. It also has the ability to include or ignore +// ghost cells in its planar slices +template +blkMultiArray3d blkMultiArray3d::Slice(const string &dir, + const range &dirRange, + const bool physOnly) const { + // dir -- direction of slice + // dirRange -- range of slice in direction given + // phsOnly -- flag to only include physical cells in the two directions that + // are not specified as dir + return SliceArray((*this), dir, dirRange, physOnly); +} + +// member function to return a slice of the array +// overload to slice line out of array +template +blkMultiArray3d blkMultiArray3d::Slice(const string &dir, int d2Ind, + int d3Ind, const bool physOnly, + const string id, const bool upper2, + const bool upper3) const { + // dir -- direction of line slice (direction 1) + // d2Ind -- index of direction 2 + // d3Ind -- index of direction 3 + // physOnly -- flag to only include physical cells in line slice + // id -- type of multiArray3d being sliced: cell, i, j, or k + // d2Ind and d3Ind are supplied as cell indices, but may need to be + // altered if the array is storing i, j, or k face data + // upper2 -- flag to determine if direction 2 is at upper index + // upper3 -- flag to determine if direction 3 is at upper index + return SliceArray((*this), dir, d2Ind, d3Ind, physOnly, id, upper2, upper3); +} + +// overload to slice plane out of array +// Identical to previous slice overload, but more general in that in can slice +// over a subset of direction 2 & 3. This is useful to slice out a plane that +// borders a boundary condition patch. +template +blkMultiArray3d blkMultiArray3d::Slice(const string &dir, int dirInd, + range dir1, range dir2, + const string id, + const int type) const { + // dir -- normal direction of planar slice + // dirInd -- index in normal direction + // dir1 -- range of direction 1 (direction 3 is normal to slice) + // dir2 -- range of direction 2 (direction 3 is normal to slice) + // id -- id of array being sliced (i, j, k for faces, cell for cells) + // type -- surface type of dir + return SliceArray((*this), dir, dirInd, dir1, dir2, id, type); +} + +// member function to insert an array into this one +// this is the main insert funciton that all other overloaded insert functions +// call +template +template +void blkMultiArray3d::Insert(const range &ir, const range &jr, + const range &kr, const TT &arr) { + // ir -- i-index range to take slice [inclusive, exclusive) + // jr -- j-index range to take slice [inclusive, exclusive) + // kr -- k-index range to take slice [inclusive, exclusive) + // arr -- array to insert into this one + InsertArray((*this), ir, jr, kr, arr); +} + +// Overload to insert only in one direction. Given a 3D array, this inserts a +// plane with normal direction dir, or a smaller 3D array where the direction +// dir is inserted over dirRange. It also has the ability to include or ignore +// ghost cells in its planar inserts +template +template +void blkMultiArray3d::Insert(const string &dir, const range &dirRange, + const TT &arr, const bool physOnly) { + // dir -- direction of slice to insert + // dirRange -- range to insert slice into in direction given + // arr -- array to insert + // phsOnly -- flag to only include physical cells in the two directions that + // are not specified as dir + InsertArray((*this), dir, dirRange, arr, physOnly); +} + +// overload to insert line into array +template +template +void blkMultiArray3d::Insert(const string &dir, int d2Ind, int d3Ind, + const TT &arr, const bool physOnly, + const string id, const bool upper2, + const bool upper3) { + // dir -- direction of line slice to insert (direction 1) + // d2Ind -- index of direction 2 to insert into + // d3Ind -- index of direction 3 to insert into + // physOnly -- flag to only include physical cells in line insert + // id -- type of multiArray3d being sliced: cell, i, j, or k + // d2Ind and d3Ind are supplied as cell indices, but may need to be + // altered if the array is storing i, j, or k face data + // upper2 -- flag to determine if direction 2 is at upper index + // upper3 -- flag to determine if direction 3 is at upper index + InsertArray((*this), dir, d2Ind, d3Ind, arr, physOnly, id, upper2, upper3); +} + +// overload to insert plane into array +// Identical to previous insert overload, but more general in that in can insert +// over a subset of direction 2 & 3. This is useful to insert into a plane that +// borders a boundary condition patch. +template +template +void blkMultiArray3d::Insert(const string &dir, int dirInd, range dir1, + range dir2, const TT &arr, const string id, + const int type) { + // dir -- normal direction of planar slice + // dirInd -- index in normal direction + // dir1 -- range of direction 1 (direction 3 is normal to slice) + // dir2 -- range of direction 2 (direction 3 is normal to slice) + // arr -- array to insert + // id -- id of array being inserted into (i, j, k for faces, cell for cells) + // type -- surface type of dir + InsertArray((*this), dir, dirInd, dir1, dir2, arr, id, type); +} + +template +blkMultiArray3d blkMultiArray3d::GrowI() const { + return GrowInI(*this); +} +template +blkMultiArray3d blkMultiArray3d::GrowJ() const { + return GrowInJ(*this); +} +template +blkMultiArray3d blkMultiArray3d::GrowK() const { + return GrowInK(*this); +} + +/* Function to swap slice using MPI. This is similar to the SwapSlice + function, but is called when the neighboring procBlocks are on different + processors. +*/ +template +void blkMultiArray3d::SwapSliceMPI(const connection &conn, const int &rank, + const MPI_Datatype &MPI_arrData, + const int tag) { + // conn -- connection boundary information + // rank -- processor rank + // MPI_arrData -- MPI datatype for passing data in *this + // tag -- id for MPI swap (default 1) + SwapSliceParallel((*this), conn, rank, MPI_arrData, tag); +} + +/* Function to swap ghost cells between two blocks at an connection +boundary. Slices are removed from the physical cells (extending into ghost cells +at the edges) of one block and inserted into the ghost cells of its partner +block. The reverse is also true. The slices are taken in the coordinate system +orientation of their parent block. + + Interior Cells Ghost Cells Ghost Cells Interior Cells + ________ ______|________ _________ _______________|_______ _________ +Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 + | | | | | | | | | | + | Ui-1 | Ui | Uj | Uj+1 | | Ui-1 | Ui | Uj | Uj+1 | + | | | | | | | | | | + |________|______|________|_________| |________|______|_______|_________| + | | + +The above diagram shows the resulting values after the ghost cell swap. The +logic ensures that the ghost cells at the connection boundary exactly match +their partner block as if there were no separation in the grid. +*/ +template +template +void blkMultiArray3d::SwapSlice(const connection &conn, TT &array) { + // conn -- connection boundary information + // array -- second array involved in connection boundary + SwapSliceLocal((*this), conn, array); +} + +template +template +void blkMultiArray3d::PutSlice(const TT &array, const connection &inter, + const int &d3) { + // array -- array to insert into *this + // inter -- connection data structure defining patches and orientation + // d3 -- distance of direction normal to patch to insert + InsertSlice((*this), array, inter, d3); +} + + +#endif diff --git a/include/boundaryConditions.hpp b/include/boundaryConditions.hpp index b946e98..4b0fb0f 100644 --- a/include/boundaryConditions.hpp +++ b/include/boundaryConditions.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,6 +29,9 @@ one block. */ #include // string #include // ostream #include // unique_ptr +#include +#include +#include #include "mpi.h" // parallelism #include "vector3d.hpp" #include "range.hpp" @@ -40,6 +43,8 @@ using std::string; using std::cout; using std::endl; using std::shared_ptr; +using std::pair; +using std::map; // forward class declaration class plot3dBlock; @@ -78,7 +83,21 @@ class boundarySurface { int KMax() const {return data_[5];} int Tag() const {return data_[6];} + void MoveI(const int &s) { + data_[0] += s; + data_[1] += s; + } + void MoveJ(const int &s) { + data_[2] += s; + data_[3] += s; + } + void MoveK(const int &s) { + data_[4] += s; + data_[5] += s; + } + int SurfaceType() const; + bool IsUpper() const { return this->SurfaceType() % 2 == 0; } string Direction1() const; string Direction2() const; string Direction3() const; @@ -123,6 +142,7 @@ class boundarySurface { bool operator==(const boundarySurface &) const; bool operator!=(const boundarySurface &s) const { return !(*this == s); }; + bool operator<(const boundarySurface &s) const; // Destructor ~boundarySurface() noexcept {} @@ -226,6 +246,7 @@ class boundaryConditions { int NumSurfJ() const {return numSurfJ_;} int NumSurfK() const {return numSurfK_;} int NumSurfaces() const {return numSurfI_ + numSurfJ_ + numSurfK_;} + void Sort() {std::sort(std::begin(surfs_), std::end(surfs_));} string GetBCTypes(const int &a) const {return surfs_[a].BCType();} int GetIMin(const int &a) const {return surfs_[a].IMin();} @@ -275,8 +296,8 @@ class boundaryConditions { boundaryConditions Split(const string&, const int&, const int&, const int&, vector&); - void DependentSplit(const boundarySurface&, const plot3dBlock&, - const plot3dBlock&, const int&, const string&, + void DependentSplit(const boundarySurface&, boundarySurface, + const int&, const int&, const string&, const int&, const int&, const int&); void Join(const boundaryConditions&, const string&, vector&); void Merge(const string &); @@ -286,6 +307,8 @@ class boundaryConditions { void PackBC(char*(&), const int&, int&) const; void UnpackBC(char*(&), const int&, int&); + vector> CGridPairs(const int &) const; + // Destructor ~boundaryConditions() noexcept {} }; @@ -409,6 +432,9 @@ class connection { vector GetConnectionBCs(const vector&, const vector&, const decomposition&, const input&); +map> GetBlockInterConnBCs( + const vector &, const vector &, + const int &); ostream & operator<< (ostream &os, const boundaryConditions&); ostream & operator<< (ostream &os, const boundarySurface&); diff --git a/include/conserved.hpp b/include/conserved.hpp new file mode 100644 index 0000000..8d7ca1a --- /dev/null +++ b/include/conserved.hpp @@ -0,0 +1,77 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef CONSERVEDHEADERDEF +#define CONSERVEDHEADERDEF + +#include +#include "varArray.hpp" + +using std::ostream; + +class conserved : public varArray { + public: + // constructor + conserved(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies) {} + conserved(const vector::const_iterator &b, + const vector::const_iterator &e, const int &numSpecies) + : varArray(b, e, numSpecies) {} + + // member functions + const double & RhoN(const int &ii) const { return this->SpeciesN(ii); } + double Rho() const { return this->SpeciesSum(); } + vector RhoVec() const { + return {this->begin(), this->begin() + this->NumSpecies()}; + } + double MassFractionN(const int &ii) const { + return this->RhoN(ii) / this->Rho(); + } + vector MassFractions() const { + vector mf(this->NumSpecies()); + const auto totalRho = this->Rho(); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = this->RhoN(ii) / totalRho; + } + return mf; + } + const double & RhoU() const { return this->MomentumX(); } + const double & RhoV() const { return this->MomentumY(); } + const double & RhoW() const { return this->MomentumZ(); } + const double & RhoE() const { return this->Energy(); } + const double & RhoTke() const { return this->TurbulenceN(0); } + const double & RhoOmega() const { return this->TurbulenceN(1); } + const double & RhoTurbN(const int &ii) const { return this->TurbulenceN(ii); } + + arrayView GetView() const; + + // move constructor and assignment operator + conserved(conserved &&) noexcept = default; + conserved &operator=(conserved &&) noexcept = default; + + // copy constructor and assignment operator + conserved(const conserved &) = default; + conserved &operator=(const conserved &) = default; + + // destructor + ~conserved() noexcept {} +}; + +ostream &operator<<(ostream &os, const conserved &); + + + +#endif diff --git a/include/diffusion.hpp b/include/diffusion.hpp new file mode 100644 index 0000000..447a5b2 --- /dev/null +++ b/include/diffusion.hpp @@ -0,0 +1,116 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef DIFFUSIONHEADERDEF +#define DIFFUSIONHEADERDEF + +// This header file contains the classes for all diffusion models + +#include + +using std::vector; + +// forward class declarations +class fluid; + +// abstract base class for diffusion models +class diffusion { + + public: + // Constructor + diffusion() {} + + // move constructor and assignment operator + diffusion(diffusion&&) noexcept = default; + diffusion& operator=(diffusion&&) noexcept = default; + + // copy constructor and assignment operator + diffusion(const diffusion&) = default; + diffusion& operator=(const diffusion&) = default; + + // Member functions for abstract base class + virtual double LaminarDiffCoeff(const double &mu) const = 0; + virtual double TurbDiffCoeff(const double &mut) const = 0; + double DiffCoeff(const double &mu, const double &mut) { + return this->LaminarDiffCoeff(mu) + this->TurbDiffCoeff(mut); + } + + // Destructor + virtual ~diffusion() noexcept {} +}; + +// this class models no diffusion +class diffNone : public diffusion { + + public: + // Constructors + diffNone() {} + + // move constructor and assignment operator + diffNone(diffNone&&) noexcept = default; + diffNone& operator=(diffNone&&) noexcept = default; + + // copy constructor and assignment operator + diffNone(const diffNone&) = default; + diffNone& operator=(const diffNone&) = default; + + // Member functions + double LaminarDiffCoeff(const double &mu) const override { return 0.0; } + double TurbDiffCoeff(const double &mut) const override { return 0.0; } + + // Destructor + ~diffNone() noexcept {} +}; + + + +// this class models diffusion using Schmidt number +class schmidt : public diffusion { + double schmidtNumber_; + double turbSchmidtNumber_; + + public: + // Constructors + schmidt(const double &sc, const double &tsc) + : schmidtNumber_(sc), turbSchmidtNumber_(tsc) {} + + // move constructor and assignment operator + schmidt(schmidt&&) noexcept = default; + schmidt& operator=(schmidt&&) noexcept = default; + + // copy constructor and assignment operator + schmidt(const schmidt&) = default; + schmidt& operator=(const schmidt&) = default; + + // Member functions + double LaminarDiffCoeff(const double &mu) const override { + return mu / schmidtNumber_; + } + double TurbDiffCoeff(const double &mut) const override { + return mut / turbSchmidtNumber_; + } + + // Destructor + ~schmidt() noexcept {} +}; + + +// -------------------------------------------------------------------------- +// function declarations + + + +#endif diff --git a/include/eos.hpp b/include/eos.hpp index 2d153ce..c3bb692 100644 --- a/include/eos.hpp +++ b/include/eos.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,11 +21,16 @@ // This header file contains the equation of state classes #include +#include #include "vector3d.hpp" #include "thermodynamic.hpp" +#include "macros.hpp" using std::unique_ptr; +// forward class declaration +class fluid; + // abstract base class for equation of state class eos { @@ -42,22 +47,33 @@ class eos { eos& operator=(const eos&) = default; // Member functions for abstract base class + virtual int NumSpecies() const = 0; + virtual double GasConstant(const int &ii) const = 0; + virtual double MixtureGasConstant(const vector &mf) const = 0; + virtual const vector &GasConstants() const = 0; virtual double PressFromEnergy(const unique_ptr &thermo, - const double &rho, const double &energy, + const vector &rho, + const double &energy, const double &vel) const = 0; - virtual double PressureRT(const double &rho, + virtual double PressureRT(const vector &rho, const double &temperature) const = 0; virtual double SpecEnergy(const unique_ptr &thermo, - const double &t) const = 0; + const double &t, + const vector &mf) const = 0; virtual double Energy(const double &specEn, const double &vel) const = 0; + virtual double SpeciesEnthalpy(const unique_ptr &thermo, + const double &t, const double &vel, + const int &ss) const = 0; virtual double Enthalpy(const unique_ptr &thermo, - const double &t, const double &vel) const = 0; - virtual double SoS(const double &pressure, const double &rho) const = 0; + const double &t, const double &vel, + const vector &mf) const = 0; + virtual double SoS(const unique_ptr &thermo, + const double &pressure, + const vector &rho) const = 0; virtual double Temperature(const double &pressure, - const double &rho) const = 0; - virtual double PressureDim(const double &rho, - const double &temperature) const = 0; - virtual double DensityTP(const double &temp, const double &press) const = 0; + const vector &rho) const = 0; + virtual double DensityTP(const double &temp, const double &press, + const vector &mf) const = 0; // Destructor virtual ~eos() noexcept {} @@ -69,42 +85,40 @@ class eos { // nondimensional from it is P = rho * T / gammaRef class idealGas : public eos { - const double gammaRef_; - const double gasConst_; + vector gasConst_; public: // Constructor - idealGas(const unique_ptr &thermo, const double &r, - const double &t) - : gammaRef_(thermo->Gamma(t)), gasConst_(r) {} - - // move constructor and assignment operator - idealGas(idealGas&&) noexcept = default; - idealGas& operator=(idealGas&&) noexcept = default; - - // copy constructor and assignment operator - idealGas(const idealGas&) = default; - idealGas& operator=(const idealGas&) = default; + idealGas(const vector &, const double &, const double &); // Member functions + int NumSpecies() const override { return gasConst_.size(); } + double GasConstant(const int &ii) const override { return gasConst_[ii]; } + double MixtureGasConstant(const vector &mf) const override { + MSG_ASSERT(mf.size() == gasConst_.size(), "mismatch in species size"); + return std::inner_product(std::begin(mf), std::end(mf), + std::begin(gasConst_), 0.0); + } + const vector &GasConstants() const override { return gasConst_; } double PressFromEnergy(const unique_ptr &thermo, - const double &rho, const double &energy, + const vector &rho, const double &energy, const double &vel) const override; - double PressureRT(const double &rho, + double PressureRT(const vector &rho, const double &temperature) const override; - double SpecEnergy(const unique_ptr &thermo, - const double &t) const override; + double SpecEnergy(const unique_ptr &thermo, const double &t, + const vector &mf) const override; double Energy(const double &specEn, const double &vel) const override; + double SpeciesEnthalpy(const unique_ptr &thermo, + const double &t, const double &vel, + const int &ss) const override; double Enthalpy(const unique_ptr &thermo, const double &t, - const double &vel) const override; - double SoS(const double &pressure, const double &rho) const override; - double Temperature(const double &pressure, const double &rho) const override; - double PressureDim(const double &rho, - const double &temperature) const override; - // nondimensional version (R=1/gamma) - double DensityTP(const double &temp, const double &press) const override { - return press * gammaRef_ / temp; - } + const double &vel, const vector &mf) const override; + double SoS(const unique_ptr &thermo, const double &pressure, + const vector &rho) const override; + double Temperature(const double &pressure, + const vector &rho) const override; + double DensityTP(const double &temp, const double &press, + const vector &mf) const override; // Destructor ~idealGas() noexcept {} diff --git a/include/fluid.hpp b/include/fluid.hpp index 012902c..6037a11 100644 --- a/include/fluid.hpp +++ b/include/fluid.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,31 +20,37 @@ // This header file contains the properties for a given fluid #include +#include #include #include #include using std::vector; +using std::array; using std::ifstream; using std::string; using std::ostream; // class for fluid properties class fluid { - double n_ = 2.5; - double molarMass_ = 0.02897; // kg/mol - double vibTemp_ = 3056.0; // K + double n_; + double molarMass_; // kg/mol + vector vibTemp_; // K double universalGasConst_ = 8.3144598; // J / mol-K + array transportViscosity_; + array transportConductivity_; + double massFracRef_ = 1.0; string name_ = "air"; bool nondimensional_ = false; // private member functions void SetNondimensional(const bool &nd) { nondimensional_ = nd; } + void GetDatabaseProperties(const string &); public: // Constructor - fluid() {} - fluid(string& str, const string = "fluid"); + fluid() { this->GetDatabaseProperties(name_); } + fluid(string &str, const string = "fluid"); // move constructor and assignment operator fluid(fluid&&) noexcept = default; @@ -57,9 +63,12 @@ class fluid { // Member functions for abstract base class double N() const { return n_; } double MolarMass() const { return molarMass_; } - double VibrationalTemperature() const { return vibTemp_; } + vector VibrationalTemperature() const { return vibTemp_; } double GasConstant() const { return universalGasConst_ / molarMass_; } double UniversalGasConstant() const { return universalGasConst_; } + auto ViscosityCoeffs() const { return transportViscosity_; } + auto ConductivityCoeffs() const { return transportConductivity_; } + double MassFractionRef() const { return massFracRef_; } string Name() const { return name_; } bool IsNondimensional() const { return nondimensional_; } diff --git a/include/fluxJacobian.hpp b/include/fluxJacobian.hpp index 9df54f6..d805411 100644 --- a/include/fluxJacobian.hpp +++ b/include/fluxJacobian.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,41 +19,118 @@ #define FLUXJACOBIANHEADERDEF // define the macro #include // vector -#include // unique_ptr +#include +#include +#include #include "vector3d.hpp" #include "tensor.hpp" #include "uncoupledScalar.hpp" #include "matrix.hpp" +#include "varArray.hpp" +#include "arrayView.hpp" +#include "utility.hpp" // TauNormal +#include "inviscidFlux.hpp" // ConvectiveFluxUpdate +#include "input.hpp" // input +#include "physicsModels.hpp" using std::vector; using std::ostream; -using std::unique_ptr; // forward class declarations -class primVars; -class eos; -class transport; -class thermodynamic; -class turbModel; -class input; -class genArray; +class primitive; +class conserved; + +template ::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>, + typename = std::enable_if_t::value>> +void ArrayMultiplication(const vector::const_iterator &mat, + const int &flowSize, const int &turbSize, + const bool &isScalar, const T1 &orig, T2 &arr) { + MSG_ASSERT(isScalar || (flowSize + turbSize) == orig.Size(), + "matrix/vector size mismatch"); + MSG_ASSERT(isScalar || (flowSize + turbSize) == arr.Size(), + "matrix/vector size mismatch"); + + auto GetFlowVal = [&flowSize](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * flowSize + c); + }; + auto GetTurbVal = [&flowSize, &turbSize](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + flowSize * flowSize + r * turbSize + c); + }; + + if (isScalar) { + for (auto ii = 0; ii < arr.TurbulenceIndex(); ++ii) { + arr[ii] = orig[ii] * GetFlowVal(mat, 0, 0); + } + for (auto ii = arr.TurbulenceIndex(); ii < arr.Size(); ++ii) { + arr[ii] = orig[ii] * GetTurbVal(mat, 0, 0); + } + } else { + for (auto rr = 0; rr < flowSize; ++rr) { + for (auto cc = 0; cc < flowSize; ++cc) { + arr[rr] += GetFlowVal(mat, rr, cc) * orig[cc]; + } + } + + for (auto rr = 0; rr < turbSize; ++rr) { + for (auto cc = 0; cc < turbSize; ++cc) { + arr[flowSize + rr] += GetTurbVal(mat, rr, cc) * orig[flowSize + cc]; + } + } + } +} // This class holds the flux jacobians for the flow and turbulence equations. // In the LU-SGS method the jacobians are scalars. class fluxJacobian { - squareMatrix flowJacobian_; - squareMatrix turbJacobian_; + vector data_; + int flowSize_; + int turbSize_; + + // private member functions + int GetFlowLoc(const int &r, const int &c) const { + return r * flowSize_ + c; + } + int GetTurbLoc(const int &r, const int &c) const { + return flowSize_ * flowSize_ + r * turbSize_ + c; + } + double & FlowJacobian(const int &r, const int &c) { + return data_[this->GetFlowLoc(r, c)]; + } + double & TurbJacobian(const int &r, const int &c) { + return data_[this->GetTurbLoc(r, c)]; + } public: // constructors - fluxJacobian(const double &flow, const double &turb); - fluxJacobian(const int &flowSize, const int &turbSize); + fluxJacobian(const int &flowSize, const int &turbSize) + : data_(flowSize * flowSize + turbSize * turbSize, 0.0), + flowSize_(flowSize), + turbSize_(turbSize) {} + fluxJacobian(const double &flow, const double &turb) : fluxJacobian(1, 1) { + this->FlowJacobian(0, 0) = flow; + this->TurbJacobian(0, 0) = turb; + } fluxJacobian(const squareMatrix &flow, const squareMatrix &turb) - : flowJacobian_(flow), turbJacobian_(turb) {} + : fluxJacobian(flow.Size(), turb.Size()) { + std::copy(flow.begin(), flow.end(), data_.begin()); + std::copy(turb.begin(), turb.end(), data_.begin() + flowSize_ * flowSize_); + } fluxJacobian() : fluxJacobian(0.0, 0.0) {} - explicit fluxJacobian(const uncoupledScalar &specRad) : - fluxJacobian(specRad.FlowVariable(), specRad.TurbVariable()) {} + fluxJacobian(const uncoupledScalar &specRad, const bool &hasTurb) + : fluxJacobian(1, hasTurb ? 1 : 0) { + this->FlowJacobian(0, 0) = specRad.FlowVariable(); + if (hasTurb) { + this->TurbJacobian(0, 0) = specRad.TurbVariable(); + } + } // move constructor and assignment operator fluxJacobian(fluxJacobian&&) noexcept = default; @@ -64,49 +141,154 @@ class fluxJacobian { fluxJacobian& operator=(const fluxJacobian&) = default; // member functions - squareMatrix FlowJacobian() const {return flowJacobian_;} - squareMatrix TurbulenceJacobian() const {return turbJacobian_;} + int Size() const {return data_.size();} + int FlowSize() const { return flowSize_; } + int TurbSize() const { return turbSize_; } - void AddToFlowJacobian(const squareMatrix &jac) {flowJacobian_ += jac;} - void AddToTurbJacobian(const squareMatrix &jac) {turbJacobian_ += jac;} - void SubtractFromFlowJacobian(const squareMatrix &jac) {flowJacobian_ -= jac;} - void SubtractFromTurbJacobian(const squareMatrix &jac) {turbJacobian_ -= jac;} + const double & FlowJacobian(const int &r, const int &c) const { + return data_[this->GetFlowLoc(r, c)]; + } + const double & TurbJacobian(const int &r, const int &c) const { + return data_[this->GetTurbLoc(r, c)]; + } + + // provide begin and end so std::begin and std::end can be used + // use lower case to conform with std::begin, std::end + auto begin() noexcept {return data_.begin();} + const auto begin() const noexcept {return data_.begin();} + auto end() noexcept {return data_.end();} + const auto end() const noexcept {return data_.end();} + auto beginTurb() noexcept { return data_.begin() + flowSize_ * flowSize_; } + const auto beginTurb() const noexcept { + return data_.begin() + flowSize_ * flowSize_; + } + + // const squareMatrix & FlowJacobian() const {return flowJacobian_;} + // const squareMatrix & TurbulenceJacobian() const {return turbJacobian_;} - void MultiplyOnDiagonal(const double &, const bool &); - void AddOnDiagonal(const double &, const bool &); + void AddToFlowJacobian(const squareMatrix &jac); + void AddToTurbJacobian(const squareMatrix &jac); + void SubtractFromFlowJacobian(const squareMatrix &jac); + void SubtractFromTurbJacobian(const squareMatrix &jac); - void RusanovFluxJacobian(const primVars &, const unique_ptr &, - const unique_ptr &, + void MultFlowJacobian(const double &fac); + void MultTurbJacobian(const double &fac); + + void MultiplyOnDiagonal(const double &fac) { + this->FlowMultiplyOnDiagonal(fac); + this->TurbMultiplyOnDiagonal(fac); + } + void FlowMultiplyOnDiagonal(const double &fac) { + MultiplyFacOnDiagonal(this->begin(), flowSize_, fac); + } + void TurbMultiplyOnDiagonal(const double &fac) { + MultiplyFacOnDiagonal(this->beginTurb(), turbSize_, fac); + } + + void AddOnDiagonal(const double &fac) { + this->FlowAddOnDiagonal(fac); + this->TurbAddOnDiagonal(fac); + } + void FlowAddOnDiagonal(const double &fac) { + AddFacOnDiagonal(this->begin(), flowSize_, fac); + } + void TurbAddOnDiagonal(const double &fac) { + AddFacOnDiagonal(this->beginTurb(), turbSize_, fac); + } + + bool HasTurbulence() const { return turbSize_ > 0; } + + fluxJacobian FlowMatMult(const fluxJacobian &) const; + fluxJacobian TurbMatMult(const fluxJacobian &) const; + + void FlowSwapRows(const int &r1, const int &r2) { + SwapMatRows(this->begin(), flowSize_, r1, r2); + } + void TurbSwapRows(const int &r1, const int &r2) { + SwapMatRows(this->beginTurb(), turbSize_, r1, r2); + } + + void FlowRowMultiply(const int &r, const int &c, const double &fac) { + RowMultiplyFactor(this->begin(), flowSize_, r, c, fac); + } + void TurbRowMultiply(const int &r, const int &c, const double &fac) { + RowMultiplyFactor(this->beginTurb(), turbSize_, r, c, fac); + } + + void FlowLinCombRow(const int &r1, const double &fac, const int &r2) { + LinearCombRow(this->begin(), flowSize_, r1, fac, r2); + } + void TurbLinCombRow(const int &r1, const double &fac, const int &r2) { + LinearCombRow(this->beginTurb(), turbSize_, r1, fac, r2); + } + + int FlowFindMaxInCol(const int &c, const int &start, const int &end) const { + return FindMaxInColumn(this->begin(), flowSize_, c, start, end); + } + int TurbFindMaxInCol(const int &c, const int &start, const int &end) const { + return FindMaxInColumn(this->beginTurb(), turbSize_, c, start, end); + } + + void FlowIdentity() { IdentityMatrix(this->begin(), flowSize_); } + void TurbIdentity() { IdentityMatrix(this->beginTurb(), turbSize_); } + + double FlowMaxAbsValOnDiagonal() const { + return MaximumAbsValOnDiagonal(this->begin(), flowSize_); + } + double TurbMaxAbsValOnDiagonal() const { + return MaximumAbsValOnDiagonal(this->beginTurb(), turbSize_); + } + + template + void RusanovFluxJacobian(const T &, const physics &, const unitVec3dMag &, const bool &, - const input &, const unique_ptr &); - void InvFluxJacobian(const primVars &, const unique_ptr &, - const unique_ptr &, - const unitVec3dMag &, const input &, - const unique_ptr &); - void ApproxRoeFluxJacobian(const primVars &, const primVars &, - const unique_ptr &, - const unique_ptr &, + const input &); + template + void InvFluxJacobian(const T &, const physics &, const unitVec3dMag &, + const input &); + template + void ApproxRoeFluxJacobian(const T1 &, const T2 &, const physics &, const unitVec3dMag &, const bool &, - const input &, const unique_ptr &); - void DelPrimativeDelConservative(const primVars &, - const unique_ptr &, - const unique_ptr &, const input &); - - void ApproxTSLJacobian( - const primVars &, const double &, const double &, const double &, - const unique_ptr &, const unique_ptr &, - const unique_ptr &, const unitVec3dMag &, - const double &, const unique_ptr &, const input &, - const bool &, const tensor &); + const input &); + template + void DelprimitiveDelConservative(const T &, const physics &, const input &); + + template + void ApproxTSLJacobian(const T &, const double &, const double &, + const double &, const physics &, + const unitVec3dMag &, const double &, + const input &, const bool &, const tensor &); void Zero() { - flowJacobian_.Zero(); - turbJacobian_.Zero(); + std::fill(this->begin(), this->end(), 0.0); } - genArray ArrayMult(genArray) const; - bool IsScalar() const; - void Inverse(const bool &); + template ::value>> + T ArrayMult(const T &orig) const { + T arr(orig.Size(), orig.NumSpecies()); + ArrayMultiplication(this->begin(), flowSize_, turbSize_, this->IsScalar(), + orig, arr); + return arr; + } + template ::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>> + auto ArrayMult(const T &arrView) const { + auto arr = arrView.GetViewType(); + ArrayMultiplication(this->begin(), flowSize_, turbSize_, this->IsScalar(), + arrView, arr); + return arr; + } + bool IsScalar() const {return flowSize_ == 1;} + void Inverse() { + this->FlowInverse(); + this->TurbInverse(); + } + void FlowInverse() { MatrixInverse(this->begin(), flowSize_); } + void TurbInverse() { MatrixInverse(this->beginTurb(), turbSize_); } inline fluxJacobian & operator+=(const fluxJacobian &); inline fluxJacobian & operator-=(const fluxJacobian &); @@ -135,11 +317,6 @@ class fluxJacobian { return lhs /= s; } - friend inline const fluxJacobian operator-(const double &lhs, - fluxJacobian rhs); - friend inline const fluxJacobian operator/(const double &lhs, - fluxJacobian rhs); - // destructor ~fluxJacobian() noexcept {} }; @@ -148,29 +325,33 @@ class fluxJacobian { // operator overload for addition fluxJacobian & fluxJacobian::operator+=(const fluxJacobian &other) { - flowJacobian_ += other.flowJacobian_; - turbJacobian_ += other.turbJacobian_; + MSG_ASSERT(this->Size() == other.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), other.begin(), this->begin(), + std::plus()); return *this; } // operator overload for subtraction with a scalar fluxJacobian & fluxJacobian::operator-=(const fluxJacobian &other) { - flowJacobian_ -= other.flowJacobian_; - turbJacobian_ -= other.turbJacobian_; + MSG_ASSERT(this->Size() == other.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), other.begin(), this->begin(), + std::minus()); return *this; } // operator overload for elementwise multiplication fluxJacobian & fluxJacobian::operator*=(const fluxJacobian &other) { - flowJacobian_ *= other.flowJacobian_; - turbJacobian_ *= other.turbJacobian_; + MSG_ASSERT(this->Size() == other.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), other.begin(), this->begin(), + std::multiplies()); return *this; } // operator overload for elementwise division fluxJacobian & fluxJacobian::operator/=(const fluxJacobian &other) { - flowJacobian_ /= other.flowJacobian_; - turbJacobian_ /= other.turbJacobian_; + MSG_ASSERT(this->Size() == other.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), other.begin(), this->begin(), + std::divides()); return *this; } @@ -193,29 +374,29 @@ inline const fluxJacobian operator/(fluxJacobian lhs, const fluxJacobian &rhs) { // operator overloads for double ------------------------------------- // operator overload for addition fluxJacobian & fluxJacobian::operator+=(const double &scalar) { - flowJacobian_ += scalar; - turbJacobian_ += scalar; + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val += scalar; }); return *this; } // operator overload for subtraction with a scalar fluxJacobian & fluxJacobian::operator-=(const double &scalar) { - flowJacobian_ -= scalar; - turbJacobian_ -= scalar; + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val -= scalar; }); return *this; } // operator overload for elementwise multiplication fluxJacobian & fluxJacobian::operator*=(const double &scalar) { - flowJacobian_ *= scalar; - turbJacobian_ *= scalar; + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val *= scalar; }); return *this; } // operator overload for elementwise division fluxJacobian & fluxJacobian::operator/=(const double &scalar) { - flowJacobian_ /= scalar; - turbJacobian_ /= scalar; + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val /= scalar; }); return *this; } @@ -224,8 +405,7 @@ inline const fluxJacobian operator+(const double &lhs, fluxJacobian rhs) { } inline const fluxJacobian operator-(const double &lhs, fluxJacobian rhs) { - rhs.flowJacobian_ = lhs - rhs.flowJacobian_; - rhs.turbJacobian_ = lhs - rhs.turbJacobian_; + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs - val; }); return rhs; } @@ -234,50 +414,365 @@ inline const fluxJacobian operator*(const double &lhs, fluxJacobian rhs) { } inline const fluxJacobian operator/(const double &lhs, fluxJacobian rhs) { - rhs.flowJacobian_ = lhs / rhs.flowJacobian_; - rhs.turbJacobian_ = lhs / rhs.turbJacobian_; + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs / val; }); return rhs; } ostream &operator<<(ostream &os, const fluxJacobian &jacobian); -genArray RusanovScalarOffDiagonal(const primVars &, const genArray &, - const unitVec3dMag &, - const double &, const double &, +// --------------------------------------------------------------------------- +// member functions + +/* Function to calculate Rusanov flux jacobian. The Rusanov flux is defined as +shown below. + + F = 0.5 * (F(Ul) + F(Ur) - L(Ul, Ur) * (Ur - Ul) + +Differentiating by the left and right states gives the left and right flux +jacobians. + + dF_Ul = 0.5 * (A(Ul) + L(Ul, Ur)) + dF_Ur = 0.5 * (A(Ur) - L(Ul, Ur)) + +In the above equations the dissipation term L is held constant during +differentiation. A represents the convective flux jacobian matrix. + */ +template +void fluxJacobian::RusanovFluxJacobian(const T &state, const physics &phys, + const unitVec3dMag &area, + const bool &positive, const input &inp) { + // state -- primitive variables at face + // phys -- physics models + // area -- face area vector + // positive -- flag to determine whether to add or subtract dissipation + // inp -- input variables + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + // face inviscid spectral radius + const auto specRad = InvFaceSpectralRadius(state, area, phys); + + // form dissipation matrix based on spectral radius + fluxJacobian dissipation(inp.NumFlowEquations(), inp.NumTurbEquations()); + dissipation.FlowIdentity(); + dissipation.FlowMultiplyOnDiagonal(specRad); + + // begin jacobian calculation + this->InvFluxJacobian(state, phys, area, inp); + + // compute turbulent dissipation if necessary + if (inp.IsRANS()) { + // multiply by 0.5 b/c averaging with convection matrix + const auto tJac = + 0.5 * phys.Turbulence()->InviscidDissJacobian(state, area); + std::copy(tJac.begin(), tJac.end(), dissipation.beginTurb()); + } + + positive ? (*this) += dissipation : (*this) -= dissipation; +} + +// function to calculate inviscid flux jacobian +template +void fluxJacobian::InvFluxJacobian(const T &state, const physics &phys, + const unitVec3dMag &area, + const input &inp) { + // state -- primitive variables at face + // phys -- physics models + // area -- face area vector + // inp -- input variables + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + const auto t = state.Temperature(phys.EoS()); + const auto n = area.UnitVector(); + const auto velNorm = state.Velocity().DotProd(n); + const auto mf = state.MassFractions(); + const auto gamma = phys.Thermodynamic()->Gamma(t, mf); + const auto gm1 = gamma - 1.0; + const auto phi = 0.5 * gm1 * state.Velocity().MagSq(); + const auto a1 = gamma * state.Energy(phys) - phi; + const auto a3 = gamma - 2.0; + + // begin jacobian calculation + *this = fluxJacobian(inp.NumFlowEquations(), inp.NumTurbEquations()); + + const auto ns = state.NumSpecies(); + for (auto ii = 0; ii < ns; ++ii) { + for (auto jj = 0; jj < ns; ++jj) { + this->FlowJacobian(ii, jj) = velNorm * (Kronecker(ii, jj) - mf[ii]); + } + + // rows for species equations + this->FlowJacobian(ii, ns + 0) = mf[ii] * n.X(); + this->FlowJacobian(ii, ns + 1) = mf[ii] * n.Y(); + this->FlowJacobian(ii, ns + 2) = mf[ii] * n.Z(); + + // columns for species equations + this->FlowJacobian(ns + 0, ii) = phi * n.X() - state.U() * velNorm; + this->FlowJacobian(ns + 1, ii) = phi * n.Y() - state.V() * velNorm; + this->FlowJacobian(ns + 2, ii) = phi * n.Z() - state.W() * velNorm; + this->FlowJacobian(ns + 3, ii) = velNorm * (phi - a1); + } + + // calculate flux derivatives wrt state + // column one + this->FlowJacobian(ns + 0, ns) = velNorm - a3 * n.X() * state.U(); + this->FlowJacobian(ns + 1, ns) = state.V() * n.X() - gm1 * state.U() * n.Y(); + this->FlowJacobian(ns + 2, ns) = state.W() * n.X() - gm1 * state.U() * n.Z(); + this->FlowJacobian(ns + 3, ns) = a1 * n.X() - gm1 * state.U() * velNorm; + + // column two + this->FlowJacobian(ns + 0, ns + 1) = state.U() * n.Y() - gm1 * state.V() * n.X(); + this->FlowJacobian(ns + 1, ns + 1) = velNorm - a3 * n.Y() * state.V(); + this->FlowJacobian(ns + 2, ns + 1) = state.W() * n.Y() - gm1 * state.V() * n.Z(); + this->FlowJacobian(ns + 3, ns + 1) = a1 * n.Y() - gm1 * state.V() * velNorm; + + // column three + this->FlowJacobian(ns + 0, ns + 2) = state.U() * n.Z() - gm1 * state.W() * n.X(); + this->FlowJacobian(ns + 1, ns + 2) = state.V() * n.Z() - gm1 * state.W() * n.Y(); + this->FlowJacobian(ns + 2, ns + 2) = velNorm - a3 * n.Z() * state.W(); + this->FlowJacobian(ns + 3, ns + 2) = a1 * n.Z() - gm1 * state.W() * velNorm; + + // column four + this->FlowJacobian(ns + 0, ns + 3) = gm1 * n.X(); + this->FlowJacobian(ns + 1, ns + 3) = gm1 * n.Y(); + this->FlowJacobian(ns + 2, ns + 3) = gm1 * n.Z(); + this->FlowJacobian(ns + 3, ns + 3) = gamma * velNorm; + + // multiply by 0.5 b/c averaging with dissipation matrix + this->MultFlowJacobian(0.5 * area.Mag()); + + // turbulent jacobian here + if (inp.IsRANS()) { + // multiply by 0.5 b/c averaging with dissipation matrix + const auto tJac = + 0.5 * phys.Turbulence()->InviscidConvJacobian(state, area); + std::copy(tJac.begin(), tJac.end(), this->beginTurb()); + } +} + +/* Function to calculate approximate Roe flux jacobian. The Roe flux is +defined as shown below. + + F = 0.5 * (F(Ul) + F(Ur) - Aroe(Ul, Ur) * (Ur - Ul) + +Differentiating by the left and right states gives the left and right flux +jacobians. + + dF_Ul = 0.5 * (A(Ul) + Aroe(Ul, Ur)) + dF_Ur = 0.5 * (A(Ur) - Aroe(Ul, Ur)) + +In the above equations the Roe matrix Aroe is held constant during +differentiation. A represents the convective flux jacobian matrix. + */ +template +void fluxJacobian::ApproxRoeFluxJacobian(const T1 &left, const T2 &right, + const physics &phys, + const unitVec3dMag &area, + const bool &positive, + const input &inp) { + // left -- primitive variables from left side + // right -- primitive variables from right side + // phys -- physics model + // area -- face area vector + // positive -- flag to determine whether to add or subtract dissipation + // inp -- input variables + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // compute Roe averaged state + const auto roeAvg = RoeAveragedState(left, right); + + // compute Roe matrix + fluxJacobian roeMatrix; + roeMatrix.InvFluxJacobian(roeAvg, phys, area, inp); + + // compute convective flux jacobian + positive ? this->InvFluxJacobian(left, phys, area, inp) + : this->InvFluxJacobian(right, phys, area, inp); + + positive ? (*this) += roeMatrix : (*this) -= roeMatrix; +} + +// change of variable matrix going from primitive to conservative variables +// from Dwight +template +void fluxJacobian::DelprimitiveDelConservative(const T &state, + const physics &phys, + const input &inp) { + // state -- primitive variables + // phys -- physics models + // inp -- input variables + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + const auto t = state.Temperature(phys.EoS()); + const auto gammaMinusOne = + phys.Thermodynamic()->Gamma(t, state.MassFractions()) - 1.0; + const auto invRho = 1.0 / state.Rho(); + + *this = fluxJacobian(inp.NumFlowEquations(), inp.NumTurbEquations()); + + const auto ns = state.NumSpecies(); + for (auto ii = 0; ii < ns; ++ii) { + this->FlowJacobian(ii, ii) = 1.0; + + // assign species column + this->FlowJacobian(ns + 0, ii) = -invRho * state.U(); + this->FlowJacobian(ns + 1, ii) = -invRho * state.V(); + this->FlowJacobian(ns + 2, ii) = -invRho * state.W(); + this->FlowJacobian(ns + 3, ii) = + 0.5 * gammaMinusOne * state.Velocity().DotProd(state.Velocity()); + } + + // assign column 1 + this->FlowJacobian(ns, ns) = invRho; + this->FlowJacobian(ns + 3, ns) = -gammaMinusOne * state.U(); + + // assign column 2 + this->FlowJacobian(ns + 1, ns + 1) = invRho; + this->FlowJacobian(ns + 3, ns + 1) = -gammaMinusOne * state.V(); + + // assign column 3 + this->FlowJacobian(ns + 2, ns + 2) = invRho; + this->FlowJacobian(ns + 3, ns + 2) = -gammaMinusOne * state.W(); + + // assign column 4 + this->FlowJacobian(ns + 3, ns + 3) = gammaMinusOne; + + // turbulent jacobian here + if (inp.IsRANS()) { + this->TurbJacobian(0, 0) = invRho; + this->TurbJacobian(1, 1) = invRho; + } +} + +// approximate thin shear layer jacobian following implementation in Dwight. +// does not use any gradients +template +void fluxJacobian::ApproxTSLJacobian(const T &state, const double &lamVisc, + const double &turbVisc, const double &f1, + const physics &phys, + const unitVec3dMag &area, + const double &dist, const input &inp, + const bool &left, + const tensor &vGrad) { + // state -- primitive variables + // phys -- physics models + // area -- face area vector + // dist -- distance from cell center to cell center + // inp -- input variables + // left -- flag that is negative if using left state + // vGrad -- velocity gradient + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + *this = fluxJacobian(inp.NumFlowEquations(), inp.NumTurbEquations()); + + const auto t = state.Temperature(phys.EoS()); + const auto mu = phys.Transport()->NondimScaling() * lamVisc; + const auto mut = phys.Transport()->NondimScaling() * turbVisc; + const auto n = area.UnitVector(); + const auto velNorm = state.Velocity().DotProd(n); + const auto mf = state.MassFractions(); + const auto rho = state.Rho(); + const auto k = phys.Transport()->EffectiveConductivity(t, mf); + const auto kt = phys.Transport()->TurbConductivity( + mut, phys.Turbulence()->TurbPrandtlNumber(), t, phys.Thermodynamic(), mf); + + const auto tauNorm = TauNormal(vGrad, n, mu, mut, phys.Transport()); + + auto fac = left ? -1.0 : 1.0; + + constexpr auto third = 1.0 / 3.0; + const auto ns = state.NumSpecies(); + for (auto ii = 0; ii < ns; ++ii) { + for (auto jj = 0; jj < ns; ++jj) { + this->FlowJacobian(ii, jj) = phys.Diffusion()->DiffCoeff(mu, mut) * + (Kronecker(ii, jj) - mf[ii]) / + ((mu + mut) * rho); + } + // assign species column + const auto speciesEnthalpy = + this->FlowJacobian(ii, ii) * state.SpeciesEnthalpy(phys, ii); + this->FlowJacobian(ns + 3, ii) = + -(k + kt) * t / ((mu + mut) * rho) + speciesEnthalpy; + } + + // assign column 1 + this->FlowJacobian(ns + 0, ns) = third * n.X() * n.X() + 1.0; + this->FlowJacobian(ns + 1, ns) = third * n.X() * n.Y(); + this->FlowJacobian(ns + 2, ns) = third * n.X() * n.Z(); + this->FlowJacobian(ns + 3, ns) = fac * 0.5 * dist / (mu + mut) * tauNorm.X() + + third * n.X() * velNorm + state.U(); + + // assign column 2 + this->FlowJacobian(ns + 0, ns + 1) = third * n.Y() * n.X(); + this->FlowJacobian(ns + 1, ns + 1) = third * n.Y() * n.Y() + 1.0; + this->FlowJacobian(ns + 2, ns + 1) = third * n.Y() * n.Z(); + this->FlowJacobian(ns + 3, ns + 1) = + fac * 0.5 * dist / (mu + mut) * tauNorm.Y() + third * n.Y() * velNorm + + state.V(); + + // assign column 3 + this->FlowJacobian(ns + 0, ns + 2) = third * n.Z() * n.X(); + this->FlowJacobian(ns + 1, ns + 2) = third * n.Z() * n.Y(); + this->FlowJacobian(ns + 2, ns + 2) = third * n.Z() * n.Z() + 1.0; + this->FlowJacobian(ns + 3, ns + 2) = + fac * 0.5 * dist / (mu + mut) * tauNorm.Z() + third * n.Z() * velNorm + + state.W(); + + // assign column 4 + this->FlowJacobian(ns + 3, ns + 3) = (k + kt) / ((mu + mut) * rho); + + this->MultFlowJacobian(area.Mag() * (mu + mut) / dist); + + fluxJacobian prim2Cons; + prim2Cons.DelprimitiveDelConservative(state, phys, inp); + const auto product = this->FlowMatMult(prim2Cons); + std::copy(product.begin(), product.beginTurb(), this->begin()); + + // calculate turbulent jacobian if necessary + if (inp.IsRANS()) { + const auto turbProd = + fac * phys.Turbulence()->ViscousJacobian( + state, area, lamVisc, phys.Transport(), dist, turbVisc, f1); + std::copy(turbProd.begin(), turbProd.end(), this->beginTurb()); + // Don't need to multiply by prim2Cons b/c jacobian is already wrt + // conservative variables + } +} + +// --------------------------------------------------------------------------- +// non member functions +varArray RusanovScalarOffDiagonal(const primitiveView &, const varArrayView &, + const unitVec3dMag &, const double &, const double &, const double &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const bool &, const bool &); -genArray RusanovBlockOffDiagonal(const primVars &, const genArray &, - const unitVec3dMag &, - const double &, const double &, - const double &, const double &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const input &, const bool &, + const double &, const physics &, const bool &, + const bool &); +varArray RusanovBlockOffDiagonal(const primitiveView &, const varArrayView &, + const unitVec3dMag &, const double &, + const double &, const double &, const double &, + const physics &, const input &, const bool &, const tensor &); -genArray RoeOffDiagonal(const primVars &, const primVars &, - const genArray &, - const unitVec3dMag &, const double &, - const double &, const double &, - const double &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const bool &, +varArray RoeOffDiagonal(const primitiveView &, const primitiveView &, + const varArrayView &, const unitVec3dMag &, + const double &, const double &, const double &, + const double &, const physics &, const bool &, const bool &, const bool &); -genArray OffDiagonal(const primVars &, const primVars &, const genArray &, - const unitVec3dMag &, const double &, +varArray OffDiagonal(const primitiveView &, const primitiveView &, + const varArrayView &, const unitVec3dMag &, const double &, const double &, const double &, - const tensor &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const input &, - const bool &); + const double &, const tensor &, + const physics &, const input &, const bool &); #endif diff --git a/include/genArray.hpp b/include/genArray.hpp deleted file mode 100644 index d04e296..0000000 --- a/include/genArray.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) - - Aither is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Aither is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#ifndef ARRAYHEADERDEF // only if the macro ARRAYHEADERDEF is not defined - // execute these lines of code -#define ARRAYHEADERDEF // define the macro - -#include -#include "macros.hpp" - -using std::ostream; - -// forward class declarations -class uncoupledScalar; - -/*class to store an array of a fixed size equal to the number of variables -being solved for. This is useful because a vector of these will be -contiguous in memory. */ -class genArray { - double data_[NUMVARS]; - - public: - // constructor - genArray(const double &a, const double &b, const double &c, const double &d, - const double &e, const double &f, const double &g) - : data_{a, b, c, d, e, f, g} {} - genArray(const double &a, const double &b, const double &c, const double &d, - const double &e) - : genArray(a, b, c, d, e, 0.0, 0.0) {} - genArray() : genArray(0.0, 0.0, 0.0, 0.0, 0.0) {} - explicit genArray(const double &a) : genArray(a, a, a, a, a, a, a) {} - explicit genArray(const uncoupledScalar &a); - - // member functions - void Zero(); - double Sum(); - void SquareRoot(); - - // move constructor and assignment operator - genArray(genArray&&) noexcept = default; - genArray& operator=(genArray&&) noexcept = default; - - // copy constructor and assignment operator - genArray(const genArray&) = default; - genArray& operator=(const genArray&) = default; - - // operator overloads - const double & operator[](const int &r) const { return data_[r]; } - double & operator[](const int &r) { return data_[r]; } - - inline genArray & operator+=(const genArray &); - inline genArray & operator-=(const genArray &); - inline genArray & operator*=(const genArray &); - inline genArray & operator/=(const genArray &); - - inline genArray & operator+=(const double &); - inline genArray & operator-=(const double &); - inline genArray & operator*=(const double &); - inline genArray & operator/=(const double &); - - inline genArray operator+(const double &s) const { - auto lhs = *this; - return lhs += s; - } - inline genArray operator-(const double &s) const { - auto lhs = *this; - return lhs -= s; - } - inline genArray operator*(const double &s) const { - auto lhs = *this; - return lhs *= s; - } - inline genArray operator/(const double &s) const { - auto lhs = *this; - return lhs /= s; - } - - void GlobalReduceMPI(const int &, const int &); - - // destructor - ~genArray() noexcept {} -}; - -// function declarations -------------------------------------- -// operator overload for addition -genArray & genArray::operator+=(const genArray &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] += arr[rr]; - } - return *this; -} - -// operator overload for subtraction -genArray & genArray::operator-=(const genArray &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] -= arr[rr]; - } - return *this; -} - -// operator overload for elementwise multiplication -genArray & genArray::operator*=(const genArray &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] *= arr[rr]; - } - return *this; -} - -// operator overload for elementwise division -genArray & genArray::operator/=(const genArray &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] /= arr[rr]; - } - return *this; -} - -inline const genArray operator+(genArray lhs, const genArray &rhs) { - return lhs += rhs; -} - -inline const genArray operator-(genArray lhs, const genArray &rhs) { - return lhs -= rhs; -} - -inline const genArray operator*(genArray lhs, const genArray &rhs) { - return lhs *= rhs; -} - -inline const genArray operator/(genArray lhs, const genArray &rhs) { - return lhs /= rhs; -} - -// operator overloads for double ------------------------------------- -// operator overload for addition -genArray & genArray::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; - } - return *this; -} - -// operator overload for subtraction with a scalar -genArray & genArray::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; - } - return *this; -} - -// operator overload for elementwise multiplication -genArray & genArray::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; - } - return *this; -} - -// operator overload for elementwise division -genArray & genArray::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; - } - return *this; -} - -inline const genArray operator+(const double &lhs, genArray rhs) { - return rhs += lhs; -} - -inline const genArray operator-(const double &lhs, genArray rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs[rr] = lhs - rhs[rr]; - } - return rhs; -} - -inline const genArray operator*(const double &lhs, genArray rhs) { - return rhs *= lhs; -} - -inline const genArray operator/(const double &lhs, genArray rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs[rr] = lhs / rhs[rr]; - } - return rhs; -} - -ostream &operator<<(ostream &os, const genArray &); - -#endif diff --git a/include/ghostStates.hpp b/include/ghostStates.hpp new file mode 100644 index 0000000..e999278 --- /dev/null +++ b/include/ghostStates.hpp @@ -0,0 +1,46 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef GHOSTHEADERDEF +#define GHOSTHEADERDEF + +#include +#include "arrayView.hpp" +#include "tensor.hpp" +#include "primitive.hpp" + +using std::string; + +// forward class declarations +struct wallVars; +class input; + +primitive GetGhostState(const primitiveView &interior, const string &bcType, + const vector3d &areaVec, const double &wallDist, + const int &surf, const input &inputVars, const int &tag, + const physics &phys, wallVars &wVars, const int &layer, + const double &mu = 0.0, + const double &dt = 0.0, const primitive &stateN = {}, + const vector3d &pressGrad = {}, + const tensor &velGrad = {}, + const double &avgMach = 0.0, + const double &maxMach = 0.0); + +primitive ExtrapolateHoldMixture(const primitive &boundary, + const double &factor, + const primitiveView &interior); + +#endif \ No newline at end of file diff --git a/include/input.hpp b/include/input.hpp index 75f932d..d52c7ce 100644 --- a/include/input.hpp +++ b/include/input.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,6 +39,8 @@ class turbModel; class eos; class transport; class thermodynamic; +class diffusion; +class physics; class input { string simName_; // simulation name @@ -54,7 +56,8 @@ class input { double tRef_; // reference temperature double lRef_; // reference length double aRef_; // reference speed of sound - vector fluids_; // fluids in simulation + vector mixtureRef_; // reference mixture mass fractions + vector fluids_; // fluids in simulation vector bc_; // vector of boundary conditions for each // block string timeIntegration_; // time integration method @@ -83,8 +86,10 @@ class input { string thermodynamicModel_; // model for thermodynamics string equationOfState_; // model for equation of state string transportModel_; // model for viscous transport + string diffusionModel_; // model for species diffusion int restartFrequency_; // how often to output restart data int iterationStart_; // starting number for iterations + double schmidtNumber_; // schmidt number for species diffusion set outputVariables_; // variables to output set wallOutputVariables_; // wall variables to output @@ -98,6 +103,12 @@ class input { void CheckWallOutputVariables(); void CheckTurbulenceModel() const; void CheckSpecies() const; + void CheckNonreflecting() const; + unique_ptr AssignTurbulenceModel() const; + unique_ptr AssignEquationOfState() const; + unique_ptr AssignTransportModel() const; + unique_ptr AssignDiffusionModel(const double &) const; + unique_ptr AssignThermodynamicModel() const; public: // constructor @@ -125,9 +136,17 @@ class input { int IterationStart() const {return iterationStart_;} double RRef() const {return rRef_;} - double LRef() const {return lRef_;} + double LRef() const { return lRef_; } double TRef() const {return tRef_;} double ARef() const {return aRef_;} + vector MixtureRef() const { return mixtureRef_; } + vector RRefVec() const { + auto rhoVec = mixtureRef_; + for (auto &rho : rhoVec) { + rho *= rRef_; + } + return rhoVec; + } void NondimensionalizeStateData(const unique_ptr &); void NondimensionalizeFluid(); @@ -137,6 +156,7 @@ class input { string TimeIntegration() const { return timeIntegration_; } bool IsMultilevelInTime() const { return timeIntegration_ == "bdf2"; } + bool IsMultiSpecies() const { return this->NumSpecies() > 1; } bool NeedToStoreTimeN() const { return this->IsImplicit() || this->TimeIntegration() == "rk4"; } @@ -194,12 +214,14 @@ class input { string ThermodynamicModel() const {return thermodynamicModel_;} string EquationOfState() const {return equationOfState_;} string TransportModel() const {return transportModel_;} + string DiffusionModel() const {return diffusionModel_;} int NumVars() const {return vars_.size();} int NumVarsOutput() const {return outputVariables_.size();} int NumWallVarsOutput() const {return wallOutputVariables_.size();} int NumEquations() const; - int NumFlowEquations() const {return NUMFLOWVARS;} + int NumSpecies() const { return fluids_.size(); } + int NumFlowEquations() const {return 4 + this->NumSpecies();} int NumTurbEquations() const; void ReadInput(const int &); @@ -210,24 +232,28 @@ class input { bool IsRANS() const; bool IsLES() const; bool IsBlockMatrix() const; - + bool IsTimeAccurate() const { + return timeIntegration_ == "bdf2" || timeIntegration_ == "rk4" || + timeIntegration_ == "crankNicholson"; + } string OrderOfAccuracy() const; - unique_ptr AssignTurbulenceModel() const; - unique_ptr AssignEquationOfState(const unique_ptr &); - unique_ptr AssignTransportModel() const; - unique_ptr AssignThermodynamicModel() const; + physics AssignPhysicsModels() const; double ViscousCFLCoefficient() const; - int NumberGhostLayers() const; icState ICStateForBlock(const int &) const; const shared_ptr & BCData(const int &) const; - fluid Fluid(const int = 0) const; + const fluid &Fluid(const int &ii) const { return fluids_[ii]; } + void CheckSpecies(const vector &) const; + bool HaveSpecies(const string &) const; + int SpeciesIndex(const string &) const; bool IsWenoZ() const {return this->FaceReconstruction() == "wenoZ";} + double SchmidtNumber() const { return schmidtNumber_; } + // destructor ~input() noexcept {} }; diff --git a/include/inputStates.hpp b/include/inputStates.hpp index 03b89be..c03c246 100644 --- a/include/inputStates.hpp +++ b/include/inputStates.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ conditions and initial conditions. #include #include #include +#include #include #include #include "vector3d.hpp" @@ -33,9 +34,13 @@ conditions and initial conditions. using std::string; using std::vector; using std::map; +using std::set; using std::ifstream; using std::shared_ptr; +#define DEFAULT_TURB_INTENSITY 0.01 +#define DEFAULT_EDDY_VISC_RATIO 0.01 + // this is an abstract base class class inputState { int tag_; @@ -92,8 +97,12 @@ class inputState { virtual int NumberSpecies() const { return 0; } virtual string File() const { return "undefined"; } virtual bool IsFromFile() const { return false; } + virtual bool IsNonreflecting() const { return false; } + virtual const double LengthScale() const { return 0.0; } bool IsNondimensional() const { return nondimensional_; } void SetNondimensional(const bool &nd) {nondimensional_ = nd;} + virtual void Read(string &str) = 0; + virtual string Name() const { return "inputState"; } // destructor virtual ~inputState() noexcept {} @@ -101,21 +110,21 @@ class inputState { class icState : public inputState { - vector3d velocity_; - double density_; - double pressure_; - double turbIntensity_ = 0.01; // default values - double eddyViscRatio_ = 10.0; + vector3d velocity_ = {0.0, 0.0, 0.0}; + double density_ = 0.0; + double pressure_ = 0.0; + double turbIntensity_ = DEFAULT_TURB_INTENSITY; + double eddyViscRatio_ = DEFAULT_EDDY_VISC_RATIO; map massFractions_ = {{"air", 1.0}}; string file_ = "undefined"; bool specifiedTurbulence_ = false; bool specifiedMassFractions_ = false; bool specifiedFile_ = false; + string name_ = "icState"; public: // constructor - icState() : velocity_{0.0, 0.0, 0.0}, density_(0.0), pressure_(0.0) {} - explicit icState(string &str, const string name = "icState"); + icState() : inputState() {} // move constructor and assignment operator icState(icState&&) noexcept = default; @@ -126,7 +135,10 @@ class icState : public inputState { icState& operator=(const icState&) = default; // Member functions - const vector3d Velocity() const override {return velocity_;} + void Read(string &str) override; + string Name() const override { return name_; } + void UpdateName(const string &n) { name_ = n; } + const vector3d Velocity() const override { return velocity_; } const double Density() const override {return density_;} const double Pressure() const override {return pressure_;} const double TurbulenceIntensity() const override {return turbIntensity_;} @@ -139,6 +151,8 @@ class icState : public inputState { void Print(ostream &os) const override; void Nondimensionalize(const double &rRef, const double &tRef, const double &lRef, const double &aRef) override; + virtual void NondimensionalizeExtra(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) {} double MassFraction(const string &species) const override { return massFractions_.find(species)->second; } @@ -147,6 +161,9 @@ class icState : public inputState { void SetSpecifiedFile() { specifiedFile_ = true; } string File() const override { return file_; } bool IsFromFile() const override { return specifiedFile_; } + virtual void AssignExtraData(const string &s1, const string &s2) {} + virtual void ExtraDataChecks() const {} + virtual bool MatchesExtraData(const string &s1) const { return false; } // Destructor virtual ~icState() noexcept {} @@ -156,7 +173,7 @@ class icState : public inputState { class characteristic : public icState { public: // constructor - explicit characteristic(string &str) : icState(str, "characteristic") {} + characteristic() : icState() { this->UpdateName("characteristic"); } // move constructor and assignment operator characteristic(characteristic&&) noexcept = default; @@ -173,20 +190,59 @@ class characteristic : public icState { ~characteristic() noexcept {} }; +// data for inlet bc is same is for initial conditions +class inlet : public icState { + bool nonreflecting_ = false; + bool specifiedReflecting_ = false; + int nonreflectingCount_ = 0; + double lengthScale_ = 0.0; + int lengthCount_ = 0; + set extraData_ = {"nonreflecting", "lengthScale"}; + + public: + // constructor + inlet() : icState() { this->UpdateName("inlet"); } + + // move constructor and assignment operator + inlet(inlet&&) noexcept = default; + inlet& operator=(inlet&&) noexcept = default; + + // copy constructor and assignment operator + inlet(const inlet&) = default; + inlet& operator=(const inlet&) = default; + + // Member functions + void Print(ostream &os) const override; + bool IsNonreflecting() const override { return nonreflecting_; } + bool SpecifiedReflecting() const { return specifiedReflecting_; } + const double LengthScale() const override { return lengthScale_; } + void NondimensionalizeExtra(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; + void AssignExtraData(const string &s1, const string &s2) override; + void ExtraDataChecks() const override; + bool MatchesExtraData(const string &s1) const override { + return extraData_.find(s1) != extraData_.end(); + } + + // Destructor + ~inlet() noexcept {} +}; + class stagnationInlet : public inputState { - vector3d direction_; - double p0_; - double t0_; - double turbIntensity_ = 0.01; // default values - double eddyViscRatio_ = 10.0; + vector3d direction_ = {0.0, 0.0, 0.0}; + double p0_ = 0.0; + double t0_ = 0.0; + double turbIntensity_ = DEFAULT_TURB_INTENSITY; + double eddyViscRatio_ = DEFAULT_EDDY_VISC_RATIO; map massFractions_ = {{"air", 1.0}}; bool specifiedTurbulence_ = false; bool specifiedMassFractions_ = false; + string name_ = "stagnationInlet"; public: // constructor - explicit stagnationInlet(string &str); + stagnationInlet() : inputState() {} // move constructor and assignment operator stagnationInlet(stagnationInlet&&) noexcept = default; @@ -197,7 +253,9 @@ class stagnationInlet : public inputState { stagnationInlet& operator=(const stagnationInlet&) = default; // Member functions - const vector3d Direction() const override {return direction_;} + void Read(string &str) override; + string Name() const override { return name_; } + const vector3d Direction() const override { return direction_; } const double StagnationPressure() const override {return p0_;} const double StagnationTemperature() const override {return t0_;} const double TurbulenceIntensity() const override {return turbIntensity_;} @@ -221,11 +279,15 @@ class stagnationInlet : public inputState { class pressureOutlet : public inputState { - double pressure_; + double pressure_ = 0.0; + bool nonreflecting_ = false; + bool specifiedReflecting_ = false; + double lengthScale_ = 0.0; + string name_ = "pressureOutlet"; public: // constructor - explicit pressureOutlet(string &str, const string name = "pressureOutlet"); + pressureOutlet() : inputState() {} // move constructor and assignment operator pressureOutlet(pressureOutlet&&) noexcept = default; @@ -236,7 +298,12 @@ class pressureOutlet : public inputState { pressureOutlet& operator=(const pressureOutlet&) = default; // Member functions + void Read(string &str) override; + string Name() const override { return name_; } const double Pressure() const override {return pressure_;} + bool IsNonreflecting() const override { return nonreflecting_; } + bool SpecifiedReflecting() const { return specifiedReflecting_; } + const double LengthScale() const override { return lengthScale_; } void Print(ostream &os) const override; void Nondimensionalize(const double &rRef, const double &tRef, const double &lRef, const double &aRef) override; @@ -250,7 +317,7 @@ class pressureOutlet : public inputState { class supersonicInflow : public icState { public: // constructor - explicit supersonicInflow(string &str) : icState(str, "supersonicInflow") {} + supersonicInflow() : icState() { this->UpdateName("supersonicInflow"); } // move constructor and assignment operator supersonicInflow(supersonicInflow&&) noexcept = default; @@ -268,73 +335,6 @@ class supersonicInflow : public icState { }; -// data for subsonicOutflow bc is same is for pressureOutlet -class subsonicOutflow : public pressureOutlet { - public: - // constructor - explicit subsonicOutflow(string &str) : - pressureOutlet(str, "subsonicOutflow") {} - - // move constructor and assignment operator - subsonicOutflow(subsonicOutflow&&) noexcept = default; - subsonicOutflow& operator=(subsonicOutflow&&) noexcept = default; - - // copy constructor and assignment operator - subsonicOutflow(const subsonicOutflow&) = default; - subsonicOutflow& operator=(const subsonicOutflow&) = default; - - // Member functions - void Print(ostream &os) const override; - - // Destructor - ~subsonicOutflow() noexcept {} -}; - - -class subsonicInflow : public inputState { - vector3d velocity_; - double density_; - double turbIntensity_ = 0.01; // default values - double eddyViscRatio_ = 10.0; - map massFractions_ = {{"air", 1.0}}; - bool specifiedTurbulence_ = false; - bool specifiedMassFractions_ = false; - - public: - // constructor - explicit subsonicInflow(string &str); - - // move constructor and assignment operator - subsonicInflow(subsonicInflow&&) noexcept = default; - subsonicInflow& operator=(subsonicInflow&&) noexcept = default; - - // copy constructor and assignment operator - subsonicInflow(const subsonicInflow&) = default; - subsonicInflow& operator=(const subsonicInflow&) = default; - - // Member functions - const vector3d Velocity() const override {return velocity_;} - const double Density() const override {return density_;} - const double TurbulenceIntensity() const override {return turbIntensity_;} - const double EddyViscosityRatio() const override {return eddyViscRatio_;} - const bool SpecifiedTurbulence() const {return specifiedTurbulence_;} - void SetSpecifiedTurbulence() {specifiedTurbulence_ = true;} - const bool SpecifiedMassFractions() const {return specifiedMassFractions_;} - void SetSpecifiedMassFractions() {specifiedMassFractions_ = true;} - int NumberSpecies() const override {return massFractions_.size();} - void Print(ostream &os) const override; - void Nondimensionalize(const double &rRef, const double &tRef, - const double &lRef, const double &aRef) override; - double MassFraction(const string &species) const override { - return massFractions_.find(species)->second; - } - map MassFractions() const override { return massFractions_; } - - // Destructor - ~subsonicInflow() noexcept {} -}; - - class viscousWall : public inputState { // default conditions for stationary adiabatic wall vector3d velocity_ = {0.0, 0.0, 0.0}; @@ -345,10 +345,10 @@ class viscousWall : public inputState { string wallTreatment_ = "lowRe"; bool specifiedTemperature_ = false; bool specifiedHeatFlux_ = false; + string name_ = "viscousWall"; public: // constructor - explicit viscousWall(string &str); viscousWall() : inputState() {} // move constructor and assignment operator @@ -360,7 +360,9 @@ class viscousWall : public inputState { viscousWall& operator=(const viscousWall&) = default; // Member functions - const vector3d Velocity() const override {return velocity_;} + void Read(string &str) override; + string Name() const override { return name_; } + const vector3d Velocity() const override { return velocity_; } const double Temperature() const override {return temperature_;} const double HeatFlux() const override {return heatFlux_;} const double VonKarmen() const override {return vonKarmen_;} @@ -392,10 +394,11 @@ class periodic : public inputState { vector3d point_ = {0.0, 0.0, 0.0}; double rotation_ = 0.0; int endTag_ = -1; + string name_ = "periodic"; public: // constructor - explicit periodic(string &str); + periodic() : inputState() {} // move constructor and assignment operator periodic(periodic&&) noexcept = default; @@ -406,6 +409,8 @@ class periodic : public inputState { periodic& operator=(const periodic&) = default; // Member functions + void Read(string &str) override; + string Name() const override { return name_; } bool IsTranslation() const override { return translation_ != vector3d(0.0, 0.0, 0.0); } @@ -430,11 +435,10 @@ class periodic : public inputState { ostream &operator<<(ostream &, const inputState &); ostream &operator<<(ostream &, const icState &); ostream &operator<<(ostream &, const characteristic &); +ostream &operator<<(ostream &, const inlet &); ostream &operator<<(ostream &, const stagnationInlet &); ostream &operator<<(ostream &, const pressureOutlet &); ostream &operator<<(ostream &, const supersonicInflow &); -ostream &operator<<(ostream &, const subsonicOutflow &); -ostream &operator<<(ostream &, const subsonicInflow &); ostream &operator<<(ostream &, const viscousWall &); ostream &operator<<(ostream &, const periodic &); @@ -442,6 +446,7 @@ ostream &operator<<(ostream &, const periodic &); vector Tokenize(string, const string &, const unsigned int = 0); string Trim(const string &, const string & = " \t\r\n"); vector3d ReadVector(const string &); +vector ReadVectorXd(const string &); map ReadMassFractions(const string &); vector ReadICList(ifstream &, string &); vector ReadStringList(ifstream &, string &); diff --git a/include/inviscidFlux.hpp b/include/inviscidFlux.hpp index 5d2a303..04a21d3 100644 --- a/include/inviscidFlux.hpp +++ b/include/inviscidFlux.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +23,12 @@ #include // cout #include // unique_ptr #include "vector3d.hpp" // vector3d -#include "macros.hpp" +#include "varArray.hpp" +#include "primitive.hpp" +#include "utility.hpp" +#include "eos.hpp" +#include "thermodynamic.hpp" +#include "turbulence.hpp" using std::vector; using std::string; @@ -36,31 +41,37 @@ using std::unique_ptr; // forward class declaration class eos; class thermodynamic; -class primVars; -class genArray; +class conserved; class squareMatrix; class turbModel; -class inviscidFlux { - double data_[NUMVARS]; // rho dot velocity vector - // rho dot velocity vector * u-velocity + pressure * i-dir-vector - // rho dot velocity vector * v-velocity + pressure * j-dir-vector - // rho dot velocity vector * w-velocity + pressure * k-dir-vector - // rho dot velocity vector * enthalpy - +class inviscidFlux : public varArray { // private member functions - void ConstructFromPrim(const primVars &, const unique_ptr &, - const unique_ptr &, + template + void ConstructFromPrim(const T &, const physics &phys, const vector3d &); public: // constructors - inviscidFlux() : data_{0.0} {} - inviscidFlux(const primVars &, const unique_ptr &, - const unique_ptr &, const vector3d &); - inviscidFlux(const genArray &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const vector3d &); + inviscidFlux() : varArray() {} + inviscidFlux(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies) {} + template + inviscidFlux(const T &state, const physics &phys, + const vector3d &area) + : inviscidFlux(state.Size(), state.NumSpecies()) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + this->ConstructFromPrim(state, phys, area); + } + inviscidFlux(const conserved &cons, const physics &phys, + const vector3d &area) + : inviscidFlux(cons.Size(), cons.NumSpecies()) { + // convert conserved variables to primitive variables + const primitive state(cons, phys); + this->ConstructFromPrim(state, phys, area); + } // move constructor and assignment operator inviscidFlux(inviscidFlux&&) noexcept = default; @@ -71,189 +82,515 @@ class inviscidFlux { inviscidFlux& operator=(const inviscidFlux&) = default; // member functions - double RhoVel() const { return data_[0]; } - double RhoVelU() const { return data_[1]; } - double RhoVelV() const { return data_[2]; } - double RhoVelW() const { return data_[3]; } - double RhoVelH() const { return data_[4]; } - double RhoVelK() const { return data_[5]; } - double RhoVelO() const { return data_[6]; } - - void RoeFlux(const inviscidFlux&, const genArray&); - void AUSMFlux(const primVars &, const primVars &, const unique_ptr &, - const unique_ptr &, const vector3d &, - const double &, const double &, const double &, const double &, - const double &); - - inline inviscidFlux & operator+=(const inviscidFlux &); - inline inviscidFlux & operator-=(const inviscidFlux &); - inline inviscidFlux & operator*=(const inviscidFlux &); - inline inviscidFlux & operator/=(const inviscidFlux &); - - inline inviscidFlux & operator+=(const double &); - inline inviscidFlux & operator-=(const double &); - inline inviscidFlux & operator*=(const double &); - inline inviscidFlux & operator/=(const double &); - - inline inviscidFlux operator+(const double &s) const { - auto lhs = *this; - return lhs += s; - } - inline inviscidFlux operator-(const double &s) const { - auto lhs = *this; - return lhs -= s; - } - inline inviscidFlux operator*(const double &s) const { - auto lhs = *this; - return lhs *= s; - } - inline inviscidFlux operator/(const double &s) const { - auto lhs = *this; - return lhs /= s; - } - - friend inline const inviscidFlux operator-(const double &lhs, - inviscidFlux rhs); - friend inline const inviscidFlux operator/(const double &lhs, - inviscidFlux rhs); - - genArray ConvertToGenArray() const; + const double & MassN(const int &ii) const { return this->SpeciesN(ii); } + void RoeFlux(const inviscidFlux&, const varArray&); + template + void AUSMFlux(const T1 &, const T2 &, const physics &phys, + const vector3d &, const double &, const double &, + const double &, const double &, const double &); // destructor ~inviscidFlux() noexcept {} }; -// function definitions -// function to calculate Roe flux with entropy fix -inviscidFlux RoeFlux(const primVars &, const primVars &, - const unique_ptr &, const unique_ptr &, - const vector3d &); -inviscidFlux AUSMFlux(const primVars &, const primVars &, - const unique_ptr &, - const unique_ptr &, - const vector3d &); -inviscidFlux InviscidFlux(const primVars &, const primVars &, - const unique_ptr &, - const unique_ptr &, - const vector3d &, const string &); -inviscidFlux RusanovFlux(const primVars &, const primVars &, - const unique_ptr &, - const unique_ptr &, - const vector3d &, const bool &); - -// function to calculate Roe flux with entropy fix for implicit methods -void ApproxRoeFluxJacobian(const primVars &, const primVars &, - const unique_ptr &, const vector3d &, - double &, squareMatrix &, squareMatrix &); - -genArray ConvectiveFluxUpdate(const primVars &, const primVars &, - const unique_ptr &, - const unique_ptr &, - const vector3d &); - -// operator overload for addition -inviscidFlux & inviscidFlux::operator+=(const inviscidFlux &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] += arr.data_[rr]; +// ---------------------------------------------------------------------------- +// member functions + +// flux is a 3D flux in the normal direction of the given face +/* + +F = [rho * vel (dot) area + rho * vel (dot) area * velx + P * areax + rho * vel (dot) area * vely + P * areay + rho * vel (dot) area * velz + P * areaz + rho * vel (dot) area * H + rho * vel (dot) area * k + rho * vel (dot) area * w] + +rho -- density +vel -- velocity vector (3D) +area -- area vector (3D) +P -- pressure +H -- enthalpy +velx, vely, velz -- velocity components +areax, areay, areaz -- area components +k -- turbulence kinetic energy +w -- specific turbulent dissipation + +Constructor is put in a private member function because identical code is +used for constructing from primitive variables and conservative variables +once the conservative variables have been changed to primitive variables. +The C++11 way of delegating constructors is not used because the primitive +class is not fully defined in the inviscidFlux.hpp header. This way both +constructors (primitive version and conserved version) can call this function +to avoid code duplication. +*/ +template +void inviscidFlux::ConstructFromPrim(const T &state, + const physics &phys, + const vector3d &normArea) { + // state -- primitive variables + // eqnState -- equation of state + // normArea -- unit area vector of face + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + const auto vel = state.Velocity(); + const auto velNorm = vel.DotProd(normArea); + + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + (*this)[ii] = state.RhoN(ii) * velNorm; + } + const auto rho = state.Rho(); + (*this)[this->MomentumXIndex()] = + rho * velNorm * vel.X() + state.P() * normArea.X(); + (*this)[this->MomentumYIndex()] = + rho * velNorm * vel.Y() + state.P() * normArea.Y(); + (*this)[this->MomentumZIndex()] = + rho * velNorm * vel.Z() + state.P() * normArea.Z(); + (*this)[this->EnergyIndex()] = + rho * velNorm * state.Enthalpy(phys); + + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[this->TurbulenceIndex() + ii] = + rho * velNorm * state.TurbulenceN(ii); } - return *this; } -// operator overload for subtraction with a scalar -inviscidFlux & inviscidFlux::operator-=(const inviscidFlux &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] -= arr.data_[rr]; +template +void inviscidFlux::AUSMFlux(const T1 &left, const T2 &right, + const physics &phys, const vector3d &area, + const double &sos, const double &mPlusLBar, + const double &mMinusRBar, const double &pPlus, + const double &pMinus) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // calculate left flux + const auto vl = mPlusLBar * sos; + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + (*this)[ii] = left.RhoN(ii) * vl; } - return *this; -} -// operator overload for elementwise multiplication -inviscidFlux & inviscidFlux::operator*=(const inviscidFlux &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] *= arr.data_[rr]; + // get indices + auto imx = this->MomentumXIndex(); + auto imy = this->MomentumYIndex(); + auto imz = this->MomentumZIndex(); + auto ie = this->EnergyIndex(); + auto it = this->TurbulenceIndex(); + + auto rhoL = left.Rho(); + (*this)[imx] = rhoL * vl * left.U() + pPlus * left.P() * area.X(); + (*this)[imy] = rhoL * vl * left.V() + pPlus * left.P() * area.Y(); + (*this)[imz] = rhoL * vl * left.W() + pPlus * left.P() * area.Z(); + (*this)[ie] = rhoL * vl * left.Enthalpy(phys); + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[it + ii] = rhoL * vl * left.TurbulenceN(ii); } - return *this; -} -// operator overload for elementwise division -inviscidFlux & inviscidFlux::operator/=(const inviscidFlux &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] /= arr.data_[rr]; + // calculate right flux (add contribution) + const auto vr = mMinusRBar * sos; + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + (*this)[ii] += right.RhoN(ii) * vr; + } + auto rhoR = right.Rho(); + (*this)[imx] += rhoR * vr * right.U() + pMinus * right.P() * area.X(); + (*this)[imy] += rhoR * vr * right.V() + pMinus * right.P() * area.Y(); + (*this)[imz] += rhoR * vr * right.W() + pMinus * right.P() * area.Z(); + (*this)[ie] += rhoR * vr * right.Enthalpy(phys); + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[it + ii] += rhoR * vr * right.TurbulenceN(ii); } - return *this; } -inline const inviscidFlux operator+(inviscidFlux lhs, const inviscidFlux &rhs) { - return lhs += rhs; -} -inline const inviscidFlux operator-(inviscidFlux lhs, const inviscidFlux &rhs) { - return lhs -= rhs; -} +// ---------------------------------------------------------------------------- +// function definitions +/* Function to calculate inviscid flux using Roe's approximate Riemann solver. +The function takes in the primitive varibles constructed +from the left and right states, an equation of state, a face area vector, and +outputs the inviscid flux as well as the maximum wave speed. +The function uses Harten's entropy fix to correct wave speeds near 0 and near +sonic. +__________________________________________ +| | Ul|Ur | | +| | | | | +| Ui-1 | Ui Ua Ui+1 | Ui+2 | +| | | | | +| | | | | +|_________|_________|__________|_________| + +In the diagram above, Ul and Ur represent the reconstructed states, which for +the MUSCL scheme (1st and 2nd order) come from the stencil shown +above. Ua represents the average state at the face at which the flux will be +calculated. In this case it is a Roe average. Once the average +state has been calculated, the Roe flux can be calculated using the following +equation. + +F = 1/2 * (Fl + Fr - D) + +F represents the calculated Roe flux at the given face. Fl is the inviscid flux +calculated from the reconstructed state Ul. Fr is the inviscid +flux calculated from the reconstructed state Ur. D is the dissipation term which +is calculated using the Roe averaged state, as well as the +eigen values and eigen vectors resulting from the Roe linearization. + +D = A * (Ur - Ul) = T * L * T^-1 * (Ur - Ul) = T * L * (Cr - Cl) + +A is the linearized Roe matrix. It is equal to the convective flux jacobian +(dF/dU) calculated with the Roe averaged state. The linearization +essentially states that the flux jacobian (which is the change in flux over +change in state) mulitplied by the change in state is equal to the +change in flux. The change in flux is then added to the average of the physical +right and left fluxes (central difference). The Roe matrix, A, +can be diagonalized where T and T^-1 are the right and left eigenvectors +respectively and L is the eigenvalues. T^-1 multiplied by the change in +state results in the change in characteristic wave amplitude (Cr - Cl), or wave +strength. In its final form (right most) T represents the +characteristic waves, L represents the wave speeds, and (Cr - Cl) represents the +wave strength across the face. + +*/ +template +inviscidFlux RoeFlux(const T1 &left, const T2 &right, const physics &phys, + const vector3d &n) { + // left -- primitive variables from left + // right -- primitive variables from right + // phys -- physics models + // n -- norm area vector of face + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // compute Rho averaged quantities + // Roe averaged state + const auto roe = RoeAveragedState(left, right); + // Roe averaged total enthalpy + const auto hR = roe.Enthalpy(phys); + // Roe averaged speed of sound + const auto aR = roe.SoS(phys); + // Roe averaged density + const auto rhoR = roe.Rho(); + // Roe velocity dotted with normalized area vector + const auto velNormR = roe.Velocity().DotProd(n); + // Roe mass fractions + const auto mfR = roe.MassFractions(); + // Delta between right and left states + const auto delta = right - left; + // normal velocity difference between left and right states + const auto normVelDiff = delta.Velocity().DotProd(n); + + // calculate wave strengths (Cr - Cl) + vector waveStrength(4 + left.NumTurbulence()); + waveStrength[0] = (delta.P() - rhoR * aR * normVelDiff) / (2.0 * aR * aR); + waveStrength[1] = delta.Rho() - delta.P() / (aR * aR); + waveStrength[2] = (delta.P() + rhoR * aR * normVelDiff) / (2.0 * aR * aR); + waveStrength[3] = rhoR; + for (auto ii = 0; ii < left.NumTurbulence(); ++ii) { + waveStrength[4 + ii] = rhoR * delta.TurbulenceN(ii) + + roe.TurbulenceN(ii) * delta.Rho() - + delta.P() * roe.TurbulenceN(ii) / (aR * aR); + } -inline const inviscidFlux operator*(inviscidFlux lhs, const inviscidFlux &rhs) { - return lhs *= rhs; -} + // calculate absolute value of wave speeds (L) + vector waveSpeed(4 + left.NumTurbulence()); + waveSpeed[0] = fabs(velNormR - aR); // left moving acoustic wave speed + waveSpeed[1] = fabs(velNormR); // entropy wave speed + waveSpeed[2] = fabs(velNormR + aR); // right moving acoustic wave speed + waveSpeed[3] = fabs(velNormR); // shear wave speed + for (auto ii = 0; ii < left.NumTurbulence(); ++ii) { + waveSpeed[4 + ii] = fabs(velNormR); // turbulent eqn wave speed + } -inline const inviscidFlux operator/(inviscidFlux lhs, const inviscidFlux &rhs) { - return lhs /= rhs; -} + // calculate entropy fix (Harten) and adjust wave speeds if necessary + // default setting for entropy fix to kick in + constexpr auto entropyFix = 0.1; -// operator overloads for double ------------------------------------- -// operator overload for addition -inviscidFlux & inviscidFlux::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; + if (waveSpeed[0] < entropyFix) { + waveSpeed[0] = + 0.5 * (waveSpeed[0] * waveSpeed[0] / entropyFix + entropyFix); + } + if (waveSpeed[2] < entropyFix) { + waveSpeed[2] = + 0.5 * (waveSpeed[2] * waveSpeed[2] / entropyFix + entropyFix); } - return *this; -} -// operator overload for subtraction with a scalar -inviscidFlux & inviscidFlux::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; + // calculate right eigenvectors (T) + // get indices + const auto imx = left.MomentumXIndex(); + const auto imy = left.MomentumYIndex(); + const auto imz = left.MomentumZIndex(); + const auto ie = left.EnergyIndex(); + const auto it = left.TurbulenceIndex(); + + // calculate eigenvector due to left acoustic wave + varArray lAcousticEigV(left.Size(), left.NumSpecies()); + for (auto ii = 0; ii < lAcousticEigV.NumSpecies(); ++ii) { + lAcousticEigV[ii] = mfR[ii]; + } + lAcousticEigV[imx] = roe.U() - aR * n.X(); + lAcousticEigV[imy] = roe.V() - aR * n.Y(); + lAcousticEigV[imz] = roe.W() - aR * n.Z(); + lAcousticEigV[ie] = hR - aR * velNormR; + for (auto ii = 0; ii < lAcousticEigV.NumTurbulence(); ++ii) { + lAcousticEigV[it + ii] = roe.TurbulenceN(ii); } - return *this; -} -// operator overload for elementwise multiplication -inviscidFlux & inviscidFlux::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; + // calculate eigenvector due to entropy wave + varArray entropyEigV(left.Size(), left.NumSpecies()); + for (auto ii = 0; ii < entropyEigV.NumSpecies(); ++ii) { + entropyEigV[ii] = 1.0; + } + // non-species values are repated for number of species + entropyEigV[imx] = roe.U() * entropyEigV.NumSpecies(); + entropyEigV[imy] = roe.V() * entropyEigV.NumSpecies(); + entropyEigV[imz] = roe.W() * entropyEigV.NumSpecies(); + entropyEigV[ie] = 0.5 * roe.Velocity().MagSq() * entropyEigV.NumSpecies(); + // turbulence values are zero + + // calculate eigenvector due to right acoustic wave + varArray rAcousticEigV(left.Size(), left.NumSpecies()); + for (auto ii = 0; ii < rAcousticEigV.NumSpecies(); ++ii) { + rAcousticEigV[ii] = mfR[ii]; + } + rAcousticEigV[imx] = roe.U() + aR * n.X(); + rAcousticEigV[imy] = roe.V() + aR * n.Y(); + rAcousticEigV[imz] = roe.W() + aR * n.Z(); + rAcousticEigV[ie] = hR + aR * velNormR; + for (auto ii = 0; ii < rAcousticEigV.NumTurbulence(); ++ii) { + rAcousticEigV[it + ii] = roe.TurbulenceN(ii); } - return *this; -} -// operator overload for elementwise division -inviscidFlux & inviscidFlux::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; + // calculate eigenvector due to shear wave + varArray shearEigV(left.Size(), left.NumSpecies()); + // species values are zero + shearEigV[imx] = delta.U() - normVelDiff * n.X(); + shearEigV[imy] = delta.V() - normVelDiff * n.Y(); + shearEigV[imz] = delta.W() - normVelDiff * n.Z(); + shearEigV[ie] = + roe.Velocity().DotProd(delta.Velocity()) - velNormR * normVelDiff; + // turbulence values are zero + + // calculate eigenvector due to turbulent equation 1 + varArray tkeEigV(left.Size(), left.NumSpecies()); + if (tkeEigV.HasTurbulenceData()) { + tkeEigV[it] = 1.0; } - return *this; -} -inline const inviscidFlux operator+(const double &lhs, inviscidFlux rhs) { - return rhs += lhs; -} + // calculate eigenvector due to turbulent equation 2 + varArray omgEigV(left.Size(), left.NumSpecies()); + if (omgEigV.HasTurbulenceData() && omgEigV.NumTurbulence() > 1) { + omgEigV[it + 1] = 1.0; + } -inline const inviscidFlux operator-(const double &lhs, inviscidFlux rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs - rhs.data_[rr]; + // calculate dissipation term ( eigenvector * wave speed * wave strength) + varArray dissipation(left.Size(), left.NumSpecies()); + for (auto ii = 0; ii < dissipation.Size(); ++ii) { + // contribution from left acoustic wave + // contribution from entropy wave + // contribution from right acoustic wave + // contribution from shear wave + // contribution from turbulent wave 1 + // contribution from turbulent wave 2 + dissipation[ii] = waveSpeed[0] * waveStrength[0] * lAcousticEigV[ii] + + waveSpeed[1] * waveStrength[1] * entropyEigV[ii] + + waveSpeed[2] * waveStrength[2] * rAcousticEigV[ii] + + waveSpeed[3] * waveStrength[3] * shearEigV[ii]; + if (dissipation.HasTurbulenceData()) { + dissipation[ii] += waveSpeed[4] * waveStrength[4] * tkeEigV[ii] + + waveSpeed[5] * waveStrength[5] * omgEigV[ii]; + } } - return rhs; + + // calculate left/right physical flux + inviscidFlux leftFlux(left, phys, n); + inviscidFlux rightFlux(right, phys, n); + + // calculate numerical Roe flux + leftFlux.RoeFlux(rightFlux, dissipation); + + return leftFlux; } -inline const inviscidFlux operator*(const double &lhs, inviscidFlux rhs) { - return rhs *= lhs; +/* Function to calculate the AUSMPW+ flux as described in "Accurate Compuations + of Hypersonic Flows Using AUSMPW+ Scheme and Shock-Aligned Grid Technique". + by Kim, Kim, & Rho. AIAA 1998. Unlike the Roe scheme, this flux scheme is an + example of flux vector splitting instead of flux difference splitting. + Although more dissipative, it has shown good performance in the high speed + regime where the Roe scheme can suffer from carbuncle problems. The flux is + split into the convective and pressure terms, which are then split based on + the mach number and pressure. The flux discretization is shown below. + + F = M^+_l * c * F_cl + M^-_r * c * F_cr + P^+_l * P_l + P^-_r * P_r +*/ +template +inviscidFlux AUSMFlux(const T1 &left, const T2 &right, const physics &phys, + const vector3d &area) { + // left -- primitive variables from left + // right -- primitive variables from right + // phys -- physics models + // area -- norm area vector of face + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // calculate average specific enthalpy normal to face + const auto velNormL = left.Velocity().DotProd(area); + const auto velTanSqL = (left.Velocity() - velNormL * area).MagSq(); + const auto velNormR = right.Velocity().DotProd(area); + const auto velTanSqR = (right.Velocity() - velNormR * area).MagSq(); + const auto hnl = left.Enthalpy(phys) - 0.5 * velTanSqL; + const auto hnr = right.Enthalpy(phys) - 0.5 * velTanSqR; + const auto hn = 0.5 * (hnl + hnr); + + // calculate c* from Kim, Kim, Rho 1998 + const auto mfl = left.MassFractions(); + const auto mfr = right.MassFractions(); + vector mf(mfl.size()); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = 0.5 * (mfl[ii] + mfr[ii]); + } + const auto tl = left.Temperature(phys.EoS()); + const auto tr = right.Temperature(phys.EoS()); + const auto t = 0.5 * (tl + tr); + const auto gamma = phys.Thermodynamic()->Gamma(t, mf); + const auto sosStar = sqrt(2.0 * hn * (gamma - 1.0) / (gamma + 1.0)); + + // calculate speed of sound on face c_1/2 from Kim, Kim, Rho 1998 + const auto vel = 0.5 * (velNormL + velNormR); + auto sos = sosStar; + if (vel < 0.0) { + sos = sosStar * sosStar / std::max(velNormR, sosStar); + } else if (vel > 0.0) { + sos = sosStar * sosStar / std::max(velNormL, sosStar); + } + + // calculate left/right mach numbers + const auto ml = velNormL / sos; + const auto mr = velNormR / sos; + + // calculate split mach number and pressure terms + const auto mPlusL = + fabs(ml) <= 1.0 ? 0.25 * pow(ml + 1.0, 2.0) : 0.5 * (ml + fabs(ml)); + const auto mMinusR = + fabs(mr) <= 1.0 ? -0.25 * pow(mr - 1.0, 2.0) : 0.5 * (mr - fabs(mr)); + const auto pPlus = fabs(ml) <= 1.0 ? 0.25 * pow(ml + 1.0, 2.0) * (2.0 - ml) + : 0.5 * (1.0 + Sign(ml)); + const auto pMinus = fabs(mr) <= 1.0 ? 0.25 * pow(mr - 1.0, 2.0) * (2.0 + mr) + : 0.5 * (1.0 - Sign(mr)); + + // calculate pressure weighting terms + const auto ps = pPlus * left.P() + pMinus * right.P(); + const auto w = + 1.0 - pow(std::min(left.P() / right.P(), right.P() / left.P()), 3.0); + const auto fl = fabs(ml) < 1.0 ? left.P() / ps - 1.0 : 0.0; + const auto fr = fabs(mr) < 1.0 ? right.P() / ps - 1.0 : 0.0; + + // calculate final split properties + const auto mavg = mPlusL + mMinusR; + const auto mPlusLBar = mavg >= 0.0 + ? mPlusL + mMinusR * ((1.0 - w) * (1.0 + fr) - fl) + : mPlusL * w * (1.0 + fl); + const auto mMinusRBar = + mavg >= 0.0 ? mMinusR * w * (1.0 + fr) + : mMinusR + mPlusL * ((1.0 - w) * (1.0 + fl) - fr); + + inviscidFlux ausm(left.Size(), left.NumSpecies()); + ausm.AUSMFlux(left, right, phys, area, sos, mPlusLBar, mMinusRBar, pPlus, + pMinus); + return ausm; } -inline const inviscidFlux operator/(const double &lhs, inviscidFlux rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs / rhs.data_[rr]; +template +inviscidFlux InviscidFlux(const T1 &left, const T2 &right, + const physics &phys, + const vector3d &area, const string &flux) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + inviscidFlux invFlux; + if (flux == "roe") { + invFlux = RoeFlux(left, right, phys, area); + } else if (flux == "ausm") { + invFlux = AUSMFlux(left, right, phys, area); + } else { + cerr << "ERROR: inviscid flux type " << flux << " is not recognized!" + << endl; + cerr << "Choose 'roe' or 'ausm'" << endl; + exit(EXIT_FAILURE); } - return rhs; + return invFlux; } -ostream &operator<<(ostream &os, const inviscidFlux &); +template +inviscidFlux RusanovFlux(const T1 &left, const T2 &right, + const physics &phys, + const vector3d &areaNorm, + const bool &positive) { + // left -- primitive variables from left + // right -- primitive variables from right + // phys -- physics models + // areaNorm -- norm area vector of face + // positive -- flag that is positive to add spectral radius + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // calculate maximum spectral radius + const auto leftSpecRad = + fabs(left.Velocity().DotProd(areaNorm)) + left.SoS(phys); + const auto rightSpecRad = + fabs(right.Velocity().DotProd(areaNorm)) + right.SoS(phys); + const auto fac = positive ? -1.0 : 1.0; + const auto specRad = fac * std::max(leftSpecRad, rightSpecRad); + + // calculate left/right physical flux + inviscidFlux leftFlux(left, phys, areaNorm); + inviscidFlux rightFlux(right, phys, areaNorm); + + return 0.5 * (leftFlux + rightFlux - specRad); +} + +// function to take in the primitive variables, equation of state, face area +// vector, and primitive variable update and calculate the change in the +// convective flux +template +inviscidFlux ConvectiveFluxUpdate(const T1 &state, + const T2 &stateUpdate, + const physics &phys, + const vector3d &normArea) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // get inviscid flux of old state + const inviscidFlux oldFlux(state, phys, normArea); + // get updated inviscid flux + const inviscidFlux newFlux(stateUpdate, phys, normArea); + + // calculate difference in flux + return newFlux - oldFlux; +} #endif diff --git a/include/kdtree.hpp b/include/kdtree.hpp index 6791fe5..efbaa8c 100644 --- a/include/kdtree.hpp +++ b/include/kdtree.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/limiter.hpp b/include/limiter.hpp new file mode 100644 index 0000000..7cae718 --- /dev/null +++ b/include/limiter.hpp @@ -0,0 +1,31 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef LIMITERHEADERDEF +#define LIMITERHEADERDEF + +/* This header contains functions to limit the primitive variables during + * reconstruction + */ + +// forward class declarations +class primitive; + +primitive LimiterVanAlbada(const primitive &); +primitive LimiterMinmod(const primitive &); +primitive LimiterNone(const int &, const int &); + +#endif diff --git a/include/macros.hpp.in b/include/macros.hpp.in index df11fb5..9eb2b81 100644 --- a/include/macros.hpp.in +++ b/include/macros.hpp.in @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,11 +18,10 @@ // execute these lines of code #define MACROSHEADERDEF // define the macro -#define NUMVARS 7 -#define NUMFLOWVARS 5 #define EPS 1.0e-30 #define ROOTP 0 -#define DEFAULTWALLDIST 1.0e10 +#define DEFAULT_WALL_DIST 1.0e10 +#define WALL_DIST_NEG_TOL -1.0e-10 #define MAJORVERSION @aither_VERSION_MAJOR@ #define MINORVERSION @aither_VERSION_MINOR@ #define PATCHNUMBER @aither_VERSION_PATCH@ @@ -30,4 +29,14 @@ #define MPI_CXX_BOOL MPI_C_BOOL #endif +#ifndef NDEBUG +# define MSG_ASSERT(expr, msg) \ + AssertWithMessage(#expr, expr, __FILE__, __LINE__, msg) +#else +# define MSG_ASSERT(expr, msg) ; +#endif + +void AssertWithMessage(const char *exprStr, bool expr, const char *file, + int line, const char *msg); + #endif diff --git a/include/matMultiArray3d.hpp b/include/matMultiArray3d.hpp new file mode 100644 index 0000000..e0b23e4 --- /dev/null +++ b/include/matMultiArray3d.hpp @@ -0,0 +1,175 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef MATMULTIARRAY3DHEADERDEF +#define MATMULTIARRAY3DHEADERDEF + +/* This file contains the header and implementation for a multidimensional (3D) + array class. The class is to act as a container to store flux jacobian + matrices and provide easy access to elements with i, j, k indexing. + */ + +#include // ostream +#include // vector +#include +#include +#include "multiArray3d.hpp" +#include "fluxJacobian.hpp" +#include "varArray.hpp" +#include "arrayView.hpp" + +using std::ostream; +using std::endl; +using std::cout; +using std::cerr; +using std::vector; +using std::string; + +class matMultiArray3d : public multiArray3d { + int flowSize_; + int turbSize_; + + // private member functions + auto BeginFlow(const int &ii, const int &jj, const int &kk) noexcept { + return this->begin() + this->GetLoc1D(ii, jj, kk); + } + const auto BeginFlow(const int &ii, const int &jj, const int &kk) const + noexcept { + return this->begin() + this->GetLoc1D(ii, jj, kk); + } + auto BeginTurb(const int &ii, const int &jj, const int &kk) noexcept { + return this->begin() + this->GetLoc1D(ii, jj, kk) + + flowSize_ * flowSize_; + } + const auto BeginTurb(const int &ii, const int &jj, const int &kk) const + noexcept { + return this->begin() + this->GetLoc1D(ii, jj, kk) + + flowSize_ * flowSize_; + } + + public: + // constructor + matMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const fluxJacobian &init) + : multiArray3d(ii, jj, kk, ng, init.Size()), + flowSize_(init.FlowSize()), turbSize_(init.TurbSize()) { + for (auto kk = this->StartK(); kk < this->EndK(); ++kk) { + for (auto jj = this->StartJ(); jj < this->EndJ(); ++jj) { + for (auto ii = this->StartI(); ii < this->EndI(); ++ii) { + std::copy(init.begin(), init.end(), this->BeginFlow(ii, jj, kk)); + } + } + } + } + matMultiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs, const int &fs, const int &ts) + : multiArray3d(ii, jj, kk, ng, bs), + flowSize_(fs), + turbSize_(ts) {} + matMultiArray3d() : multiArray3d(), flowSize_(0), turbSize_(0) {} + + // move constructor and assignment operator + matMultiArray3d(matMultiArray3d &&) noexcept = default; + matMultiArray3d &operator=(matMultiArray3d &&) noexcept = default; + + // copy constructor and assignment operator + matMultiArray3d(const matMultiArray3d &) = default; + matMultiArray3d &operator=(const matMultiArray3d &) = default; + + // member functions + int FlowSize() const { return flowSize_; } + int TurbSize() const { return turbSize_; } + bool IsScalar() const { return flowSize_ == 1; } + void Zero() { std::fill(this->begin(), this->end(), 0.0); } + + void MultiplyOnDiagonal(const int &ii, const int &jj, const int &kk, + const double &fac) { + MultiplyFacOnDiagonal(this->BeginFlow(ii, jj, kk), flowSize_, fac); + MultiplyFacOnDiagonal(this->BeginTurb(ii, jj, kk), turbSize_, fac); + } + void AddOnDiagonal(const int &ii, const int &jj, const int &kk, + const double &fac) { + AddFacOnDiagonal(this->BeginFlow(ii, jj, kk), flowSize_, fac); + AddFacOnDiagonal(this->BeginTurb(ii, jj, kk), turbSize_, fac); + } + void Inverse(const int &ii, const int &jj, const int &kk) { + MatrixInverse(this->BeginFlow(ii, jj, kk), flowSize_); + MatrixInverse(this->BeginTurb(ii, jj, kk), turbSize_); + } + + void Add(const int &ii, const int &jj, const int &kk, + const fluxJacobian &jac) { + MSG_ASSERT(jac.Size() == this->BlockSize(), "block size must match"); + std::transform(this->BeginFlow(ii, jj, kk), + this->BeginFlow(ii, jj, kk) + this->BlockSize(), jac.begin(), + this->BeginFlow(ii, jj, kk), std::plus()); + } + void Subtract(const int &ii, const int &jj, const int &kk, + const fluxJacobian &jac) { + MSG_ASSERT(jac.Size() == this->BlockSize(), "block size must match"); + std::transform(this->BeginFlow(ii, jj, kk), + this->BeginFlow(ii, jj, kk) + this->BlockSize(), jac.begin(), + this->BeginFlow(ii, jj, kk), std::minus()); + } + void SubtractFromTurb(const int &ii, const int &jj, const int &kk, + const squareMatrix &jac) { + MSG_ASSERT(jac.Size() == this->TurbSize(), "block size must match"); + std::transform( + this->BeginTurb(ii, jj, kk), + this->BeginTurb(ii, jj, kk) + this->TurbSize() * this->TurbSize(), + jac.begin(), this->BeginTurb(ii, jj, kk), std::minus()); + } + + template ::value>> + T ArrayMult(const int &ii, const int &jj, const int &kk, + const T &orig) const { + T arr(orig.Size(), orig.NumSpecies()); + ArrayMultiplication(this->BeginFlow(ii, jj, kk), flowSize_, turbSize_, + this->IsScalar(), orig, arr); + return arr; + } + template ::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>> + auto ArrayMult(const int &ii, const int &jj, const int &kk, + const T &arrView) const { + auto arr = arrView.GetViewType(); + ArrayMultiplication(this->BeginFlow(ii, jj, kk), flowSize_, turbSize_, + this->IsScalar(), arrView, arr); + return arr; + } + + void ClearResize(const int &ii, const int &jj, const int &kk, + const int &ng, const int &bs, const int &fs, const int &ts) { + *this = matMultiArray3d(ii, jj, kk, ng, bs, fs, ts); + } + void ClearResize(const int &ii, const int &jj, const int &kk, const int &ng, + const fluxJacobian &val) { + *this = matMultiArray3d(ii, jj, kk, ng, val); + } + + // destructor + ~matMultiArray3d() noexcept {} +}; + +// --------------------------------------------------------------------------- +// member function definitions +ostream &operator<<(ostream &os, const matMultiArray3d &arr); + +#endif diff --git a/include/matrix.hpp b/include/matrix.hpp index e3082c8..0624dca 100644 --- a/include/matrix.hpp +++ b/include/matrix.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,13 +20,51 @@ #include #include +#include +#include #include "macros.hpp" using std::ostream; using std::vector; -// forward class declarations -class genArray; +// forward class declaration +class varArray; + +// --------------------------------------------------------------------------- +// matrix functions + +// function for matrix multiplication +// using cache efficient implimentation +void MatrixMultiply(const vector::const_iterator &matL, + const vector::const_iterator &matR, + const vector::iterator &result, const int &size); + +double MaximumAbsValOnDiagonal(const vector::const_iterator &mat, + const int &size); + +void IdentityMatrix(const vector::iterator &mat, const int &size); + +int FindMaxInColumn(const vector::const_iterator &mat, const int &size, + const int &c, const int &start, const int &end); + +void RowMultiplyFactor(const vector::iterator &mat, const int &size, + const int &r, const int &c, const double &factor); + +void LinearCombRow(const vector::iterator &mat, const int &size, + const int &r1, const double &factor, const int &r2); + +void SwapMatRows(const vector::iterator &mat, const int &size, + const int &r1, const int &r2); + +void MatrixInverse(const vector::iterator &mat, const int &size); + +void MultiplyFacOnDiagonal(const vector::iterator &mat, const int &size, + const double &val); + +void AddFacOnDiagonal(const vector::iterator &mat, const int &size, + const double &val); + +// --------------------------------------------------------------------------- // class to store a square matrix class squareMatrix { @@ -52,17 +90,36 @@ class squareMatrix { squareMatrix& operator=(const squareMatrix &) = default; // member functions + // provide begin and end so std::begin and std::end can be used + // use lower case to conform with std::begin, std::end + auto begin() noexcept {return data_.begin();} + const auto begin() const noexcept {return data_.begin();} + auto end() noexcept {return data_.end();} + const auto end() const noexcept {return data_.end();} + int Size() const {return size_;} - void SwapRows(const int &, const int &); - void Inverse(); - int FindMaxInCol(const int &, const int &, const int &) const; - void RowMultiply(const int &, const int &, const double &); - void LinCombRow(const int &, const double &, const int &); - void Zero(); - void Identity(); + void SwapRows(const int &r1, const int &r2) { + SwapMatRows(this->begin(), size_, r1, r2); + } + void Inverse() { MatrixInverse(this->begin(), size_); } + int FindMaxInCol(const int &c, const int &start, const int &end) const { + return FindMaxInColumn(this->begin(), size_, c, start, end); + } + void RowMultiply(const int &r, const int &c, const double &fac) { + RowMultiplyFactor(this->begin(), size_, r, c, fac); + } + void LinCombRow(const int &r1, const double &fac, const int &r2) { + LinearCombRow(this->begin(), size_, r1, fac, r2); + } + void Zero() { std::fill(this->begin(), this->end(), 0.0); } + void Identity() { IdentityMatrix(this->begin(), size_); } squareMatrix MatMult(const squareMatrix &) const; - genArray ArrayMult(const genArray &, const int = 0) const; - double MaxAbsValOnDiagonal() const; + template ::value>> + T ArrayMult(const T &, const int = 0) const; + double MaxAbsValOnDiagonal() const { + return MaximumAbsValOnDiagonal(this->begin(), size_); + } // operator overloads double & operator()(const int &r, const int &c) { @@ -105,37 +162,62 @@ class squareMatrix { // function declarations +// member function to do matrix/vector multplication with varArray type +template +T squareMatrix::ArrayMult(const T &vec, const int pos) const { + // vec -- vector to multiply with + auto product = vec; + + // zero out portion of array that will be written over + if (pos == 0) { + for (auto ii = 0; ii < vec.TurbulenceIndex(); ii++) { + product[ii] = 0.0; + } + } else { + for (auto ii = pos; ii < vec.Size(); ii++) { + product[ii] = 0.0; + } + } + + for (auto rr = 0; rr < size_; rr++) { + for (auto cc = 0; cc < size_; cc++) { + product[pos + rr] += (*this)(rr, cc) * vec[pos + cc]; + } + } + return product; +} + ostream &operator<<(ostream &os, const squareMatrix &); // operator overload for addition squareMatrix & squareMatrix::operator+=(const squareMatrix &mat) { - for (auto ii = 0U; ii < mat.data_.size(); ii++) { - data_[ii] += mat.data_[ii]; - } + MSG_ASSERT(this->Size() == mat.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), mat.begin(), this->begin(), + std::plus()); return *this; } // operator overload for subtraction squareMatrix & squareMatrix::operator-=(const squareMatrix &mat) { - for (auto ii = 0U; ii < mat.data_.size(); ii++) { - data_[ii] -= mat.data_[ii]; - } + MSG_ASSERT(this->Size() == mat.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), mat.begin(), this->begin(), + std::minus()); return *this; } // operator overload for elementwise multiplication squareMatrix & squareMatrix::operator*=(const squareMatrix &mat) { - for (auto ii = 0U; ii < mat.data_.size(); ii++) { - data_[ii] *= mat.data_[ii]; - } + MSG_ASSERT(this->Size() == mat.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), mat.begin(), this->begin(), + std::multiplies()); return *this; } // operator overload for elementwise multiplication squareMatrix & squareMatrix::operator/=(const squareMatrix &mat) { - for (auto ii = 0U; ii < mat.data_.size(); ii++) { - data_[ii] /= mat.data_[ii]; - } + MSG_ASSERT(this->Size() == mat.Size(), "matrix sizes must be equal"); + std::transform(this->begin(), this->end(), mat.begin(), this->begin(), + std::divides()); return *this; } @@ -158,33 +240,29 @@ inline const squareMatrix operator/(squareMatrix lhs, const squareMatrix &rhs) { // operator overloads for double -------------------------------------------- // operator overload for addition squareMatrix & squareMatrix::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val += scalar; }); return *this; } // operator overload for subtraction squareMatrix & squareMatrix::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val -= scalar; }); return *this; } // operator overload for multiplication squareMatrix & squareMatrix::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val *= scalar; }); return *this; } // operator overload for division squareMatrix & squareMatrix::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val /= scalar; }); return *this; } @@ -193,11 +271,7 @@ inline const squareMatrix operator+(const double &lhs, squareMatrix rhs) { } inline const squareMatrix operator-(const double &lhs, squareMatrix rhs) { - for (auto rr = 0; rr < rhs.Size(); rr++) { - for (auto cc = 0; cc < rhs.Size(); cc++) { - rhs(rr, cc) = lhs - rhs(rr, cc); - } - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs - val; }); return rhs; } @@ -206,11 +280,7 @@ inline const squareMatrix operator*(const double &lhs, squareMatrix rhs) { } inline const squareMatrix operator/(const double &lhs, squareMatrix rhs) { - for (auto rr = 0; rr < rhs.Size(); rr++) { - for (auto cc = 0; cc < rhs.Size(); cc++) { - rhs(rr, cc) = lhs / rhs(rr, cc); - } - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs / val; }); return rhs; } diff --git a/include/multiArray3d.hpp b/include/multiArray3d.hpp index 8f8450e..106e0ff 100644 --- a/include/multiArray3d.hpp +++ b/include/multiArray3d.hpp @@ -1,6 +1,6 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) - + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -28,10 +28,13 @@ #include // vector #include // string #include // unique_ptr +#include // pair +#include #include "mpi.h" #include "vector3d.hpp" #include "boundaryConditions.hpp" // connection #include "range.hpp" // range +#include "macros.hpp" // MSG_ASSERT using std::ostream; using std::endl; @@ -48,25 +51,24 @@ class multiArray3d { int numJ_; int numK_; int numGhosts_; - - // private member functions - int GetLoc1D(const int &ii, const int &jj, const int &kk) const { - return (ii + numGhosts_) + (jj + numGhosts_) * numI_ + - (kk + numGhosts_) * numI_ * numJ_; - } + int blkSize_; public: // constructor multiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, - const T &init) : - data_((ii + 2 * ng) * (jj + 2 * ng) * (kk + 2 * ng), init), + const int &bs, const T &init) : + data_(bs * (ii + 2 * ng) * (jj + 2 * ng) * (kk + 2 * ng), init), numI_(ii + 2 * ng), numJ_(jj + 2 * ng), numK_(kk + 2 * ng), - numGhosts_(ng) {} - multiArray3d(const int &ii, const int &jj, const int &kk, const int &ng) : - data_((ii + 2 * ng) * (jj + 2 * ng) * (kk + 2 * ng)), + numGhosts_(ng), blkSize_(bs) {} + multiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs=1) : + data_(bs * (ii + 2 * ng) * (jj + 2 * ng) * (kk + 2 * ng)), numI_(ii + 2 * ng), numJ_(jj + 2 * ng), numK_(kk + 2 * ng), - numGhosts_(ng) {} - multiArray3d() : multiArray3d(0, 0, 0, 0) {} + numGhosts_(ng), blkSize_(bs) {} + multiArray3d(const int &ii, const int &jj, const int &kk, const int &ng, + const std::pair &info) + : multiArray3d(ii, jj, kk, ng, info.first) {} + multiArray3d() : multiArray3d(0, 0, 0, 0, 1) {} // move constructor and assignment operator multiArray3d(multiArray3d&&) noexcept = default; @@ -78,6 +80,12 @@ class multiArray3d { // member functions int Size() const {return data_.size();} + int BlockSize() const { return blkSize_; } + int NumBlocks() const {return this->Size() / this->BlockSize();} + virtual std::pair BlockInfo() const { + return std::make_pair(this->BlockSize(), 0); + } + bool IsEmpty() const { return data_.empty(); } int NumI() const {return numI_;} int NumJ() const {return numJ_;} int NumK() const {return numK_;} @@ -93,6 +101,22 @@ class multiArray3d { int EndK() const {return numK_ - numGhosts_;} int Start(const string &) const; int End(const string &) const; + int GetLoc1D(const int &ii, const int &jj, const int &kk) const { + MSG_ASSERT(ii >= this->StartI() && ii < this->EndI(), + "i-index out of range"); + MSG_ASSERT(jj >= this->StartJ() && jj < this->EndJ(), + "j-index out of range"); + MSG_ASSERT(kk >= this->StartK() && kk < this->EndK(), + "k-index out of range"); + return blkSize_ * ((ii + numGhosts_) + (jj + numGhosts_) * numI_ + + (kk + numGhosts_) * numI_ * numJ_); + } + int GetLoc1D(const int &ii, const int &jj, const int &kk, + const int &ll) const { + MSG_ASSERT(ll >= 0 && ll < blkSize_, + "accessing index outside of block limit"); + return this->GetLoc1D(ii, jj, kk) + ll; + } int PhysStartI() const {return 0;} int PhysStartJ() const {return 0;} @@ -129,24 +153,28 @@ class multiArray3d { multiArray3d Slice(const string &, int, range, range, const string = "cell", const int = 0) const; - void Insert(const range &, const range &, const range &, - const multiArray3d &); - void Insert(const string &, const range &, const multiArray3d &, - const bool = false); - void Insert(const string &, int, int, const multiArray3d &, - const bool = false, const string = "cell", const bool = false, - const bool = false); - void Insert(const string &, int, range, range, const multiArray3d &, + template + void Insert(const range &, const range &, const range &, const TT &); + template + void Insert(const string &, const range &, const TT &, const bool = false); + template + void Insert(const string &, int, int, const TT &, const bool = false, + const string = "cell", const bool = false, const bool = false); + template + void Insert(const string &, int, range, range, const TT &, const string = "cell", const int = 0); - void Fill(const multiArray3d &); - void PutSlice(const multiArray3d &, const connection &, const int &); + template + void Fill(const TT &); + template + void PutSlice(const TT &, const connection &, const int &); void SwapSliceMPI(const connection &, const int &, const MPI_Datatype &, const int = 1); - void SwapSlice(const connection &, multiArray3d &); + template + void SwapSlice(const connection &, TT &); - void Zero(const T &); - void Zero(); + void Zero(const T &z) { std::fill(this->begin(), this->end(), z); } + void Zero() { this->Zero(T()); } multiArray3d GrowI() const; multiArray3d GrowJ() const; @@ -157,45 +185,64 @@ class multiArray3d { T GetElem(const int &ii, const int &jj, const int &kk) const; + void InsertBlock(const int &ii, const int &jj, const int &kk, const T &val) { + (*this)(ii, jj, kk) = val; + } + void InsertBlock(const string &dir, const int &d1, const int &d2, + const int &d3, const T &val) { + (*this)(dir, d1, d2, d3) = val; + } + // operator overloads - T& operator()(const int &ii, const int &jj, const int &kk) { - return data_[this->GetLoc1D(ii, jj, kk)]; + T &operator()(const int &ii, const int &jj, const int &kk, + const int &ll = 0) { + return data_[this->GetLoc1D(ii, jj, kk, ll)]; } - const T& operator()(const int &ii, const int &jj, const int &kk) const { - return data_[this->GetLoc1D(ii, jj, kk)]; + const T &operator()(const int &ii, const int &jj, const int &kk, + const int &ll = 0) const { + return data_[this->GetLoc1D(ii, jj, kk, ll)]; } - T& operator()(const int &ind) { + T &operator()(const int &ind) { return data_[ind]; } - const T& operator()(const int &ind) const { + const T &operator()(const int &ind) const { return data_[ind]; } - T& operator()(const string &dir, const int &d1, const int &d2, const int &d3) { + T &operator()(const string &dir, const int &d1, const int &d2, + const int &d3, const int &bb = 0) { if (dir == "i") { // direction 1 is i - return data_[this->GetLoc1D(d1, d2, d3)]; + return (*this)(d1, d2, d3, bb); } else if (dir == "j") { // direction 1 is j - return data_[this->GetLoc1D(d3, d1, d2)]; + return (*this)(d3, d1, d2, bb); } else if (dir == "k") { // direction 1 is k - return data_[this->GetLoc1D(d2, d3, d1)]; + return (*this)(d2, d3, d1, bb); } else { cerr << "ERROR: Direction " << dir << " is not recognized!" << endl; exit(EXIT_FAILURE); } } const T& operator()(const string &dir, const int &d1, const int &d2, - const int &d3) const { + const int &d3, const int &bb = 0) const { if (dir == "i") { // direction 1 is i - return data_[this->GetLoc1D(d1, d2, d3)]; + return (*this)(d1, d2, d3, bb); } else if (dir == "j") { // direction 1 is j - return data_[this->GetLoc1D(d3, d1, d2)]; + return (*this)(d3, d1, d2, bb); } else if (dir == "k") { // direction 1 is k - return data_[this->GetLoc1D(d2, d3, d1)]; + return (*this)(d2, d3, d1, bb); } else { cerr << "ERROR: Direction " << dir << " is not recognized!" << endl; exit(EXIT_FAILURE); } } + T &operator[](const int &ind) { + return data_[ind]; + } + const T &operator[](const int &ind) const { + return data_[ind]; + } + + // arithmetic with same type inline multiArray3d & operator+=(const multiArray3d &); inline multiArray3d & operator-=(const multiArray3d &); @@ -287,11 +334,15 @@ class multiArray3d { } void ClearResize(const int &ii, const int &jj, const int &kk, const int &ng) { - *this = multiArray3d(ii, jj, kk, ng); + *this = multiArray3d(ii, jj, kk, ng, blkSize_); + } + void ClearResize(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs) { + *this = multiArray3d(ii, jj, kk, ng, bs); } - void ClearResize(const int &ii, const int &jj, const int &kk, - const int &ng, const T &val) { - *this = multiArray3d(ii, jj, kk, ng, val); + void ClearResize(const int &ii, const int &jj, const int &kk, const int &ng, + const int &bs, const T &val) { + *this = multiArray3d(ii, jj, kk, ng, bs, val); } void SameSizeResize(const int &ii, const int &jj, const int &kk); @@ -299,119 +350,700 @@ class multiArray3d { const int &ng); // destructor - ~multiArray3d() noexcept {} + virtual ~multiArray3d() noexcept {} }; // --------------------------------------------------------------------------- -// member function definitions - +// non member functions +// main slice function that all other overloaded slice functions call template -int multiArray3d::Start(const string &dir) const { - if (dir == "i") { - return this->StartI(); - } else if (dir == "j") { - return this->StartJ(); - } else if (dir == "k") { - return this->StartK(); - } else { - cerr << "ERROR: Error in multiArray3d::Start. Direction " << dir - << " is not recognized!" << endl; +auto SliceArray(const T &parent, const range &ir, const range &jr, + const range &kr) { + // ir -- i-index range to take slice [inclusive, exclusive) + // jr -- j-index range to take slice [inclusive, exclusive) + // kr -- k-index range to take slice [inclusive, exclusive) + // T should be multiArray3d or blkMultiArray3d type + +#ifndef NDEBUG + // check that slice bounds are within parent array and that end bounds are + // greater than or equal to start bounds + if (!ir.IsInside(parent.RangeI()) || !jr.IsInside(parent.RangeJ()) || + !kr.IsInside(parent.RangeK()) || !ir.IsValid() || !jr.IsValid() || + !kr.IsValid()) { + cerr << "ERROR: Error in SliceArray. Cannot take slice with " + << "boundaries " << ir << ", " << jr << ", " << kr << endl + << "from array with ranges " << parent.RangeI() << ", " + << parent.RangeJ() << ", " << parent.RangeK() << endl; exit(EXIT_FAILURE); } +#endif + + // slices always have 0 ghost cells + T arr(ir.Size(), jr.Size(), kr.Size(), 0, parent.BlockInfo()); + + // s is for index of sliced array, p is for index of parent array + for (int ks = arr.StartK(), kp = kr.Start(); ks < arr.EndK(); ks++, kp++) { + for (int js = arr.StartJ(), jp = jr.Start(); js < arr.EndJ(); js++, jp++) { + for (int is = arr.StartI(), ip = ir.Start(); is < arr.EndI(); is++, ip++) { + arr.InsertBlock(is, js, ks, parent(ip, jp, kp)); + } + } + } + return arr; } +// Overload to slice only in one direction. Given a 3D array, this slice returns +// a plane with normal direction dir, or a smaller 3D array where the direction +// dir is sliced over dirRange. It also has the ability to include or ignore +// ghost cells in its planar slices template -int multiArray3d::End(const string &dir) const { +auto SliceArray(const T &parent, const string &dir, const range &dirRange, + const bool physOnly) { + // dir -- direction of slice + // dirRange -- range of slice in direction given + // phsOnly -- flag to only include physical cells in the two directions that + // are not specified as dir + if (dir == "i") { - return this->EndI(); + if (physOnly) { + return parent.Slice(dirRange, parent.PhysRangeJ(), parent.PhysRangeK()); + } else { + return parent.Slice(dirRange, parent.RangeJ(), parent.RangeK()); + } } else if (dir == "j") { - return this->EndJ(); + if (physOnly) { + return parent.Slice(parent.PhysRangeI(), dirRange, parent.PhysRangeK()); + } else { + return parent.Slice(parent.RangeI(), dirRange, parent.RangeK()); + } } else if (dir == "k") { - return this->EndK(); + if (physOnly) { + return parent.Slice(parent.PhysRangeI(), parent.PhysRangeJ(), dirRange); + } else { + return parent.Slice(parent.RangeI(), parent.RangeJ(), dirRange); + } } else { - cerr << "ERROR: Error in multiArray3d::End. Direction " << dir + cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir << " is not recognized!" << endl; exit(EXIT_FAILURE); } } +// function to return a slice of the array +// overload to slice line out of array template -int multiArray3d::PhysStart(const string &dir) const { - if (dir == "i") { - return this->PhysStartI(); - } else if (dir == "j") { - return this->PhysStartJ(); - } else if (dir == "k") { - return this->PhysStartK(); +auto SliceArray(const T &parent, const string &dir, int d2Ind, int d3Ind, + const bool physOnly, const string id, const bool upper2, + const bool upper3) { + // dir -- direction of line slice (direction 1) + // d2Ind -- index of direction 2 + // d3Ind -- index of direction 3 + // physOnly -- flag to only include physical cells in line slice + // id -- type of multiArray3d being sliced: cell, i, j, or k + // d2Ind and d3Ind are supplied as cell indices, but may need to be + // altered if the array is storing i, j, or k face data + // upper2 -- flag to determine if direction 2 is at upper index + // upper3 -- flag to determine if direction 3 is at upper index + + if (dir == "i") { // d2 = j, d3 = k + if (upper2 && id == "j") { + d2Ind++; + } else if (upper3 && id == "k") { + d3Ind++; + } + + if (physOnly) { + return parent.Slice(parent.PhysRangeI(), d2Ind, d3Ind); + } else { + return parent.Slice(parent.RangeI(), d2Ind, d3Ind); + } + } else if (dir == "j") { // d2 = k, d3 = i + if (upper2 && id == "k") { + d2Ind++; + } else if (upper3 && id == "i") { + d3Ind++; + } + + if (physOnly) { + return parent.Slice(d3Ind, parent.PhysRangeJ(), d2Ind); + } else { + return parent.Slice(d3Ind, parent.RangeJ(), d2Ind); + } + } else if (dir == "k") { // d2 = i, d3 = j + if (upper2 && id == "i") { + d2Ind++; + } else if (upper3 && id == "j") { + d3Ind++; + } + + if (physOnly) { + return parent.Slice(d2Ind, d3Ind, parent.PhysRangeK()); + } else { + return parent.Slice(d2Ind, d3Ind, parent.RangeK()); + } } else { - cerr << "ERROR: Error in multiArray3d::PhysStart. Direction " << dir + cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir << " is not recognized!" << endl; exit(EXIT_FAILURE); } } +// overload to slice plane out of array +// Identical to previous slice overload, but more general in that in can slice +// over a subset of direction 2 & 3. This is useful to slice out a plane that +// borders a boundary condition patch. template -int multiArray3d::PhysEnd(const string &dir) const { - if (dir == "i") { - return this->PhysEndI(); - } else if (dir == "j") { - return this->PhysEndJ(); - } else if (dir == "k") { - return this->PhysEndK(); +auto SliceArray(const T &parent, const string &dir, int dirInd, range dir1, + range dir2, const string id, const int type) { + // dir -- normal direction of planar slice + // dirInd -- index in normal direction + // dir1 -- range of direction 1 (direction 3 is normal to slice) + // dir2 -- range of direction 2 (direction 3 is normal to slice) + // id -- id of array being sliced (i, j, k for faces, cell for cells) + // type -- surface type of dir + + if (dir == "i") { // d1 = j, d2 = k + if (type == 2 && id == "i") { // upper i-surface & i face data + dirInd++; + } + if (id == "j") { + dir1.GrowEnd(); + } else if (id == "k") { + dir2.GrowEnd(); + } + return parent.Slice(dirInd, dir1, dir2); + } else if (dir == "j") { // d1 = k, d2 = i + if (type == 4 && id == "j") { // upper j-surface & j face data + dirInd++; + } + if (id == "k") { + dir1.GrowEnd(); + } else if (id == "i") { + dir2.GrowEnd(); + } + return parent.Slice(dir2, dirInd, dir1); + } else if (dir == "k") { // d1 = i, d2 = j + if (type == 6 && id == "k") { // upper k-surface & k face data + dirInd++; + } + if (id == "i") { + dir1.GrowEnd(); + } else if (id == "j") { + dir2.GrowEnd(); + } + return parent.Slice(dir1, dir2, dirInd); } else { - cerr << "ERROR: Error in multiArray3d::PhysEnd. Direction " << dir + cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir << " is not recognized!" << endl; exit(EXIT_FAILURE); } } - +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// main insert funciton that all other overloaded insert functions call template -T multiArray3d::GetElem(const int &ii, const int &jj, const int &kk) const { - if (ii < this->EndI() && jj < this->EndJ() && kk < this->Endk() && - ii >= this->StartI() && jj >= this->StartJ() && kk >= this->StartK()) { - return data_[this->GetLoc1D(ii, jj, kk)]; - } else { - cerr << "ERROR: Tried to access location outside of bounds of " - << "multiArray3d" << endl; - cerr << "Tried to access " << ii << ", " << jj << ", " << kk << endl; - cerr << "Maximum locations are " << this->EndI() - 1 << ", " - << this->EndJ() - 1 << ", " << this->EndK() - 1 << endl; +void InsertArray(T &parent, const range &ir, const range &jr, const range &kr, + const T &arr) { + // ir -- i-index range to take slice [inclusive, exclusive) + // jr -- j-index range to take slice [inclusive, exclusive) + // kr -- k-index range to take slice [inclusive, exclusive) + // arr -- array to insert into this one + +#ifndef NDEBUG + // check that given bounds fit in this, sizes match, and that bounds are valid + if (!ir.IsInside(parent.RangeI()) || !jr.IsInside(parent.RangeJ()) || + !kr.IsInside(parent.RangeK()) || ir.Size() != arr.RangeI().Size() || + jr.Size() != arr.RangeJ().Size() || kr.Size() != arr.RangeK().Size() || + !ir.IsValid() || !jr.IsValid() || !kr.IsValid()) { + cerr << "ERROR: Error in InsertArray. Given array does not fit in " + << "given bounds" << endl + << "Given bounds: " << ir << ", " << jr << ", " << kr << endl + << "Bounds of array being inserted: " << arr.RangeI() << ", " + << arr.RangeJ() << ", " << arr.RangeK() << endl; + cerr << "Bounds of array accepting data: " << parent.RangeI() << ", " + << parent.RangeJ() << ", " << parent.RangeK() << endl; exit(EXIT_FAILURE); } -} +#endif -// Same type operator overloads -// operator overload for addition -template -multiArray3d & multiArray3d::operator+=(const multiArray3d &arr) { - for (auto rr = 0; rr < this->Size(); rr++) { - data_[rr] += arr.data_[rr]; + // s is for index of sliced array, p is for index of parent array + for (int ks = arr.StartK(), kp = kr.Start(); ks < arr.EndK(); ks++, kp++) { + for (int js = arr.StartJ(), jp = jr.Start(); js < arr.EndJ(); js++, jp++) { + for (int is = arr.StartI(), ip = ir.Start(); is < arr.EndI(); is++, ip++) { + parent.InsertBlock(ip, jp, kp, arr(is, js, ks)); + } + } } - return *this; } -// operator overload for subtraction with a scalar +// Overload to insert only in one direction. Given a 3D array, this inserts a +// plane with normal direction dir, or a smaller 3D array where the direction +// dir is inserted over dirRange. It also has the ability to include or ignore +// ghost cells in its planar inserts template -multiArray3d & multiArray3d::operator-=(const multiArray3d &arr) { - for (auto rr = 0; rr < this->Size(); rr++) { - data_[rr] -= arr.data_[rr]; - } - return *this; -} +void InsertArray(T &parent, const string &dir, const range &dirRange, + const T &arr, const bool physOnly) { + // dir -- direction of slice to insert + // dirRange -- range to insert slice into in direction given + // arr -- array to insert + // phsOnly -- flag to only include physical cells in the two directions that + // are not specified as dir -// operator overload for elementwise multiplication -template -multiArray3d & multiArray3d::operator*=(const multiArray3d &arr) { - for (auto rr = 0; rr < this->Size(); rr++) { - data_[rr] *= arr.data_[rr]; + if (dir == "i") { + if (physOnly) { + return parent.Insert(dirRange, parent.PhysRangeJ(), parent.PhysRangeK(), + arr); + } else { + return parent.Insert(dirRange, parent.RangeJ(), parent.RangeK(), arr); + } + } else if (dir == "j") { + if (physOnly) { + return parent.Insert(parent.PhysRangeI(), dirRange, parent.PhysRangeK(), + arr); + } else { + return parent.Insert(parent.RangeI(), dirRange, parent.RangeK(), arr); + } + } else if (dir == "k") { + if (physOnly) { + return parent.Insert(parent.PhysRangeI(), parent.PhysRangeJ(), dirRange, + arr); + } else { + return parent.Insert(parent.RangeI(), parent.RangeJ(), dirRange, arr); + } + } else { + cerr << "ERROR: Error in InsertArray, direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); } - return *this; } -// operator overload for elementwise division +// overload to insert line into array template -multiArray3d & multiArray3d::operator/=(const multiArray3d &arr) { +void InsertArray(T &parent, const string &dir, int d2Ind, int d3Ind, + const T &arr, const bool physOnly, const string id, + const bool upper2, const bool upper3) { + // dir -- direction of line slice to insert (direction 1) + // d2Ind -- index of direction 2 to insert into + // d3Ind -- index of direction 3 to insert into + // physOnly -- flag to only include physical cells in line insert + // id -- type of multiArray3d being sliced: cell, i, j, or k + // d2Ind and d3Ind are supplied as cell indices, but may need to be + // altered if the array is storing i, j, or k face data + // upper2 -- flag to determine if direction 2 is at upper index + // upper3 -- flag to determine if direction 3 is at upper index + + if (dir == "i") { // d2 = j, d3 = k + if (upper2 && id == "j") { + d2Ind++; + } else if (upper3 && id == "k") { + d3Ind++; + } + + if (physOnly) { + return parent.Insert(parent.PhysRangeI(), d2Ind, d3Ind, arr); + } else { + return parent.Insert(parent.RangeI(), d2Ind, d3Ind, arr); + } + } else if (dir == "j") { // d2 = k, d3 = i + if (upper2 && id == "k") { + d2Ind++; + } else if (upper3 && id == "i") { + d3Ind++; + } + + if (physOnly) { + return parent.Insert(d3Ind, parent.PhysRangeJ(), d2Ind, arr); + } else { + return parent.Insert(d3Ind, parent.RangeJ(), d2Ind, arr); + } + } else if (dir == "k") { // d2 = i, d3 = j + if (upper2 && id == "i") { + d2Ind++; + } else if (upper3 && id == "j") { + d3Ind++; + } + + if (physOnly) { + return parent.Insert(d2Ind, d3Ind, parent.PhysRangeK(), arr); + } else { + return parent.Insert(d2Ind, d3Ind, parent.RangeK(), arr); + } + } else { + cerr << "ERROR: Error in InsertArray, direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +// overload to insert plane into array +// Identical to previous insert overload, but more general in that in can insert +// over a subset of direction 2 & 3. This is useful to insert into a plane that +// borders a boundary condition patch. +template +void InsertArray(T &parent, const string &dir, int dirInd, range dir1, + range dir2, const T &arr, const string id, const int type) { + // dir -- normal direction of planar slice + // dirInd -- index in normal direction + // dir1 -- range of direction 1 (direction 3 is normal to slice) + // dir2 -- range of direction 2 (direction 3 is normal to slice) + // arr -- array to insert + // id -- id of array being inserted into (i, j, k for faces, cell for cells) + // type -- surface type of dir + + if (dir == "i") { // d1 = j, d2 = k + if (type == 2 && id == "i") { // upper i-surface & i normal + dirInd++; + } + if (id == "j") { + dir1.GrowEnd(); + } else if (id == "k") { + dir2.GrowEnd(); + } + return parent.Insert(dirInd, dir1, dir2, arr); + } else if (dir == "j") { // d1 = k, d2 = i + if (type == 4 && id == "j") { // upper j-surface & j normal + dirInd++; + } + if (id == "k") { + dir1.GrowEnd(); + } else if (id == "i") { + dir2.GrowEnd(); + } + return parent.Insert(dir2, dirInd, dir1, arr); + } else if (dir == "k") { // d1 = i, d2 = j + if (type == 6 && id == "k") { // upper k-surface & k normal + dirInd++; + } + if (id == "i") { + dir1.GrowEnd(); + } else if (id == "j") { + dir2.GrowEnd(); + } + return parent.Insert(dir1, dir2, dirInd, arr); + } else { + cerr << "ERROR: Error in InsertArray, direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +/* Function to swap ghost cells between two blocks at an connection +boundary. Slices are removed from the physical cells (extending into ghost cells +at the edges) of one block and inserted into the ghost cells of its partner +block. The reverse is also true. The slices are taken in the coordinate system +orientation of their parent block. + + Interior Cells Ghost Cells Ghost Cells Interior Cells + ________ ______|________ _________ _______________|_______ _________ +Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 + | | | | | | | | | | + | Ui-1 | Ui | Uj | Uj+1 | | Ui-1 | Ui | Uj | Uj+1 | + | | | | | | | | | | + |________|______|________|_________| |________|______|_______|_________| + | | + +The above diagram shows the resulting values after the ghost cell swap. The +logic ensures that the ghost cells at the connection boundary exactly match +their partner block as if there were no separation in the grid. +*/ +template +void SwapSliceLocal(T &array1, const connection &conn, T &array2) { + // array1 -- first array involved in connection boundary + // conn -- connection boundary information + // array2 -- second array involved in connection boundary + + // Get indices for slice coming from first block to swap + auto is1 = 0, ie1 = 0; + auto js1 = 0, je1 = 0; + auto ks1 = 0, ke1 = 0; + + conn.FirstSliceIndices(is1, ie1, js1, je1, ks1, ke1, array1.GhostLayers()); + + // Get indices for slice coming from second block to swap + auto is2 = 0, ie2 = 0; + auto js2 = 0, je2 = 0; + auto ks2 = 0, ke2 = 0; + + conn.SecondSliceIndices(is2, ie2, js2, je2, ks2, ke2, array2.GhostLayers()); + + // get slices to swap + auto slice1 = array1.Slice({is1, ie1}, {js1, je1}, {ks1, ke1}); + auto slice2 = array2.Slice({is2, ie2}, {js2, je2}, {ks2, ke2}); + + // change connections to work with slice and ghosts + connection conn1 = conn; + connection conn2 = conn; + conn1.AdjustForSlice(false, array1.GhostLayers()); + conn2.AdjustForSlice(true, array2.GhostLayers()); + + // put slices in proper blocks + array1.PutSlice(slice2, conn2, array2.GhostLayers()); + array2.PutSlice(slice1, conn1, array1.GhostLayers()); +} + +/* Function to swap slice using MPI. This is similar to the SwapSlice + function, but is called when the neighboring procBlocks are on different + processors. +*/ +template +void SwapSliceParallel(T &array, const connection &conn, const int &rank, + const MPI_Datatype &MPI_arrData, const int tag) { + // array -- array on local processor to swap + // conn -- connection boundary information + // rank -- processor rank + // MPI_arrData -- MPI datatype for passing data in *this + // tag -- id for MPI swap (default 1) + + // Get indices for slice coming from block to swap + auto is = 0, ie = 0; + auto js = 0, je = 0; + auto ks = 0, ke = 0; + + if (rank == conn.RankFirst()) { // local block first in connection + conn.FirstSliceIndices(is, ie, js, je, ks, ke, array.GhostLayers()); + } else if (rank == conn.RankSecond()) { // local block second in connection + conn.SecondSliceIndices(is, ie, js, je, ks, ke, array.GhostLayers()); + } else { + cerr << "ERROR: Error in SwapSliceParallel(). Processor rank does " + "not match either of connection ranks!" << endl; + exit(EXIT_FAILURE); + } + + // get local state slice to swap + auto slice = array.Slice({is, ie}, {js, je}, {ks, ke}); + + // swap state slices with partner block + slice.PackSwapUnpackMPI(conn, MPI_arrData, rank, tag); + + // change connections to work with slice and ghosts + auto connAdj = conn; + + // change connections to work with slice and ghosts + // block to insert into is first in connection + if (rank == conn.RankFirst()) { + connAdj.AdjustForSlice(true, array.GhostLayers()); + } else { // block to insert into is second in connection, so pass swapped + // version + connAdj.AdjustForSlice(false, array.GhostLayers()); + } + + // insert state slice into procBlock + array.PutSlice(slice, connAdj, array.GhostLayers()); +} + +template +void InsertSlice(T &array1, const T &array2, const connection &inter, + const int &d3) { + // array1 -- array to accept data + // array2 -- array to insert into array1 + // inter -- connection data structure defining patches and orientation + // d3 -- distance of direction normal to patch to insert + +#ifndef NDEBUG + // check that number of cells to insert matches + auto blkCell = inter.Dir1LenFirst() * inter.Dir2LenFirst() * d3; + if (blkCell != array2.NumBlocks()) { + cerr << "ERROR: Error in InsertSlice(). Number of cells " + "being inserted does not match designated space to insert." + << endl; + cerr << "Direction 1, 2, 3 of array to insert into: " + << inter.Dir1LenFirst() << ", " << inter.Dir2LenFirst() << ", " << d3 + << endl; + cerr << "Direction I, J, K of array3d to insert: " << array2.NumI() << ", " + << array2.NumJ() << ", " << array2.NumK() << endl; + exit(EXIT_FAILURE); + } +#endif + + // adjust insertion indices if patch borders another connection on the same + // surface of the block + const auto adjS1 = + (inter.Dir1StartInterBorderFirst()) ? array1.GhostLayers() : 0; + const auto adjE1 = + (inter.Dir1EndInterBorderFirst()) ? array1.GhostLayers() : 0; + const auto adjS2 = + (inter.Dir2StartInterBorderFirst()) ? array1.GhostLayers() : 0; + const auto adjE2 = + (inter.Dir2EndInterBorderFirst()) ? array1.GhostLayers() : 0; + + // loop over cells to insert + for (auto l3 = 0; l3 < d3; l3++) { + for (auto l2 = adjS2; l2 < inter.Dir2LenFirst() - adjE2; l2++) { + for (auto l1 = adjS1; l1 < inter.Dir1LenFirst() - adjE1; l1++) { + // get acceptor and inserter indices + auto indA = + GetSwapLoc(l1, l2, l3, array1.GhostLayers(), inter, d3, true); + auto indI = + GetSwapLoc(l1, l2, l3, array2.GhostLayers(), inter, d3, false); + + // assign cell data + array1.InsertBlock(indA[0], indA[1], indA[2], + array2(indI[0], indI[1], indI[2])); + } + } + } +} + +template +auto GrowInI(const T &orig) { + T arr(orig.NumINoGhosts() + 1, orig.NumJNoGhosts(), orig.NumKNoGhosts(), + orig.GhostLayers(), orig.BlockInfo()); + for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { + for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { + for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { + auto val = (ii == arr.EndI() - 1) ? orig(ii - 1, jj, kk) + : orig(ii, jj, kk); + arr.InsertBlock(ii, jj, kk, val); + } + } + } + return arr; +} + +template +auto GrowInJ(const T &orig) { + T arr(orig.NumINoGhosts(), orig.NumJNoGhosts() + 1, orig.NumKNoGhosts(), + orig.GhostLayers(), orig.BlockInfo()); + for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { + for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { + for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { + auto val = (jj == arr.EndJ() - 1) ? orig(ii, jj - 1, kk) + : orig(ii, jj, kk); + arr.InsertBlock(ii, jj, kk, val); + } + } + } + return arr; +} + +template +auto GrowInK(const T &orig) { + T arr(orig.NumINoGhosts(), orig.NumJNoGhosts(), orig.NumKNoGhosts() + 1, + orig.GhostLayers(), orig.BlockInfo()); + for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { + for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { + for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { + auto val = (kk == arr.EndK() - 1) ? orig(ii, jj, kk - 1) + : orig(ii, jj, kk); + arr.InsertBlock(ii, jj, kk, val); + } + } + } + return arr; +} + + +// --------------------------------------------------------------------------- +// member function definitions + +template +int multiArray3d::Start(const string &dir) const { + if (dir == "i") { + return this->StartI(); + } else if (dir == "j") { + return this->StartJ(); + } else if (dir == "k") { + return this->StartK(); + } else { + cerr << "ERROR: Error in multiArray3d::Start. Direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +template +int multiArray3d::End(const string &dir) const { + if (dir == "i") { + return this->EndI(); + } else if (dir == "j") { + return this->EndJ(); + } else if (dir == "k") { + return this->EndK(); + } else { + cerr << "ERROR: Error in multiArray3d::End. Direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +template +int multiArray3d::PhysStart(const string &dir) const { + if (dir == "i") { + return this->PhysStartI(); + } else if (dir == "j") { + return this->PhysStartJ(); + } else if (dir == "k") { + return this->PhysStartK(); + } else { + cerr << "ERROR: Error in multiArray3d::PhysStart. Direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +template +int multiArray3d::PhysEnd(const string &dir) const { + if (dir == "i") { + return this->PhysEndI(); + } else if (dir == "j") { + return this->PhysEndJ(); + } else if (dir == "k") { + return this->PhysEndK(); + } else { + cerr << "ERROR: Error in multiArray3d::PhysEnd. Direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + + +template +T multiArray3d::GetElem(const int &ii, const int &jj, const int &kk) const { + if (ii < this->EndI() && jj < this->EndJ() && kk < this->EndK() && + ii >= this->StartI() && jj >= this->StartJ() && kk >= this->StartK()) { + return (*this)(ii, jj, kk); + } else { + cerr << "ERROR: Tried to access location outside of bounds of " + << "multiArray3d" << endl; + cerr << "Tried to access " << ii << ", " << jj << ", " << kk << endl; + cerr << "Maximum locations are " << this->EndI() - 1 << ", " + << this->EndJ() - 1 << ", " << this->EndK() - 1 << endl; + exit(EXIT_FAILURE); + } +} + +// Same type operator overloads +// operator overload for addition +template +multiArray3d & multiArray3d::operator+=(const multiArray3d &arr) { + for (auto rr = 0; rr < this->Size(); rr++) { + data_[rr] += arr.data_[rr]; + } + return *this; +} + +// operator overload for subtraction with a scalar +template +multiArray3d & multiArray3d::operator-=(const multiArray3d &arr) { + for (auto rr = 0; rr < this->Size(); rr++) { + data_[rr] -= arr.data_[rr]; + } + return *this; +} + +// operator overload for elementwise multiplication +template +multiArray3d & multiArray3d::operator*=(const multiArray3d &arr) { + for (auto rr = 0; rr < this->Size(); rr++) { + data_[rr] *= arr.data_[rr]; + } + return *this; +} + +// operator overload for elementwise division +template +multiArray3d & multiArray3d::operator/=(const multiArray3d &arr) { for (auto rr = 0; rr < this->Size(); rr++) { data_[rr] /= arr.data_[rr]; } @@ -544,31 +1176,7 @@ multiArray3d multiArray3d::Slice(const range &ir, const range &jr, // ir -- i-index range to take slice [inclusive, exclusive) // jr -- j-index range to take slice [inclusive, exclusive) // kr -- k-index range to take slice [inclusive, exclusive) - - // check that slice bounds are within parent array and that end bounds are - // greater than or equal to start bounds - if (!ir.IsInside(this->RangeI()) || !jr.IsInside(this->RangeJ()) || - !kr.IsInside(this->RangeK()) || !ir.IsValid() || !jr.IsValid() || - !kr.IsValid()) { - cerr << "ERROR: Error in multiArray3d::Slice. Cannot take slice with " - << "boundaries " << ir << ", " << jr << ", " << kr << endl - << "from array with ranges " << this->RangeI() << ", " - << this->RangeJ() << ", " << this->RangeK() << endl; - exit(EXIT_FAILURE); - } - - // slices always have 0 ghost cells - multiArray3d arr(ir.Size(), jr.Size(), kr.Size(), 0); - - // s is for index of sliced array, p is for index of parent array - for (int ks = arr.StartK(), kp = kr.Start(); ks < arr.EndK(); ks++, kp++) { - for (int js = arr.StartJ(), jp = jr.Start(); js < arr.EndJ(); js++, jp++) { - for (int is = arr.StartI(), ip = ir.Start(); is < arr.EndI(); is++, ip++) { - arr(is, js, ks) = (*this)(ip, jp, kp); - } - } - } - return arr; + return SliceArray((*this), ir, jr, kr); } // member function to return a slice of the array @@ -577,186 +1185,63 @@ multiArray3d multiArray3d::Slice(const range &ir, const range &jr, // dir is sliced over dirRange. It also has the ability to include or ignore // ghost cells in its planar slices template -multiArray3d multiArray3d::Slice(const string &dir, - const range &dirRange, +multiArray3d multiArray3d::Slice(const string &dir, const range &dirRange, const bool physOnly) const { // dir -- direction of slice // dirRange -- range of slice in direction given // phsOnly -- flag to only include physical cells in the two directions that // are not specified as dir - - if (dir == "i") { - if (physOnly) { - return this->Slice(dirRange, this->PhysRangeJ(), this->PhysRangeK()); - } else { - return this->Slice(dirRange, this->RangeJ(), this->RangeK()); - } - } else if (dir == "j") { - if (physOnly) { - return this->Slice(this->PhysRangeI(), dirRange, this->PhysRangeK()); - } else { - return this->Slice(this->RangeI(), dirRange, this->RangeK()); - } - } else if (dir == "k") { - if (physOnly) { - return this->Slice(this->PhysRangeI(), this->PhysRangeJ(), dirRange); - } else { - return this->Slice(this->RangeI(), this->RangeJ(), dirRange); - } - } else { - cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } + return SliceArray((*this), dir, dirRange, physOnly); } -// member function to return a slice of the array -// overload to slice line out of array -template -multiArray3d multiArray3d::Slice(const string &dir, int d2Ind, - int d3Ind, const bool physOnly, - const string id, const bool upper2, - const bool upper3) const { - // dir -- direction of line slice (direction 1) - // d2Ind -- index of direction 2 - // d3Ind -- index of direction 3 - // physOnly -- flag to only include physical cells in line slice - // id -- type of multiArray3d being sliced: cell, i, j, or k - // d2Ind and d3Ind are supplied as cell indices, but may need to be - // altered if the array is storing i, j, or k face data - // upper2 -- flag to determine if direction 2 is at upper index - // upper3 -- flag to determine if direction 3 is at upper index - - if (dir == "i") { // d2 = j, d3 = k - if (upper2 && id == "j") { - d2Ind++; - } else if (upper3 && id == "k") { - d3Ind++; - } - - if (physOnly) { - return this->Slice(this->PhysRangeI(), d2Ind, d3Ind); - } else { - return this->Slice(this->RangeI(), d2Ind, d3Ind); - } - } else if (dir == "j") { // d2 = k, d3 = i - if (upper2 && id == "k") { - d2Ind++; - } else if (upper3 && id == "i") { - d3Ind++; - } - - if (physOnly) { - return this->Slice(d3Ind, this->PhysRangeJ(), d2Ind); - } else { - return this->Slice(d3Ind, this->RangeJ(), d2Ind); - } - } else if (dir == "k") { // d2 = i, d3 = j - if (upper2 && id == "i") { - d2Ind++; - } else if (upper3 && id == "j") { - d3Ind++; - } - - if (physOnly) { - return this->Slice(d2Ind, d3Ind, this->PhysRangeK()); - } else { - return this->Slice(d2Ind, d3Ind, this->RangeK()); - } - } else { - cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } -} - -// overload to slice plane out of array -// Identical to previous slice overload, but more general in that in can slice -// over a subset of direction 2 & 3. This is useful to slice out a plane that -// borders a boundary condition patch. -template -multiArray3d multiArray3d::Slice(const string &dir, int dirInd, - range dir1, range dir2, - const string id, const int type) const { - // dir -- normal direction of planar slice - // dirInd -- index in normal direction - // dir1 -- range of direction 1 (direction 3 is normal to slice) - // dir2 -- range of direction 2 (direction 3 is normal to slice) - // id -- id of array being sliced (i, j, k for faces, cell for cells) - // type -- surface type of dir - - if (dir == "i") { // d1 = j, d2 = k - if (type == 2 && id == "i") { // upper i-surface & i face data - dirInd++; - } - if (id == "j") { - dir1.GrowEnd(); - } else if (id == "k") { - dir2.GrowEnd(); - } - return this->Slice(dirInd, dir1, dir2); - } else if (dir == "j") { // d1 = k, d2 = i - if (type == 4 && id == "j") { // upper j-surface & j face data - dirInd++; - } - if (id == "k") { - dir1.GrowEnd(); - } else if (id == "i") { - dir2.GrowEnd(); - } - return this->Slice(dir2, dirInd, dir1); - } else if (dir == "k") { // d1 = i, d2 = j - if (type == 6 && id == "k") { // upper k-surface & k face data - dirInd++; - } - if (id == "i") { - dir1.GrowEnd(); - } else if (id == "j") { - dir2.GrowEnd(); - } - return this->Slice(dir1, dir2, dirInd); - } else { - cerr << "ERROR: Error in multiArray3d::Slice, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } +// member function to return a slice of the array +// overload to slice line out of array +template +multiArray3d multiArray3d::Slice(const string &dir, int d2Ind, int d3Ind, + const bool physOnly, const string id, + const bool upper2, + const bool upper3) const { + // dir -- direction of line slice (direction 1) + // d2Ind -- index of direction 2 + // d3Ind -- index of direction 3 + // physOnly -- flag to only include physical cells in line slice + // id -- type of multiArray3d being sliced: cell, i, j, or k + // d2Ind and d3Ind are supplied as cell indices, but may need to be + // altered if the array is storing i, j, or k face data + // upper2 -- flag to determine if direction 2 is at upper index + // upper3 -- flag to determine if direction 3 is at upper index + return SliceArray((*this), dir, d2Ind, d3Ind, physOnly, id, upper2, upper3); +} + +// overload to slice plane out of array +// Identical to previous slice overload, but more general in that in can slice +// over a subset of direction 2 & 3. This is useful to slice out a plane that +// borders a boundary condition patch. +template +multiArray3d multiArray3d::Slice(const string &dir, int dirInd, + range dir1, range dir2, const string id, + const int type) const { + // dir -- normal direction of planar slice + // dirInd -- index in normal direction + // dir1 -- range of direction 1 (direction 3 is normal to slice) + // dir2 -- range of direction 2 (direction 3 is normal to slice) + // id -- id of array being sliced (i, j, k for faces, cell for cells) + // type -- surface type of dir + return SliceArray((*this), dir, dirInd, dir1, dir2, id, type); } // member function to insert an array into this one // this is the main insert funciton that all other overloaded insert functions // call template +template void multiArray3d::Insert(const range &ir, const range &jr, const range &kr, - const multiArray3d &arr) { + const TT &arr) { // ir -- i-index range to take slice [inclusive, exclusive) // jr -- j-index range to take slice [inclusive, exclusive) // kr -- k-index range to take slice [inclusive, exclusive) // arr -- array to insert into this one - - // check that given bounds fit in this, sizes match, and that bounds are valid - if (!ir.IsInside(this->RangeI()) || !jr.IsInside(this->RangeJ()) || - !kr.IsInside(this->RangeK()) || - ir.Size() != arr.RangeI().Size() || jr.Size() != arr.RangeJ().Size() || - kr.Size() != arr.RangeK().Size() || - !ir.IsValid() || !jr.IsValid() || !kr.IsValid()) { - cerr << "ERROR: Error in multiArray3d::Insert. Given array does not fit in " - << "given bounds" << endl - << "Given bounds: " << ir << ", " << jr << ", " << kr << endl - << "Bounds of array being inserted: " << arr.RangeI() << ", " - << arr.RangeJ() << ", " << arr.RangeK() << endl; - cerr << "Bounds of array accepting data: " << this->RangeI() << ", " - << this->RangeJ() << ", " << this->RangeK() << endl; - exit(EXIT_FAILURE); - } - - // s is for index of sliced array, p is for index of parent array - for (int ks = arr.StartK(), kp = kr.Start(); ks < arr.EndK(); ks++, kp++) { - for (int js = arr.StartJ(), jp = jr.Start(); js < arr.EndJ(); js++, jp++) { - for (int is = arr.StartI(), ip = ir.Start(); is < arr.EndI(); is++, ip++) { - (*this)(ip, jp, kp) = arr(is, js, ks); - } - } - } + InsertArray((*this), ir, jr, kr, arr); } // Overload to insert only in one direction. Given a 3D array, this inserts a @@ -764,46 +1249,24 @@ void multiArray3d::Insert(const range &ir, const range &jr, const range &kr, // dir is inserted over dirRange. It also has the ability to include or ignore // ghost cells in its planar inserts template +template void multiArray3d::Insert(const string &dir, const range &dirRange, - const multiArray3d &arr, - const bool physOnly) { + const TT &arr, const bool physOnly) { // dir -- direction of slice to insert // dirRange -- range to insert slice into in direction given // arr -- array to insert // phsOnly -- flag to only include physical cells in the two directions that // are not specified as dir - - if (dir == "i") { - if (physOnly) { - return this->Insert(dirRange, this->PhysRangeJ(), this->PhysRangeK(), arr); - } else { - return this->Insert(dirRange, this->RangeJ(), this->RangeK(), arr); - } - } else if (dir == "j") { - if (physOnly) { - return this->Insert(this->PhysRangeI(), dirRange, this->PhysRangeK(), arr); - } else { - return this->Insert(this->RangeI(), dirRange, this->RangeK(), arr); - } - } else if (dir == "k") { - if (physOnly) { - return this->Insert(this->PhysRangeI(), this->PhysRangeJ(), dirRange, arr); - } else { - return this->Insert(this->RangeI(), this->RangeJ(), dirRange, arr); - } - } else { - cerr << "ERROR: Error in multiArray3d::Insert, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } + InsertArray((*this), dir, dirRange, arr, physOnly); } // overload to insert line into array template +template void multiArray3d::Insert(const string &dir, int d2Ind, int d3Ind, - const multiArray3d &arr, - const bool physOnly, const string id, - const bool upper2, const bool upper3) { + const TT &arr, const bool physOnly, + const string id, const bool upper2, + const bool upper3) { // dir -- direction of line slice to insert (direction 1) // d2Ind -- index of direction 2 to insert into // d3Ind -- index of direction 3 to insert into @@ -813,48 +1276,7 @@ void multiArray3d::Insert(const string &dir, int d2Ind, int d3Ind, // altered if the array is storing i, j, or k face data // upper2 -- flag to determine if direction 2 is at upper index // upper3 -- flag to determine if direction 3 is at upper index - - if (dir == "i") { // d2 = j, d3 = k - if (upper2 && id == "j") { - d2Ind++; - } else if (upper3 && id == "k") { - d3Ind++; - } - - if (physOnly) { - return this->Insert(this->PhysRangeI(), d2Ind, d3Ind, arr); - } else { - return this->Insert(this->RangeI(), d2Ind, d3Ind, arr); - } - } else if (dir == "j") { // d2 = k, d3 = i - if (upper2 && id == "k") { - d2Ind++; - } else if (upper3 && id == "i") { - d3Ind++; - } - - if (physOnly) { - return this->Insert(d3Ind, this->PhysRangeJ(), d2Ind, arr); - } else { - return this->Insert(d3Ind, this->RangeJ(), d2Ind, arr); - } - } else if (dir == "k") { // d2 = i, d3 = j - if (upper2 && id == "i") { - d2Ind++; - } else if (upper3 && id == "j") { - d3Ind++; - } - - if (physOnly) { - return this->Insert(d2Ind, d3Ind, this->PhysRangeK(), arr); - } else { - return this->Insert(d2Ind, d3Ind, this->RangeK(), arr); - } - } else { - cerr << "ERROR: Error in multiArray3d::Insert, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } + InsertArray((*this), dir, d2Ind, d3Ind, arr, physOnly, id, upper2, upper3); } // overload to insert plane into array @@ -862,9 +1284,10 @@ void multiArray3d::Insert(const string &dir, int d2Ind, int d3Ind, // over a subset of direction 2 & 3. This is useful to insert into a plane that // borders a boundary condition patch. template +template void multiArray3d::Insert(const string &dir, int dirInd, range dir1, - range dir2, const multiArray3d &arr, - const string id, const int type) { + range dir2, const TT &arr, const string id, + const int type) { // dir -- normal direction of planar slice // dirInd -- index in normal direction // dir1 -- range of direction 1 (direction 3 is normal to slice) @@ -872,42 +1295,7 @@ void multiArray3d::Insert(const string &dir, int dirInd, range dir1, // arr -- array to insert // id -- id of array being inserted into (i, j, k for faces, cell for cells) // type -- surface type of dir - - if (dir == "i") { // d1 = j, d2 = k - if (type == 2 && id == "i") { // upper i-surface & i normal - dirInd++; - } - if (id == "j") { - dir1.GrowEnd(); - } else if (id == "k") { - dir2.GrowEnd(); - } - return this->Insert(dirInd, dir1, dir2, arr); - } else if (dir == "j") { // d1 = k, d2 = i - if (type == 4 && id == "j") { // upper j-surface & j normal - dirInd++; - } - if (id == "k") { - dir1.GrowEnd(); - } else if (id == "i") { - dir2.GrowEnd(); - } - return this->Insert(dir2, dirInd, dir1, arr); - } else if (dir == "k") { // d1 = i, d2 = j - if (type == 6 && id == "k") { // upper k-surface & k normal - dirInd++; - } - if (id == "i") { - dir1.GrowEnd(); - } else if (id == "j") { - dir2.GrowEnd(); - } - return this->Insert(dir1, dir2, dirInd, arr); - } else { - cerr << "ERROR: Error in multiArray3d::Insert, direction " << dir - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } + InsertArray((*this), dir, dirInd, dir1, dir2, arr, id, type); } // member function to fill this array with data from a provided one @@ -915,72 +1303,30 @@ void multiArray3d::Insert(const string &dir, int dirInd, range dir1, // the data can now be accessed with the i, j, k indices from *this // if this is not wanted SameSizeResize or SameSizeResizeGhosts can be used template -void multiArray3d::Fill(const multiArray3d &arr) { +template +void multiArray3d::Fill(const TT &arr) { // arr -- array to insert into this one +#ifndef NDEBUG // check that given array is same size if (this->Size() != arr.Size()) { - cerr << "ERROR: Error in multiArray3d::Fill. Size of given array " << - "does not match size of array to fill!" << endl; + cerr << "ERROR: Error in multiArray3d::Fill. Size of given array " + << "does not match size of array to fill!" << endl; cerr << "Size of given array is " << arr.NumI() << ", " << arr.NumJ() << ", " << arr.NumK() << endl; cerr << "With " << arr.GhostLayers() << " ghost cell layers" << endl; cerr << "Resulting in a total size of " << arr.Size() << endl; - cerr << "Size of array to fill is " << numI_ << ", " << numJ_ << - ", " << numK_ << endl; + cerr << "Size of array to fill is " << numI_ << ", " << numJ_ << ", " + << numK_ << endl; cerr << "With " << numGhosts_ << " ghost cell layers" << endl; cerr << "Resulting in a total size of " << this->Size() << endl; exit(EXIT_FAILURE); } +#endif data_ = arr.data_; } -template -multiArray3d multiArray3d::GrowI() const { - multiArray3d arr(this->NumINoGhosts() + 1, this->NumJNoGhosts(), - this->NumKNoGhosts(), numGhosts_); - for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { - for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { - for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { - arr(ii, jj, kk) = (ii == arr.EndI() - 1) ? (*this)(ii - 1, jj, kk) : - (*this)(ii, jj, kk); - } - } - } - return arr; -} - -template -multiArray3d multiArray3d::GrowJ() const { - multiArray3d arr(this->NumINoGhosts(), this->NumJNoGhosts() + 1, - this->NumKNoGhosts(), numGhosts_); - for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { - for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { - for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { - arr(ii, jj, kk) = (jj == arr.EndJ() - 1) ? (*this)(ii, jj - 1, kk) : - (*this)(ii, jj, kk); - } - } - } - return arr; -} - -template -multiArray3d multiArray3d::GrowK() const { - multiArray3d arr(this->NumINoGhosts(), this->NumJNoGhosts(), - this->NumKNoGhosts() + 1, numGhosts_); - for (auto kk = arr.StartK(); kk < arr.EndK(); kk++) { - for (auto jj = arr.StartJ(); jj < arr.EndJ(); jj++) { - for (auto ii = arr.StartI(); ii < arr.EndI(); ii++) { - arr(ii, jj, kk) = (kk == arr.EndK() - 1) ? (*this)(ii, jj, kk - 1) : - (*this)(ii, jj, kk); - } - } - } - return arr; -} - template void multiArray3d::SameSizeResize(const int &ii, const int&jj, const int &kk) { @@ -1010,24 +1356,6 @@ void multiArray3d::SameSizeResizeGhosts(const int &ii, const int&jj, numGhosts_ = ng; } - -// member function to "zero out" the container with a supplied "zero" -template -void multiArray3d::Zero(const T &zero) { - for (auto &val : data_) { - val = zero; - } -} - -// member function to "zero out" the container with an available "Zero" function -template -void multiArray3d::Zero() { - for (auto &val : data_) { - val.Zero(); - } -} - - // operation overload for << - allows use of cout, cerr, etc. template ostream &operator<<(ostream &os, const multiArray3d &arr) { @@ -1046,45 +1374,26 @@ ostream &operator<<(ostream &os, const multiArray3d &arr) { } template -void multiArray3d::PutSlice(const multiArray3d &array, - const connection &inter, const int &d3) { +multiArray3d multiArray3d::GrowI() const { + return GrowInI(*this); +} +template +multiArray3d multiArray3d::GrowJ() const { + return GrowInJ(*this); +} +template +multiArray3d multiArray3d::GrowK() const { + return GrowInK(*this); +} + +template +template +void multiArray3d::PutSlice(const TT &array, const connection &inter, + const int &d3) { // array -- array to insert into *this // inter -- connection data structure defining patches and orientation // d3 -- distance of direction normal to patch to insert - - // check that number of cells to insert matches - auto blkCell = inter.Dir1LenFirst() * inter.Dir2LenFirst() * d3; - if (blkCell != array.Size()) { - cerr << "ERROR: Error in multiArray3d::PutSlice(). Number of cells " - "being inserted does not match designated space to insert." << endl; - cerr << "Direction 1, 2, 3 of multiArray3d to insert into: " - << inter.Dir1LenFirst() << ", " << inter.Dir2LenFirst() << ", " - << d3 << endl; - cerr << "Direction I, J, K of multiArray3d to insert: " << array.NumI() - << ", " << array.NumJ() << ", " << array.NumK() << endl; - exit(EXIT_FAILURE); - } - - // adjust insertion indices if patch borders another connection on the same - // surface of the block - const auto adjS1 = (inter.Dir1StartInterBorderFirst()) ? numGhosts_ : 0; - const auto adjE1 = (inter.Dir1EndInterBorderFirst()) ? numGhosts_ : 0; - const auto adjS2 = (inter.Dir2StartInterBorderFirst()) ? numGhosts_ : 0; - const auto adjE2 = (inter.Dir2EndInterBorderFirst()) ? numGhosts_ : 0; - - // loop over cells to insert - for (auto l3 = 0; l3 < d3; l3++) { - for (auto l2 = adjS2; l2 < inter.Dir2LenFirst() - adjE2; l2++) { - for (auto l1 = adjS1; l1 < inter.Dir1LenFirst() - adjE1; l1++) { - // get acceptor and inserter indices - auto indA = GetSwapLoc(l1, l2, l3, numGhosts_, inter, d3, true); - auto indI = GetSwapLoc(l1, l2, l3, array.numGhosts_, inter, d3, false); - - // assign cell data - (*this)(indA[0], indA[1], indA[2]) = array(indI[0], indI[1], indI[2]); - } - } - } + InsertSlice((*this), array, inter, d3); } /*Member function to pack an array into a buffer, swap it with its @@ -1105,9 +1414,8 @@ void multiArray3d::PackSwapUnpackMPI(const connection &inter, // add size for states MPI_Pack_size(this->Size(), MPI_arrData, MPI_COMM_WORLD, &tempSize); bufSize += tempSize; - // add size for 4 ints for multiArray3d dims and num ghosts - MPI_Pack_size(4, MPI_INT, MPI_COMM_WORLD, - &tempSize); + // add size for 5 ints for multiArray3d dims and num ghosts + MPI_Pack_size(5, MPI_INT, MPI_COMM_WORLD, &tempSize); bufSize += tempSize; // allocate buffer to pack data into @@ -1120,17 +1428,15 @@ void multiArray3d::PackSwapUnpackMPI(const connection &inter, auto numJ = this->NumJ(); auto numK = this->NumK(); auto numGhosts = this->GhostLayers(); + auto blkSize = this->BlockSize(); auto position = 0; - MPI_Pack(&numI, 1, MPI_INT, buffer, bufSize, &position, - MPI_COMM_WORLD); - MPI_Pack(&numJ, 1, MPI_INT, buffer, bufSize, &position, - MPI_COMM_WORLD); - MPI_Pack(&numK, 1, MPI_INT, buffer, bufSize, &position, - MPI_COMM_WORLD); - MPI_Pack(&numGhosts, 1, MPI_INT, buffer, bufSize, &position, - MPI_COMM_WORLD); - MPI_Pack(&(*std::begin(data_)), this->Size(), MPI_arrData, buffer, - bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&numI, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&numJ, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&numK, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&numGhosts, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&blkSize, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(data_)), this->Size(), MPI_arrData, buffer, bufSize, + &position, MPI_COMM_WORLD); MPI_Status status; if (rank == inter.RankFirst()) { // send/recv with second entry in connection @@ -1143,14 +1449,13 @@ void multiArray3d::PackSwapUnpackMPI(const connection &inter, // put slice back into multiArray3d position = 0; - MPI_Unpack(buffer, bufSize, &position, &numI, 1, MPI_INT, - MPI_COMM_WORLD); - MPI_Unpack(buffer, bufSize, &position, &numJ, 1, MPI_INT, - MPI_COMM_WORLD); - MPI_Unpack(buffer, bufSize, &position, &numK, 1, MPI_INT, - MPI_COMM_WORLD); + MPI_Unpack(buffer, bufSize, &position, &numI, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buffer, bufSize, &position, &numJ, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buffer, bufSize, &position, &numK, 1, MPI_INT, MPI_COMM_WORLD); MPI_Unpack(buffer, bufSize, &position, &numGhosts, 1, MPI_INT, MPI_COMM_WORLD); + MPI_Unpack(buffer, bufSize, &position, &blkSize, 1, MPI_INT, MPI_COMM_WORLD); + // resize slice this->SameSizeResize(numI, numJ, numK); @@ -1170,42 +1475,7 @@ void multiArray3d::SwapSliceMPI(const connection &conn, const int &rank, // rank -- processor rank // MPI_arrData -- MPI datatype for passing data in *this // tag -- id for MPI swap (default 1) - - // Get indices for slice coming from block to swap - auto is = 0, ie = 0; - auto js = 0, je = 0; - auto ks = 0, ke = 0; - - if (rank == conn.RankFirst()) { // local block first in connection - conn.FirstSliceIndices(is, ie, js, je, ks, ke, numGhosts_); - } else if (rank == conn.RankSecond()) { // local block second in connection - conn.SecondSliceIndices(is, ie, js, je, ks, ke, numGhosts_); - } else { - cerr << "ERROR: Error in procBlock::SwapSliceMPI(). Processor rank does " - "not match either of connection ranks!" << endl; - exit(EXIT_FAILURE); - } - - // get local state slice to swap - auto slice = this->Slice({is, ie}, {js, je}, {ks, ke}); - - // swap state slices with partner block - slice.PackSwapUnpackMPI(conn, MPI_arrData, rank, tag); - - // change connections to work with slice and ghosts - auto connAdj = conn; - - // change connections to work with slice and ghosts - // block to insert into is first in connection - if (rank == conn.RankFirst()) { - connAdj.AdjustForSlice(true, numGhosts_); - } else { // block to insert into is second in connection, so pass swapped - // version - connAdj.AdjustForSlice(false, numGhosts_); - } - - // insert state slice into procBlock - this->PutSlice(slice, connAdj, numGhosts_); + SwapSliceParallel((*this), conn, rank, MPI_arrData, tag); } /* Function to swap ghost cells between two blocks at an connection @@ -1228,38 +1498,11 @@ logic ensures that the ghost cells at the connection boundary exactly match their partner block as if there were no separation in the grid. */ template -void multiArray3d::SwapSlice(const connection &conn, - multiArray3d &array) { +template +void multiArray3d::SwapSlice(const connection &conn, TT &array) { // conn -- connection boundary information // array -- second array involved in connection boundary - - // Get indices for slice coming from first block to swap - auto is1 = 0, ie1 = 0; - auto js1 = 0, je1 = 0; - auto ks1 = 0, ke1 = 0; - - conn.FirstSliceIndices(is1, ie1, js1, je1, ks1, ke1, numGhosts_); - - // Get indices for slice coming from second block to swap - auto is2 = 0, ie2 = 0; - auto js2 = 0, je2 = 0; - auto ks2 = 0, ke2 = 0; - - conn.SecondSliceIndices(is2, ie2, js2, je2, ks2, ke2, array.GhostLayers()); - - // get slices to swap - auto slice1 = this->Slice({is1, ie1}, {js1, je1}, {ks1, ke1}); - auto slice2 = array.Slice({is2, ie2}, {js2, je2}, {ks2, ke2}); - - // change connections to work with slice and ghosts - connection conn1 = conn; - connection conn2 = conn; - conn1.AdjustForSlice(false, numGhosts_); - conn2.AdjustForSlice(true, array.GhostLayers()); - - // put slices in proper blocks - this->PutSlice(slice2, conn2, array.GhostLayers()); - array.PutSlice(slice1, conn1, numGhosts_); + SwapSliceLocal((*this), conn, array); } diff --git a/include/output.hpp b/include/output.hpp index b8d8f4d..ee69dff 100644 --- a/include/output.hpp +++ b/include/output.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,8 +29,8 @@ It also writes out a master file in Ensight format to name the Plot3D functions. #include #include // vector #include // string -#include // unique_ptr #include "multiArray3d.hpp" +#include "blkMultiArray3d.hpp" using std::vector; using std::string; @@ -40,20 +40,17 @@ using std::ifstream; using std::cout; using std::endl; using std::cerr; -using std::unique_ptr; using std::ostream; // forward class declarations class procBlock; -class genArray; +class conserved; class decomposition; -class eos; -class transport; -class thermodynamic; +class physics; class resid; class input; -class turbModel; -class primVars; +class primitive; +class residual; // function definitions template @@ -63,40 +60,33 @@ void WriteCellCenter(const string &, const vector &, const decomposition &, const input &); void WriteWallFaceCenter(const string &, const vector &, const double &); -void WriteFun(const vector &, const unique_ptr &, - const unique_ptr &thermo, - const unique_ptr &, const int &, const decomposition &, - const input &, const unique_ptr &); -void WriteWallFun(const vector &, const unique_ptr &, - const unique_ptr &, const int &, const input &, - const unique_ptr &); +void WriteFun(const vector &, const physics &phys, const int &, + const decomposition &, const input &); +void WriteWallFun(const vector &, const physics &phys, const int &, + const input &); void WriteMeta(const input &, const int &); void WriteWallMeta(const input &, const int &); -void WriteRestart(const vector &, const unique_ptr &, - const unique_ptr &, const int &, - const decomposition &, const input &, const genArray &); +void WriteRestart(const vector &, const physics &, const int &, + const decomposition &, const input &, const residual &); void ReadRestart(vector &, const string &, const decomposition &, - input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const unique_ptr &, - genArray &, const vector> &); - -multiArray3d ReadSolFromRestart(ifstream &, const input &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const vector &, const int &, - const int &, const int &); -multiArray3d ReadSolNm1FromRestart( - ifstream &, const input &, const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const vector &, const int &, const int &, const int &); - -void WriteResiduals(const input &, genArray &, const genArray &, const resid &, + input &, const physics &, residual &, + const vector> &); + +blkMultiArray3d ReadSolFromRestart(ifstream &, const input &, + const physics &, + const vector &, + const int &, const int &, + const int &, const int &); +blkMultiArray3d ReadSolNm1FromRestart(ifstream &, const input &, + const physics &, + const vector &, + const int &, const int &, + const int &, const int &); + +void WriteResiduals(const input &, residual &, const residual &, const resid &, const double &, const int &, const int &, ostream &); -void PrintResiduals(const input &, genArray &, const genArray &, const resid &, +void PrintResiduals(const input &, residual &, const residual &, const resid &, const double &, const int &, const int &, ostream &); void PrintHeaders(const input &, ostream &); @@ -104,4 +94,30 @@ vector Recombine(const vector &, const decomposition &); int SplitBlockNumber(const vector &, const decomposition &, const int &, const int &, const int &, const int &); +// --------------------------------------------------------------------------- +// function definitions +template +void WriteBlockDims(ofstream &outFile, const vector &vars, + int numVars) { + // write number of blocks to file + auto numBlks = static_cast(vars.size()); + outFile.write(reinterpret_cast(&numBlks), sizeof(numBlks)); + + // loop over all blocks and write out imax, jmax, kmax, numVars + for (auto &blk : vars) { + auto dumInt = blk.NumI(); + outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); + dumInt = blk.NumJ(); + outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); + dumInt = blk.NumK(); + outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); + + if (numVars > 0) { + outFile.write(reinterpret_cast(&numVars), sizeof(numVars)); + } + } +} + + + #endif diff --git a/include/parallel.hpp b/include/parallel.hpp index e862c74..38cf6b7 100644 --- a/include/parallel.hpp +++ b/include/parallel.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,7 +26,7 @@ #include // string #include "mpi.h" // parallelism #include "vector3d.hpp" -#include "multiArray3d.hpp" +#include "blkMultiArray3d.hpp" using std::vector; using std::string; @@ -104,7 +104,7 @@ class decomposition { int SplitHistIndex(const int &a) const {return splitHistIndex_[a];} string SplitHistDir(const int &a) const {return splitHistDir_[a];} template - void DecompArray(vector> &) const; + void DecompArray(vector> &) const; void PrintDiagnostics(const vector&) const; // Destructor @@ -122,21 +122,20 @@ decomposition CubicDecomposition(vector&, void SendNumProcBlocks(const vector&, int&); void SendConnections(vector&, const MPI_Datatype&); -void SetDataTypesMPI(MPI_Datatype&, MPI_Datatype&, MPI_Datatype&, MPI_Datatype&, - MPI_Datatype&, MPI_Datatype&, MPI_Datatype&, - MPI_Datatype&, MPI_Datatype&); -void FreeDataTypesMPI(MPI_Datatype&, MPI_Datatype&, MPI_Datatype&, - MPI_Datatype&, MPI_Datatype&, MPI_Datatype&, - MPI_Datatype&, MPI_Datatype&, MPI_Datatype&); - -vector SendProcBlocks(const vector&, const int&, - const int&, const MPI_Datatype&, - const MPI_Datatype&, const MPI_Datatype&, - const MPI_Datatype&, const input &); -void GetProcBlocks(vector&, const vector&, const int&, - const MPI_Datatype&, const MPI_Datatype&, - const MPI_Datatype&, const MPI_Datatype&, - const MPI_Datatype&, const input &); +void SetDataTypesMPI(MPI_Datatype &, MPI_Datatype &, MPI_Datatype &, + MPI_Datatype &, MPI_Datatype &, MPI_Datatype &, + MPI_Datatype &); +void FreeDataTypesMPI(MPI_Datatype &, MPI_Datatype &, MPI_Datatype &, + MPI_Datatype &, MPI_Datatype &, MPI_Datatype &, + MPI_Datatype &); + +vector SendProcBlocks(const vector &, const int &, + const int &, const MPI_Datatype &, + const MPI_Datatype &, + const input &); +void GetProcBlocks(vector &, const vector &, const int &, + const MPI_Datatype &, const MPI_Datatype &, + const MPI_Datatype &, const input &); void MaxLinf(resid*, resid*, int*, MPI_Datatype*); @@ -146,7 +145,7 @@ void BroadcastViscFaces(const MPI_Datatype&, vector> &); template -void decomposition::DecompArray(vector> &arr) const { +void decomposition::DecompArray(vector> &arr) const { // resize vector for split blocks arr.resize(this->NumBlocks()); diff --git a/include/physicsModels.hpp b/include/physicsModels.hpp new file mode 100644 index 0000000..a7b8457 --- /dev/null +++ b/include/physicsModels.hpp @@ -0,0 +1,81 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef PHYSICSMODELSHEADERDEF +#define PHYSICSMODELSHEADERDEF + +// This header file contains the classes for all physics models + +#include +#include "eos.hpp" +#include "transport.hpp" +#include "thermodynamic.hpp" +#include "diffusion.hpp" +#include "turbulence.hpp" + +using std::unique_ptr; + +// forward class declarations +class fluid; + +// class to store all physics models +class physics { + unique_ptr eos_; + unique_ptr transport_; + unique_ptr thermodynamic_; + unique_ptr diffusion_; + unique_ptr turbulence_; + + public: + // Constructor + physics(unique_ptr &eqnState, unique_ptr &trans, + unique_ptr &thermo, unique_ptr &diff, + unique_ptr &turb) + : eos_(std::move(eqnState)), + transport_(std::move(trans)), + thermodynamic_(std::move(thermo)), + diffusion_(std::move(diff)), + turbulence_(std::move(turb)) {} + + // move constructor and assignment operator + physics(physics&&) noexcept = default; + physics& operator=(physics&&) noexcept = default; + + // copy constructor and assignment operator + // class is non-copyable b/c it holds unique_ptrs + physics(const physics&) = delete; + physics& operator=(const physics&) = delete; + + // Member functions + const unique_ptr &EoS() const { return eos_; } + const unique_ptr &Transport() const { return transport_; } + const unique_ptr &Thermodynamic() const { + return thermodynamic_; + } + const unique_ptr &Diffusion() const { return diffusion_; } + const unique_ptr &Turbulence() const { return turbulence_; } + + // Destructor + virtual ~physics() noexcept {} +}; + + +// -------------------------------------------------------------------------- +// function declarations + + + +#endif diff --git a/include/plot3d.hpp b/include/plot3d.hpp index 4e16af0..aeedc83 100644 --- a/include/plot3d.hpp +++ b/include/plot3d.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/primVars.hpp b/include/primVars.hpp deleted file mode 100644 index fc76417..0000000 --- a/include/primVars.hpp +++ /dev/null @@ -1,381 +0,0 @@ -/* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) - - Aither is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Aither is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#ifndef PRIMVARSHEADERDEF // only if the macro PRIMVARSHEADERDEF is not defined - // execute these lines of code -#define PRIMVARSHEADERDEF // define the macro - -/* This header contains the primVars class. - -The primVars class stores the primative variables for the Euler and -Navier-Stokes equations [rho, u, v, w, P]. It contains several member functions -to manipulate these primative varibles. It also contains member functions to -extrapolate the primative variables from the cell center to the cell -face using constant and MUSCL reconstruction. It is has a member function to -supply a ghost state given a boundary condition and boundary cell. */ - -#include -#include -#include // vector -#include // string -#include // unique_ptr -#include "vector3d.hpp" // vector3d -#include "eos.hpp" // equation of state -#include "transport.hpp" // transport model -#include "thermodynamic.hpp" // thermodynamic model -#include "multiArray3d.hpp" // multiArray3d -#include "genArray.hpp" // genArray -#include "macros.hpp" - -using std::vector; -using std::string; -using std::ios; -using std::ofstream; -using std::cout; -using std::endl; -using std::cerr; -using std::ostream; -using std::unique_ptr; - -// forward class declarations -class input; -class turbModel; -struct wallVars; - -class primVars { - double data_[NUMVARS]; // primative variables at cell center - - public: - // constructors - primVars(const double &a, const double &b, const double &c, const double &d, - const double &e, const double &f, const double &g) - : data_{a, b, c, d, e, f, g} {} - primVars(const double &a, const double &b, const double &c, const double &d, - const double &e) - : primVars(a, b, c, d, e, 0.0, 0.0) {} - primVars() : primVars(0.0, 0.0, 0.0, 0.0, 0.0) {} - explicit primVars(const double &a) : primVars(a, a, a, a, a, a, a) {} - primVars(const double &r, const vector3d &v, const double &p, - const double &k, const double &w) - : primVars(r, v.X(), v.Y(), v.Z(), p, k, w) {} - primVars(const double &r, const vector3d &v, const double &p) - : primVars(r, v.X(), v.Y(), v.Z(), p) {} - primVars(const genArray &, const bool &, const unique_ptr &, - const unique_ptr &, const unique_ptr &); - - // move constructor and assignment operator - primVars(primVars&&) noexcept = default; - primVars& operator=(primVars&&) noexcept = default; - - // copy constructor and assignment operator - primVars(const primVars&) = default; - primVars& operator=(const primVars&) = default; - - // member functions - double Rho() const { return data_[0]; } - double U() const { return data_[1]; } - double V() const { return data_[2]; } - double W() const { return data_[3]; } - double P() const { return data_[4]; } - double Tke() const { return data_[5]; } - double Omega() const { return data_[6]; } - - void NondimensionalInitialize(const unique_ptr &, const input &, - const unique_ptr &, const int &, - const unique_ptr &); - bool IsZero() const; - primVars Squared() const; - primVars Abs() const; - - inline vector3d Velocity() const; - - inline double Energy(const unique_ptr &, - const unique_ptr &) const; - inline double Enthalpy(const unique_ptr &, - const unique_ptr &) const; - inline double Temperature(const unique_ptr &) const; - inline double SoS(const unique_ptr &, - const unique_ptr &) const; - - inline genArray ConsVars(const unique_ptr &, - const unique_ptr &) const; - primVars UpdateWithConsVars(const unique_ptr &, - const unique_ptr &, - const genArray &, - const unique_ptr &) const; - - void ApplyFarfieldTurbBC(const vector3d &, const double &, - const double &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &); - void LimitTurb(const unique_ptr &); - - double InvCellSpectralRadius(const unitVec3dMag &, - const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &) const; - double InvFaceSpectralRadius(const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &) const; - - double ViscCellSpectralRadius(const unitVec3dMag &, - const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, - const double &, const double &, - const unique_ptr &) const; - double ViscFaceSpectralRadius(const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, - const double &, const double &, - const unique_ptr &) const; - - double CellSpectralRadius(const unitVec3dMag &, - const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, - const double &, const double &, - const unique_ptr &, const bool &) const; - double FaceSpectralRadius(const unitVec3dMag &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, - const double &, const double &, - const unique_ptr &, const bool &) const; - - // operator overloads for addition and subtraction of states - inline primVars & operator+=(const primVars &); - inline primVars & operator-=(const primVars &); - inline primVars & operator*=(const primVars &); - inline primVars & operator/=(const primVars &); - - inline primVars & operator+=(const double &); - inline primVars & operator-=(const double &); - inline primVars & operator*=(const double &); - inline primVars & operator/=(const double &); - - inline primVars operator+(const double &s) const { - auto lhs = *this; - return lhs += s; - } - inline primVars operator-(const double &s) const { - auto lhs = *this; - return lhs -= s; - } - inline primVars operator*(const double &s) const { - auto lhs = *this; - return lhs *= s; - } - inline primVars operator/(const double &s) const { - auto lhs = *this; - return lhs /= s; - } - - friend inline const primVars operator-(const double &lhs, primVars rhs); - friend inline const primVars operator/(const double &lhs, primVars rhs); - - // member function to calculate reconstruction of state variables from cell - // center to cell face assuming value at cell center is constant over cell - // volume; zeroth order reconstruction results in first order accuracy - primVars FaceReconConst() const { return *this; } - - // member function to calculate reconstruction of state variables from cell - // center to cell face this function uses muscle extrapolation resulting in - // higher order accuracy - primVars FaceReconMUSCL(const primVars &, const primVars &, const double &, - const string &, const double &, - const double &, const double &) const; - - // calculate face reconstruction using 5th order weno scheme - primVars FaceReconWENO(const primVars &, const primVars &, const primVars &, - const primVars &, const double &, const double &, - const double &, const double &, const double &, - const bool &) const; - - // member function to calculate Van Albada limiter function - primVars LimiterVanAlbada(const primVars &) const; - primVars LimiterMinmod(const primVars &, const primVars &, - const double &) const; - primVars LimiterNone() const; - - // member function to return the state of the appropriate ghost cell - primVars GetGhostState(const string &, const vector3d &, - const double &, const int &, const input &, - const int &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, wallVars &, - const int = 1) const; - - // destructor - ~primVars() noexcept {} -}; - -// function definitions -// member function to calculate temperature from conserved variables and -// equation of state -double primVars::Temperature(const unique_ptr &eqnState) const { - return eqnState->Temperature(data_[4], data_[0]); -} - -// member function to calculate velocity from conserved variables -vector3d primVars::Velocity() const { - vector3d vel(data_[1], data_[2], data_[3]); - return vel; -} - -// member function to calculate total energy from conserved variables -double primVars::Energy(const unique_ptr &eqnState, - const unique_ptr &thermo) const { - const auto t = this->Temperature(eqnState); - return eqnState->Energy(eqnState->SpecEnergy(thermo, t), - (*this).Velocity().Mag()); -} - -// member function to calculate speed of sound from primative varialbes -double primVars::SoS(const unique_ptr &thermo, - const unique_ptr &eqnState) const { - return sqrt(thermo->Gamma(this->Temperature(eqnState)) * data_[4] / data_[0]); -} - -// member function to calculate enthalpy from conserved variables and equation -// of state -double primVars::Enthalpy(const unique_ptr &eqnState, - const unique_ptr &thermo) const { - const auto t = this->Temperature(eqnState); - return eqnState->Enthalpy(thermo, t, this->Velocity().Mag()); -} - -// member function to calculate conserved variables from primative variables -genArray primVars::ConsVars(const unique_ptr &eqnState, - const unique_ptr &thermo) const { - genArray cv(data_[0], data_[0] * data_[1], data_[0] * data_[2], - data_[0] * data_[3], data_[0] * this->Energy(eqnState, thermo), - data_[0] * data_[5], data_[0] * data_[6]); - return cv; -} - -// operator overload for addition -primVars & primVars::operator+=(const primVars &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] += arr.data_[rr]; - } - return *this; -} - -// operator overload for subtraction with a scalar -primVars & primVars::operator-=(const primVars &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] -= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise multiplication -primVars & primVars::operator*=(const primVars &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] *= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise division -primVars & primVars::operator/=(const primVars &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] /= arr.data_[rr]; - } - return *this; -} - -inline const primVars operator+(primVars lhs, const primVars &rhs) { - return lhs += rhs; -} - -inline const primVars operator-(primVars lhs, const primVars &rhs) { - return lhs -= rhs; -} - -inline const primVars operator*(primVars lhs, const primVars &rhs) { - return lhs *= rhs; -} - -inline const primVars operator/(primVars lhs, const primVars &rhs) { - return lhs /= rhs; -} - -// operator overloads for double ------------------------------------- -// operator overload for addition -primVars & primVars::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; - } - return *this; -} - -// operator overload for subtraction with a scalar -primVars & primVars::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; - } - return *this; -} - -// operator overload for elementwise multiplication -primVars & primVars::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; - } - return *this; -} - -// operator overload for elementwise division -primVars & primVars::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; - } - return *this; -} - -inline const primVars operator+(const double &lhs, primVars rhs) { - return rhs += lhs; -} - -inline const primVars operator-(const double &lhs, primVars rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs - rhs.data_[rr]; - } - return rhs; -} - -inline const primVars operator*(const double &lhs, primVars rhs) { - return rhs *= lhs; -} - -inline const primVars operator/(const double &lhs, primVars rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs / rhs.data_[rr]; - } - return rhs; -} - -ostream &operator<<(ostream &os, const primVars &); - -primVars RoeAveragedState(const primVars&, const primVars&); - -#endif diff --git a/include/primitive.hpp b/include/primitive.hpp new file mode 100644 index 0000000..a753f36 --- /dev/null +++ b/include/primitive.hpp @@ -0,0 +1,283 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef PRIMITIVEHEADERDEF +#define PRIMITIVEHEADERDEF + +/* This header contains the primitive class. + +The primitive class stores the primitive variables for the Euler and +Navier-Stokes equations [rho, u, v, w, P]. It contains several member functions +to manipulate these primitive varibles. It also contains member functions to +extrapolate the primitive variables from the cell center to the cell +face using constant and MUSCL reconstruction. It is has a member function to +supply a ghost state given a boundary condition and boundary cell. */ + +#include +#include +#include // vector +#include // string +#include // unique_ptr +#include "vector3d.hpp" // vector3d +#include "tensor.hpp" // tensor +#include "physicsModels.hpp" +#include "multiArray3d.hpp" // multiArray3d +#include "varArray.hpp" +#include "conserved.hpp" +#include "arrayView.hpp" + +using std::vector; +using std::string; +using std::ios; +using std::ofstream; +using std::cout; +using std::endl; +using std::cerr; +using std::ostream; +using std::unique_ptr; + +// forward class declarations +class input; + +class primitive : public varArray { + public: + // constructors + primitive() : varArray() {} + primitive(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies) {} + primitive(const int &numEqns, const int &numSpecies, const double &val) + : varArray(numEqns, numSpecies, val) {} + template ::value || + std::is_same::value>> + primitive(const T &, const physics &); + primitive(const vector::const_iterator &b, + const vector::const_iterator &e, const int &numSpecies) + : varArray(b, e, numSpecies) {} + + // move constructor and assignment operator + primitive(primitive&&) noexcept = default; + primitive& operator=(primitive&&) noexcept = default; + + // copy constructor and assignment operator + primitive(const primitive&) = default; + primitive& operator=(const primitive&) = default; + + // member functions + primitive CopyData() const { return *this; } + const double & RhoN(const int &ii) const { return this->SpeciesN(ii); } + double Rho() const { return this->SpeciesSum(); } + vector RhoVec() const { + return {this->begin(), this->begin() + this->NumSpecies()}; + } + double MassFractionN(const int &ii) const { + return this->RhoN(ii) / this->Rho(); + } + vector MassFractions() const { + vector mf(this->NumSpecies()); + const auto totalRho = this->Rho(); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = this->RhoN(ii) / totalRho; + } + return mf; + } + vector VolumeFractions(const unique_ptr &trans) const { + return trans->MoleFractions(this->MassFractions()); + } + const double & U() const { return this->MomentumX(); } + const double & V() const { return this->MomentumY(); } + const double & W() const { return this->MomentumZ(); } + const double & P() const { return this->varArray::Energy(); } + const double & Tke() const { return this->TurbulenceN(0); } + const double & Omega() const { return this->TurbulenceN(1); } + const double & TurbN(const int &ii) const { return this->TurbulenceN(ii); } + + void NondimensionalInitialize(const physics &, const input &, const int &); + + primitive Abs() const; + primitive Squared() const { + auto sq = (*this); + return sq *= sq; + } + + arrayView GetView() const { + return {this->begin(), this->end(), this->NumSpecies()}; + } + + vector3d Velocity() const { + return {this->U(), this->V(), this->W()}; + } + + double Energy(const physics &phys) const { + return InternalEnergy(*this, phys); + } + double SpeciesEnthalpy(const physics &phys, const int &ss) const { + return SpeciesEnthalpyFunc(*this, phys, ss); + } + double Enthalpy(const physics &phys) const { + return EnthalpyFunc(*this, phys); + } + double Temperature(const unique_ptr &eqnState) const { + return eqnState->Temperature(this->P(), this->RhoVec()); + } + double SoS(const physics &phys) const { return SpeedOfSound(*this, phys); } + + inline conserved ConsVars(const physics &) const; + primitive UpdateWithConsVars(const physics &, const varArrayView &) const; + + void ApplyFarfieldTurbBC(const vector3d &, const double &, + const double &, const physics &); + void LimitTurb(const unique_ptr &); + + // destructor + ~primitive() noexcept {} +}; + +// --------------------------------------------------------------------------- +// constructors +template +primitive::primitive(const T &cons, const physics &phys) { + // cons -- array of conserved variables + // phys -- physics models + + *this = primitive(cons.Size(), cons.NumSpecies()); + + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + (*this)[ii] = cons.SpeciesN(ii); + } + + const auto rho = cons.SpeciesSum(); + (*this)[this->MomentumXIndex()] = cons.MomentumX() / rho; + (*this)[this->MomentumYIndex()] = cons.MomentumY() / rho; + (*this)[this->MomentumZIndex()] = cons.MomentumZ() / rho; + + const auto energy = cons.Energy() / rho; + (*this)[this->EnergyIndex()] = phys.EoS()->PressFromEnergy( + phys.Thermodynamic(), this->RhoVec(), energy, this->Velocity().Mag()); + + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[this->TurbulenceIndex() + ii] = cons.TurbulenceN(ii) / rho; + } + + // Adjust turbulence variables to be above minimum if necessary + this->LimitTurb(phys.Turbulence()); +} + +// --------------------------------------------------------------------------- +// non member functions +// function to calculate conserved variables from primitive variables +template +conserved PrimToCons(const T &state, const physics &phys) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + conserved cv(state.Size(), state.NumSpecies()); + for (auto ii = 0; ii < cv.NumSpecies(); ++ii) { + cv[ii] = state[ii]; + } + const auto rho = state.Rho(); + cv[cv.MomentumXIndex()] = rho * state.U(); + cv[cv.MomentumYIndex()] = rho * state.V(); + cv[cv.MomentumZIndex()] = rho * state.W(); + cv[cv.EnergyIndex()] = rho * state.Energy(phys); + for (auto ii = 0; ii < cv.NumTurbulence(); ++ii) { + cv[cv.TurbulenceIndex() + ii] = rho * state.TurbN(ii); + } + return cv; +} + +// function to take in a vector of updates to the conservative +// variables, and update the primitive variables with it. +// this is used in the implicit solver +template +primitive UpdatePrimWithCons(const T &state, const physics &phys, + const varArrayView &du) { + // phys -- physics models + // du -- updates to conservative variables + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + // convert primitive to conservative and update + auto consUpdate = state.ConsVars(phys) + du; + // keep mass fractions positive and renormalize + const auto rho = consUpdate.Rho(); + auto mf = consUpdate.MassFractions(); + auto total = 0.0; + for (auto &frac : mf) { + frac = std::max(frac, 0.0); + total += frac; + } + for (auto &frac : mf) { + frac /= total; + } + for (auto ii = 0; ii < consUpdate.NumSpecies(); ++ii) { + consUpdate[ii] = rho * mf[ii]; + } + return primitive(consUpdate, phys); +} + + + +// --------------------------------------------------------------------------- +// member function to calculate conserved variables from primitive variables +conserved primitive::ConsVars(const physics &phys) const { + return PrimToCons((*this), phys); +} + +ostream &operator<<(ostream &os, const primitive &); + +// function to calculate the Roe averaged state +template +primitive RoeAveragedState(const T1 &left, const T2 &right) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + + // compute Rho averaged quantities + primitive rhoState(left.Size(), left.NumSpecies()); + // density ratio + const auto denRatio = sqrt(right.Rho() / left.Rho()); + // Roe averaged density + for (auto ii = 0; ii < rhoState.NumSpecies(); ++ii) { + rhoState[ii] = left.RhoN(ii) * denRatio; + } + // Roe averaged velocities - u, v, w + rhoState[rhoState.MomentumXIndex()] = + (left.U() + denRatio * right.U()) / (1.0 + denRatio); + rhoState[rhoState.MomentumYIndex()] = + (left.V() + denRatio * right.V()) / (1.0 + denRatio); + rhoState[rhoState.MomentumZIndex()] = + (left.W() + denRatio * right.W()) / (1.0 + denRatio); + + // Roe averaged pressure + rhoState[rhoState.EnergyIndex()] = + (left.P() + denRatio * right.P()) / (1.0 + denRatio); + + // Roe averaged turbulence variables + for (auto ii = 0; ii < rhoState.NumTurbulence(); ++ii) { + rhoState[rhoState.TurbulenceIndex() + ii] = + (left.TurbN(ii) + denRatio * right.TurbN(ii)) / (1.0 + denRatio); + } + + return rhoState; +} + + +#endif diff --git a/include/procBlock.hpp b/include/procBlock.hpp index 392676f..5099919 100644 --- a/include/procBlock.hpp +++ b/include/procBlock.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,9 +27,11 @@ #include "mpi.h" // parallelism #include "vector3d.hpp" // vector3d #include "multiArray3d.hpp" // multiArray3d +#include "blkMultiArray3d.hpp" // blkMultiArray3d #include "tensor.hpp" // tensor -#include "primVars.hpp" // primVars -#include "genArray.hpp" // genArray +#include "primitive.hpp" // primitive +#include "varArray.hpp" // varArray +#include "arrayView.hpp" // primitiveView #include "boundaryConditions.hpp" // connection, patch #include "macros.hpp" #include "uncoupledScalar.hpp" // uncoupledScalar @@ -40,32 +42,29 @@ using std::string; using std::ios; using std::ofstream; using std::ifstream; -using std::cout; -using std::endl; -using std::cerr; using std::unique_ptr; // forward class declarations -class eos; -class transport; -class thermodynamic; class inviscidFlux; class viscousFlux; class input; class geomSlice; class source; -class turbModel; class plot3dBlock; class resid; -class fluxJacobian; class kdtree; +class conserved; +class matMultiArray3d; +class physics; +class turbModel; +class eos; class procBlock { - multiArray3d state_; // primative variables at cell center - multiArray3d consVarsN_; // conserved variables at time n - multiArray3d consVarsNm1_; // conserved variables at time n-1 + blkMultiArray3d state_; // primitive vars at cell center + blkMultiArray3d consVarsN_; // conserved vars at t=n + blkMultiArray3d consVarsNm1_; // conserved vars at t=n-1 - multiArray3d residual_; // cell residual + blkMultiArray3d residual_; // cell residual multiArray3d> fAreaI_; // face area vector for i-faces multiArray3d> fAreaJ_; // face area vector for j-faces @@ -88,8 +87,11 @@ class procBlock { // gradients multiArray3d> velocityGrad_; multiArray3d> temperatureGrad_; + multiArray3d> densityGrad_; + multiArray3d> pressureGrad_; multiArray3d> tkeGrad_; multiArray3d> omegaGrad_; + multiArray3d> mixtureGrad_; // auxillary variables multiArray3d temperature_; @@ -113,66 +115,45 @@ class procBlock { bool isRANS_; bool storeTimeN_; bool isMultiLevelTime_; + bool isMultiSpecies_; // private member functions - void CalcInvFluxI(const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); - void CalcInvFluxJ(const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); - void CalcInvFluxK(const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); - - void CalcViscFluxI(const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); - void CalcViscFluxJ(const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); - void CalcViscFluxK(const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, - multiArray3d &); + void CalcInvFluxI(const physics &, const input &, matMultiArray3d &); + void CalcInvFluxJ(const physics &, const input &, matMultiArray3d &); + void CalcInvFluxK(const physics &, const input &, matMultiArray3d &); + + void CalcViscFluxI(const physics &, const input &, matMultiArray3d &); + void CalcViscFluxJ(const physics &, const input &, matMultiArray3d &); + void CalcViscFluxK(const physics &, const input &, matMultiArray3d &); void CalcCellDt(const int &, const int &, const int &, const double &); - void ExplicitEulerTimeAdvance(const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const int &, - const int &, const int &); - void ImplicitTimeAdvance(const genArray &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const int &, + void ExplicitEulerTimeAdvance(const physics &, const int &, const int &, + const int &); + void ImplicitTimeAdvance(const varArrayView &, const physics &, const int &, const int &, const int &); - void RK4TimeAdvance(const genArray &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const int &, const int &, - const int &, const int &); - - void AddToResidual(const inviscidFlux &, const int &, const int &, - const int &); - void AddToResidual(const viscousFlux &, const int &, const int &, - const int &); - void SubtractFromResidual(const inviscidFlux &, const int &, const int &, - const int &); - void SubtractFromResidual(const viscousFlux &, const int &, const int &, - const int &); - void SubtractFromResidual(const source &, const int &, const int &, - const int &); + void RK4TimeAdvance(const conservedView &, const physics &, const int &, + const int &, const int &, const int &); + template + void AddToResidual(const int &, const int &, const int &, const T &); + template + void SubtractFromResidual(const int &, const int &, const int &, const T &); vector SplitWallData(const string &, const int &); void JoinWallData(const vector &, const string &); + void CalcGradsI(); + void CalcGradsJ(); + void CalcGradsK(); + public: // constructors procBlock(const plot3dBlock &, const int &, const boundaryConditions &, const int &, const int &, const int &, const input &); - procBlock(const int &, const int &, const int &, const int &, const bool &, - const bool &, const bool &, const bool &, const bool &); - procBlock() : procBlock(1, 1, 1, 0, false, false, false, false, false) {} + procBlock(const int &, const int &, const int &, const int &, const int &, + const int &, const bool &, const bool &, const bool &, const bool &, + const bool &, const bool &); + procBlock() + : procBlock(0, 0, 0, 0, 0, 0, false, false, false, false, false, false) {} // move constructor and assignment operator procBlock(procBlock&&) noexcept = default; @@ -183,8 +164,10 @@ class procBlock { procBlock& operator=(const procBlock&) = default; // member functions - int NumCells() const { return residual_.Size(); } - int NumCellsGhosts() const { return state_.Size(); } + int NumCells() const { return residual_.NumBlocks(); } + int NumCellsGhosts() const { return state_.NumBlocks(); } + int NumEquations() const { return residual_(0, 0, 0).Size(); } + int NumSpecies() const { return residual_(0, 0, 0).NumSpecies(); } int NumI() const { return residual_.NumI(); } int NumJ() const { return residual_.NumJ(); } int NumK() const { return residual_.NumK(); } @@ -236,32 +219,30 @@ class procBlock { boundaryConditions BC() const {return bc_;} - primVars State(const int &ii, const int &jj, const int &kk) const { + primitiveView State(const int &ii, const int &jj, const int &kk) const { return state_(ii, jj, kk); } - genArray ConsVarsN(const int &ii, const int &jj, const int &kk) const { + conservedView ConsVarsN(const int &ii, const int &jj, const int &kk) const { return consVarsN_(ii, jj, kk); } - genArray ConsVarsNm1(const int &ii, const int &jj, const int &kk) const { + conservedView ConsVarsNm1(const int &ii, const int &jj, const int &kk) const { return consVarsNm1_(ii, jj, kk); } - multiArray3d SliceState(const int &, const int &, const int &, - const int &, const int &, - const int &) const; + blkMultiArray3d SliceState(const int &, const int &, const int &, + const int &, const int &, + const int &) const; multiArray3d> SliceBoundaryCenters(const int &) const; - void AssignSolToTimeN(const unique_ptr &, - const unique_ptr &); + void AssignSolToTimeN(const physics &); void AssignSolToTimeNm1(); double SolDeltaNCoeff(const int &, const int &, const int &, const input &) const; double SolDeltaNm1Coeff(const int &, const int &, const int &, const input &) const; - genArray SolDeltaMmN(const int &, const int &, const int &, const input &, - const unique_ptr &, - const unique_ptr &) const; - genArray SolDeltaNm1(const int &, const int &, const int &, + varArray SolDeltaMmN(const int &, const int &, const int &, const input &, + const physics &) const; + varArray SolDeltaNm1(const int &, const int &, const int &, const input &) const; double Vol(const int &ii, const int &jj, const int &kk) const { @@ -343,7 +324,7 @@ class procBlock { return wallDist_(ii, jj, kk); } - genArray Residual(const int &ii, const int &jj, const int &kk) const { + residualView Residual(const int &ii, const int &jj, const int &kk) const { return residual_(ii, jj, kk); } double Residual(const int &ii, const int &jj, const int &kk, @@ -352,10 +333,18 @@ class procBlock { } tensor VelGrad(const int &ii, const int &jj, const int &kk) const { - return isViscous_ ? velocityGrad_(ii, jj, kk) : tensor(0.0); + return velocityGrad_(ii, jj, kk); } vector3d TempGrad(const int &ii, const int &jj, const int &kk) const { - return isViscous_ ? temperatureGrad_(ii, jj, kk) : vector3d(); + return temperatureGrad_(ii, jj, kk); + } + vector3d DensityGrad(const int &ii, const int &jj, + const int &kk) const { + return densityGrad_(ii, jj, kk); + } + vector3d PressureGrad(const int &ii, const int &jj, + const int &kk) const { + return pressureGrad_(ii, jj, kk); } vector3d TkeGrad(const int &ii, const int &jj, const int &kk) const { return isRANS_ ? tkeGrad_(ii, jj, kk) : vector3d(); @@ -364,6 +353,10 @@ class procBlock { const int &kk) const { return isRANS_ ? omegaGrad_(ii, jj, kk) : vector3d(); } + vector3d MixtureGrad(const int &ii, const int &jj, const int &kk, + const int &ll) const { + return isMultiSpecies_ ? mixtureGrad_(ii, jj, kk, ll) : vector3d(); + } double Temperature(const int &ii, const int &jj, const int &kk) const { return temperature_(ii, jj, kk); @@ -382,99 +375,68 @@ class procBlock { } void CalcBlockTimeStep(const input &); - void UpdateBlock(const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const multiArray3d &, - const unique_ptr &, const int &, genArray &, + void UpdateBlock(const input &, const physics &, + const blkMultiArray3d &, const int &, residual &, resid &); - void CalcResidualNoSource(const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const input &, - const unique_ptr &, - multiArray3d &); - void CalcSrcTerms(const unique_ptr &, - const unique_ptr &, const input &, - multiArray3d &); + void CalcResidualNoSource(const physics &, const input &, matMultiArray3d &); + void CalcSrcTerms(const physics &, const input &, matMultiArray3d &); void ResetResidWS(); void ResetGradients(); void ResetTurbVars(); - void CleanResizeVecs(const int &, const int &, const int &, const int &); + void CleanResizeVecs(const int &, const int &, const int &, const int &, + const int &, const int &); - void InitializeStates(const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &); + void InitializeStates(const input &, const physics &); void AssignGhostCellsGeom(); void AssignGhostCellsGeomEdge(); - void AssignInviscidGhostCells(const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &); - void AssignInviscidGhostCellsEdge(const input &, const unique_ptr &, - const unique_ptr &thermo, - const unique_ptr &, - const unique_ptr &); - - void AssignViscousGhostCells(const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &); - void AssignViscousGhostCellsEdge(const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &); - multiArray3d GetGhostStates( - const multiArray3d &, const string &, + void AssignInviscidGhostCells(const input &, const physics &); + void AssignInviscidGhostCellsEdge(const input &, const physics &); + + void AssignViscousGhostCells(const input &, const physics &); + void AssignViscousGhostCellsEdge(const input &, const physics &); + blkMultiArray3d GetGhostStates( + const blkMultiArray3d &, const string &, const multiArray3d> &, const multiArray3d &, - const boundarySurface &, const input &, const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const unique_ptr &, const int = 1); - - void CalcGradsI(const int &, const int &, const int &, - tensor &, vector3d &, vector3d &, - vector3d &) const; - void CalcGradsJ(const int &, const int &, const int &, - tensor &, vector3d &, vector3d &, - vector3d &) const; - void CalcGradsK(const int &, const int &, const int &, - tensor &, vector3d &, vector3d &, - vector3d &) const; + const boundarySurface &, const input &, const physics &, const int &, + const multiArray3d & = {}, + const multiArray3d & = {}, + const blkMultiArray3d & = {}, + const multiArray3d> & = {}, + const multiArray3d> & = {}); + + void CalcGradsI(const int &, const int &, const int &, tensor &, + vector3d &, vector3d &, vector3d &, + vector3d &, vector3d &, + vector> &) const; + void CalcGradsJ(const int &, const int &, const int &, tensor &, + vector3d &, vector3d &, vector3d &, + vector3d &, vector3d &, + vector> &) const; + void CalcGradsK(const int &, const int &, const int &, tensor &, + vector3d &, vector3d &, vector3d &, + vector3d &, vector3d &, + vector> &) const; void CalcWallDistance(const kdtree &); - multiArray3d DeltaNMinusOne(const multiArray3d &, - const unique_ptr &, const double &, - const double &) const; - multiArray3d SolTimeMMinusN(const multiArray3d &, - const unique_ptr &, const input &, - const int &) const; - void InvertDiagonal(multiArray3d &, const input &) const; - - multiArray3d InitializeMatrixUpdate( - const input &, const unique_ptr &eos, - const unique_ptr &, - const multiArray3d &) const; - void LUSGS_Forward(const vector> &, multiArray3d &, - const unique_ptr &, const input &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const multiArray3d &, const int &) const; - double LUSGS_Backward(const vector> &, multiArray3d &, - const unique_ptr &, const input &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const multiArray3d &, const int &) const; - - double DPLUR(multiArray3d &, const unique_ptr &, const input &, - const unique_ptr &, const unique_ptr &, - const unique_ptr &, - const multiArray3d &) const; + void InvertDiagonal(matMultiArray3d &, const input &) const; + + blkMultiArray3d InitializeMatrixUpdate( + const input &, const physics &, const matMultiArray3d &) const; + void LUSGS_Forward(const vector> &, blkMultiArray3d &, + const physics &, const input &, const matMultiArray3d &, + const int &) const; + double LUSGS_Backward(const vector> &, + blkMultiArray3d &, const physics &, + const input &, const matMultiArray3d &, + const int &) const; + + double DPLUR(blkMultiArray3d &, const physics &, const input &, + const matMultiArray3d &) const; bool IsPhysical(const int &, const int &, const int &) const; bool AtCorner(const int &, const int &, const int &) const; @@ -484,7 +446,7 @@ class procBlock { int &) const; vector PutGeomSlice(const geomSlice &, connection &, const int &); - void PutStateSlice(const multiArray3d &, const connection &, + void PutStateSlice(const blkMultiArray3d &, const connection &, const int &, const int &); procBlock Split(const string &, const int &, const int &, @@ -492,7 +454,7 @@ class procBlock { void Join(const procBlock &, const string &, vector &); void SwapStateSlice(const connection &, procBlock &); - void SwapStateSliceMPI(const connection &, const int &, const MPI_Datatype &); + void SwapStateSliceMPI(const connection &, const int &); void SwapTurbSlice(const connection &, procBlock &); void SwapTurbSliceMPI(const connection &, const int &); void SwapWallDistSlice(const connection &, procBlock &); @@ -502,21 +464,15 @@ class procBlock { const MPI_Datatype &, const MPI_Datatype &); - void PackSendGeomMPI(const MPI_Datatype &, const MPI_Datatype &, - const MPI_Datatype &, const MPI_Datatype &) const; + void PackSendGeomMPI(const MPI_Datatype &, const MPI_Datatype &) const; void RecvUnpackGeomMPI(const MPI_Datatype &, const MPI_Datatype &, - const MPI_Datatype &, const MPI_Datatype &, const input &); void PackSendSolMPI(const MPI_Datatype &, const MPI_Datatype &, - const MPI_Datatype &, const MPI_Datatype &, const MPI_Datatype &) const; void RecvUnpackSolMPI(const MPI_Datatype &, const MPI_Datatype &, - const MPI_Datatype &, const MPI_Datatype &, const MPI_Datatype &, const input &); - void UpdateAuxillaryVariables(const unique_ptr &, - const unique_ptr &, - const bool = true); + void UpdateAuxillaryVariables(const physics &, const bool = true); void UpdateUnlimTurbEddyVisc(const unique_ptr &, const bool &); double ProjC2CDist(const int &, const int &, const int &, @@ -524,8 +480,8 @@ class procBlock { void DumpToFile(const string &, const string &) const; void CalcCellWidths(); - void GetStatesFromRestart(const multiArray3d &); - void GetSolNm1FromRestart(const multiArray3d &); + void GetStatesFromRestart(const blkMultiArray3d &); + void GetSolNm1FromRestart(const blkMultiArray3d &); int WallDataIndex(const boundarySurface &) const; int WallDataSize() const {return wallData_.size();} @@ -585,10 +541,66 @@ class procBlock { ~procBlock() noexcept {} }; +// ---------------------------------------------------------------------------- // function definitions template -multiArray3d PadWithGhosts(const multiArray3d &, const int &); +void procBlock::AddToResidual(const int &ii, const int &jj, const int &kk, + const T &arr) { + static_assert(std::is_base_of::value, "T must be varArray type"); + MSG_ASSERT(arr.Size() == residual_.BlockSize(), + "array block size must match residual block size"); + for (auto bb = 0; bb < residual_.BlockSize(); ++bb) { + residual_(ii, jj, kk, bb) += arr[bb]; + } +} + +template +void procBlock::SubtractFromResidual(const int &ii, const int &jj, + const int &kk, const T &arr) { + static_assert(std::is_base_of::value, "T must be varArray type"); + MSG_ASSERT(arr.Size() == residual_.BlockSize(), + "array block size must match residual block size"); + for (auto bb = 0; bb < residual_.BlockSize(); ++bb) { + residual_(ii, jj, kk, bb) -= arr[bb]; + } +} + +/* Function to pad a multiArray3d with a specified number of ghost cells + ___ ___ ___ ___ ___ ___ ___ ___ + | E | E | G | G | G | G | E | E | + |___|___|___|___|___|___|___|___| + | E | E | G | G | G | G | E | E | + |___|___|___|___|___|___|___|___| + | G | G | X | X | X | X | G | G | + |___|___|___|___|___|___|___|___| + | G | G | X | X | X | X | G | G | + |___|___|___|___|___|___|___|___| + | E | E | G | G | G | G | E | E | + |___|___|___|___|___|___|___|___| + | E | E | G | G | G | G | E | E | + |___|___|___|___|___|___|___|___| + +In the above diagram, the cells marked with an "X" represent physical cells. The +entire diagram represents the block (in 2D) padded with 2 layers of ghost cells. +The cells marked with "G" are regualar ghost cells. The cells marked with "E" are +ghost cells located along one of the 12 edges that form a plot3d block. In 3D +there are also "corner" cells located at the 8 corners that form the plot3d block. +These cells are not used though. There is a place in the vector for them to make +accessing the padded vector of cells the same as for a plot3d block without ghost +cells. +*/ +template +T PadWithGhosts(const T &var, const int &numGhosts) { + // var -- vector of variables to pad (no ghost cells included) + // numGhosts -- number of layers of ghost cells to pad var with + // T should be multiArray3d or blkMultiArray3d type + + // initialize added array + T padBlk(var.NumI(), var.NumJ(), var.NumK(), numGhosts, var.BlockInfo()); + padBlk.Insert(var.RangeI(), var.RangeJ(), var.RangeK(), var); + return padBlk; +} #endif diff --git a/include/range.hpp b/include/range.hpp index 7198e22..47767f7 100644 --- a/include/range.hpp +++ b/include/range.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/reconstruction.hpp b/include/reconstruction.hpp new file mode 100644 index 0000000..526b4ab --- /dev/null +++ b/include/reconstruction.hpp @@ -0,0 +1,381 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef RECONSTRUCTIONHEADERDEF +#define RECONSTRUCTIONHEADERDEF + +/* This header contains functions to reconstruct the primitive variables from + * the cell centers to the face centers. + */ + +#include // string +#include "arrayView.hpp" +#include "primitive.hpp" +#include "limiter.hpp" +#include "macros.hpp" +#include "utility.hpp" + +using std::string; + +// function definitions +// function to calculate reconstruction of state variables from cell +// center to cell face assuming value at cell center is constant over cell +// volume; zeroth order reconstruction results in first order accuracy +primitive FaceReconConst(const primitive &state) { return state; } +primitive FaceReconConst(const primitiveView &state) { + return state.CopyData(); +} + +// member function to calculate reconstruction of primitive variables from cell +// center to cell face this function uses MUSCL extrapolation resulting in +// higher order accuracy +/* + +____________________|_____________________ +| | Ul|Ur | | +| | | | | +| Ui-1 | Ui | Ui+1 | Ui+2 | +| | | | | +| | | | | +|_________|_________|__________|_________| + | + face to reconstruct state at +<--UW2---><--UW1---><---DW----> + +The diagram above shows the stencil used to reconstruct the left and right +states for a given face. For each reconstruction (right and left) only 3 points +are needed, two upwind points and one downwind point. For the left +reconstruction, Ui is the first upwind point, Ui-1 is the second upwind point, +and Ui+1 is the downwind point. For the right reconstruction Ui+1 is the first +upwind point, Ui+2 is the second upwind point, and Ui is the downwind point. + +For left reconstruction the MUSCL scheme goes as follows: +Ui+1/2 = Ui + 0.25 * ( (1-K) * (Ui - Ui-1) + (1+K) * (Ui+1 - Ui) ) + +The above equation assumes there is no limiter, and that the grid spacing is +uniform. In the above equation K refers to the parameter kappa which can be +varied to produce different reconstructions. Acceptable values of K are [-1,1] +(inclusive) + +K = -1 -- fully upwind reconstruction - linear - results in 2nd order accuracy +K = 0 -- fromm scheme - linear - results in 2nd order accuracy +K = 0.5 -- QUICK scheme - parabolic - results in 2nd order accuracy +K = 1 -- central scheme - linear - results in 2nd order accuracy but is unstable +without dissipation added +K = 1/3 -- third order - parabolic - results 2nd order accuracy with lowest +error +(all order of accuracy estimates assume constant fluxes on cell faces which +limits order of accuracy to 2) + +With limiters the equation looks as follows: +Ui+1/2 = Ui + 0.25 * (Ui - Ui-1) * ( (1-K) * L + (1+K) * R * Linv ) + +L represents the limiter function which ranges between 0 and 1. A value of 1 +implies there is no limiter and the full accuracy of the scheme is achieved. A +value of 0 implies that the solution has been limited to first order accuracy. +An in between value results in an order of accuracy between first and second. +Linv is the inverse of the limiter. + +R represents the divided difference that the limiter is a function of. +R = (Ui - Ui-1) / (Ui+1 - Ui) + +The MUSCL scheme can be extended to nonuniform grids by adding in terms +representing the difference in size between the cells. In the above diagram the +values UW2, UW1, and DW represent the length of the second upwind, first upwind, +and downwind cells respectively. dP and dM represent the factors due to the +change in cell size between the first upwind to downwind and first upwind to +second upwind cells. + +dP = (UW1 + DW) / (2.0 * UW) +dM = (UW + UW2) / (2.0 * UW) +R = ((Ui - Ui-1) / dP) / ((Ui+1 - Ui) / dM) + +Ui+1/2 = Ui + 0.25 * ((Ui - Ui-1) / dM) * ( (1-K) * L + (1+K) * R * Linv ) + +*/ +template +primitive FaceReconMUSCL(const T &upwind2, const T &upwind1, const T &downwind1, + const double &kappa, const string &lim, + const double &uw2, const double &uw, + const double &dw) { + // upwind2 -- upwind cell furthest from the face at which the primitive is + // being reconstructed. + // upwind1 -- upwind cell nearest to the face at which the primitive is + // being reconstructed. + // downwind1 -- downwind cell. + // kappa -- parameter that determines which scheme is implemented + // uw -- length of upwind cell + // uw2 -- length of furthest upwind cell + // dw -- length of downwind cell + + static_assert(std::is_same::value || + std::is_same::value, + "FaceReconMUSCL requires primitive or primativeView type"); + + const auto dPlus = (uw + uw) / (uw + dw); + const auto dMinus = (uw + uw) / (uw + uw2); + + // divided differences to base limiter on + const auto r = (EPS + (downwind1 - upwind1) * dPlus) / + (EPS + (upwind1 - upwind2) * dMinus); + + primitive limiter; + primitive invLimiter; + if (lim == "none") { + limiter = LimiterNone(r.Size(), r.NumSpecies()); + invLimiter = limiter; + } else if (lim == "vanAlbada") { + limiter = LimiterVanAlbada(r); + invLimiter = LimiterVanAlbada(1.0 / r); + } else if (lim == "minmod") { + limiter = LimiterMinmod(r); + invLimiter = LimiterMinmod(1.0 / r); + } else { + cerr << "ERROR: Limiter " << lim << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } + + // calculate reconstructed state at face using MUSCL method with limiter + return upwind1 + 0.25 * ((upwind1 - upwind2) * dMinus) * + ((1.0 - kappa) * limiter + (1.0 + kappa) * r * invLimiter); +} + +// WENO helper functions ----------------------------------------------------- +template +primitive BetaIntegral(const T1 &deriv1, const T2 &deriv2, const double &dx, + const double &x) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + return (deriv1.Squared() * x + deriv1 * deriv2 * x * x + + deriv2.Squared() * pow(x, 3.0) / 3.0) * + dx + + deriv2.Squared() * x * pow(dx, 3.0); +} + +template +primitive BetaIntegral(const T1 &deriv1, const T2 &deriv2, const double &dx, + const double &xl, const double &xh) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + return BetaIntegral(deriv1, deriv2, dx, xh) - + BetaIntegral(deriv1, deriv2, dx, xl); +} + +template +primitive Beta0(const double &x_0, const double &x_1, const double &x_2, + const T1 &y_0, const T2 &y_1, const T3 &y_2) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T2 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T3 requires primitive or primativeView type"); + const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); + const auto deriv1st = + (y_2 - y_1) / (0.5 * (x_2 + x_1)) + 0.5 * x_2 * deriv2nd; + + return BetaIntegral(deriv1st, deriv2nd, x_2, -0.5 * x_2, 0.5 * x_2); +} + +template +primitive Beta1(const double &x_0, const double &x_1, const double &x_2, + const T1 &y_0, const T2 &y_1, const T3 &y_2) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T3 requires primitive or primativeView type"); + const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); + const auto deriv1st = + (y_2 - y_1) / (0.5 * (x_2 + x_1)) - 0.5 * x_1 * deriv2nd; + + return BetaIntegral(deriv1st, deriv2nd, x_1, -0.5 * x_1, 0.5 * x_1); +} + +template +primitive Beta2(const double &x_0, const double &x_1, const double &x_2, + const T1 &y_0, const T2 &y_1, const T3 &y_2) { + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T1 requires primitive or primativeView type"); + static_assert(std::is_same::value || + std::is_same::value, + "T3 requires primitive or primativeView type"); + const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); + const auto deriv1st = + (y_1 - y_0) / (0.5 * (x_1 + x_0)) - 0.5 * x_0 * deriv2nd; + + return BetaIntegral(deriv1st, deriv2nd, x_0, -0.5 * x_0, 0.5 * x_0); +} + +// member function for higher order reconstruction via weno +template +primitive FaceReconWENO(const T &upwind3, const T &upwind2, const T &upwind1, + const T &downwind1, const T &downwind2, + const double &uw3, const double &uw2, const double &uw1, + const double &dw1, const double &dw2, + const bool &isWenoZ) { + // make sure template type is correct + static_assert(std::is_same::value || + std::is_same::value, + "FaceReconWENO requires primitive or primativeView type"); + + // get candidate smaller stencils + const vector cellWidth = {uw3, uw2, uw1, dw1, dw2}; + + constexpr auto degree = 2; + constexpr auto up1Loc = 2; + const auto coeffs0 = LagrangeCoeff(cellWidth, degree, 2, up1Loc); + const auto stencil0 = coeffs0[0] * upwind3 + coeffs0[1] * upwind2 + + coeffs0[2] * upwind1; + + const auto coeffs1 = LagrangeCoeff(cellWidth, degree, 1, up1Loc); + const auto stencil1 = coeffs1[0] * upwind2 + coeffs1[1] * upwind1 + + coeffs1[2] * downwind1; + + const auto coeffs2 = LagrangeCoeff(cellWidth, degree, 0, up1Loc); + const auto stencil2 = coeffs2[0] * upwind1 + coeffs2[1] * downwind1 + + coeffs2[2] * downwind2; + + // get coefficients for large stencil + const auto fullCoeffs = LagrangeCoeff(cellWidth, 4, 2, up1Loc); + + // linear weights + const auto lw0 = fullCoeffs[0] / coeffs0[0]; + const auto lw1 = fullCoeffs[4] / coeffs2[2]; + const auto lw2 = 1.0 - lw0 - lw1; + + const auto beta0 = Beta0(uw3, uw2, uw1, upwind3, upwind2, upwind1); + const auto beta1 = Beta1(uw2, uw1, dw1, upwind2, upwind1, downwind1); + const auto beta2 = Beta2(uw1, dw1, dw2, upwind1, downwind1, downwind2); + + // calculate nonlinear weights + primitive nlw0(upwind3.Size(), upwind3.NumSpecies()); + primitive nlw1(upwind3.Size(), upwind3.NumSpecies()); + primitive nlw2(upwind3.Size(), upwind3.NumSpecies()); + if (isWenoZ) { + // using weno-z weights with q = 2 + const auto tau5 = (beta0 - beta2).Abs(); + constexpr auto eps = 1.0e-40; + nlw0 = lw0 * (1.0 + (tau5 / (eps + beta0)).Squared()); + nlw1 = lw1 * (1.0 + (tau5 / (eps + beta1)).Squared()); + nlw2 = lw2 * (1.0 + (tau5 / (eps + beta2)).Squared()); + } else { // standard WENO + // calculate nonlinear weights + constexpr auto eps = 1.0e-6; + nlw0 = lw0 / (eps + beta0).Squared(); + nlw1 = lw1 / (eps + beta1).Squared(); + nlw2 = lw2 / (eps + beta2).Squared(); + } + + // normalize weights + const auto sum_nlw = nlw0 + nlw1 + nlw2; + nlw0 /= sum_nlw; + nlw1 /= sum_nlw; + nlw2 /= sum_nlw; + + // return weighted contribution of each stencil + return nlw0 * stencil0 + nlw1 * stencil1 + nlw2 * stencil2; +} + +// function to reconstruct cell variables to the face using central +// differences +template +auto FaceReconCentral(const T &varU, const T &varD, + const vector &cellWidth) { + // varU -- variable at the cell center of the upwind cell + // varD -- variable at the cell center of the downwind cell + // cellWidth -- width of cells in stencil + MSG_ASSERT(cellWidth.size() == 2, "cell width size is unexpected"); + + // get coefficients + const auto coeffs = LagrangeCoeff(cellWidth, 1, 0, 0); + + // reconstruct with central difference + return coeffs[0] * varD + coeffs[1] * varU; +} + +// function to reconstruct cell variables to the face using central +// differences (4th order) +template +std::enable_if_t::value && + !std::is_same::value, + T> +FaceReconCentral4th(const T &varU2, const T &varU1, const T &varD1, + const T &varD2, const vector &cellWidth) { + // varU2 -- variable at the cell center of the second upwind cell + // varU1 -- variable at the cell center of the first upwind cell + // varD1 -- variable at the cell center of the first downwind cell + // varD2 -- variable at the cell center of the second downwind cell + // cellWidth -- width of cells in stencil + MSG_ASSERT(cellWidth.size() == 4, "cell width size is unexpected"); + + // get coefficients + const auto coeffs = LagrangeCoeff(cellWidth, 3, 1, 1); + + // reconstruct with central difference + return coeffs[0] * varU2 + coeffs[1] * varU1 + coeffs[2] * varD1 + + coeffs[3] * varD2; +} + +// fourth order reconstruction, but use 2nd order for turbulence variables +// this is needed because fourth order reconstruction has problems with high +// omega gradients at will during simulation start up +template +std::enable_if_t::value || + std::is_same::value, + primitive> +FaceReconCentral4th(const T &varU2, const T &varU1, const T &varD1, + const T &varD2, const vector &cellWidth) { + // varU2 -- variable at the cell center of the second upwind cell + // varU1 -- variable at the cell center of the first upwind cell + // varD1 -- variable at the cell center of the first downwind cell + // varD2 -- variable at the cell center of the second downwind cell + // cellWidth -- width of cells in stencil + MSG_ASSERT(cellWidth.size() == 4, "cell width size is unexpected"); + + // get coefficients + const auto coeffs = LagrangeCoeff(cellWidth, 3, 1, 1); + + // reconstruct with central difference + auto fourth = coeffs[0] * varU2 + coeffs[1] * varU1 + coeffs[2] * varD1 + + coeffs[3] * varD2; + for (auto ii = fourth.TurbulenceIndex(); ii < fourth.Size(); ++ii) { + fourth[ii] = + FaceReconCentral(varU1[ii], varD1[ii], {cellWidth[1], cellWidth[2]}); + } + return fourth; +} + +#endif diff --git a/include/resid.hpp b/include/resid.hpp index 742b32e..8e36d11 100644 --- a/include/resid.hpp +++ b/include/resid.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/slices.hpp b/include/slices.hpp index e50f82e..a6a7c63 100644 --- a/include/slices.hpp +++ b/include/slices.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ #include #include "mpi.h" -#include "primVars.hpp" +#include "primitive.hpp" #include "vector3d.hpp" #include "multiArray3d.hpp" diff --git a/include/source.hpp b/include/source.hpp index 4eb7ea1..035092b 100644 --- a/include/source.hpp +++ b/include/source.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,8 @@ #include #include -#include "macros.hpp" +#include "varArray.hpp" +#include "arrayView.hpp" #include "vector3d.hpp" #include "tensor.hpp" @@ -36,17 +37,15 @@ using std::ostream; using std::unique_ptr; // forward class declaration -class primVars; class turbModel; class transport; class squareMatrix; -class source { - double data_[NUMVARS]; // source variables at cell center - +class source : public residual { public: - // constructors - source() : data_{0.0} {} + // constructor + source(const int &numEqns, const int &numSpecies) + : residual(numEqns, numSpecies) {} // move constructor and assignment operator source(source&&) noexcept = default; @@ -57,160 +56,21 @@ class source { source& operator=(const source&) = default; // member functions - double SrcMass() const { return data_[0]; } - double SrcMomX() const { return data_[1]; } - double SrcMomY() const { return data_[2]; } - double SrcMomZ() const { return data_[3]; } - double SrcEngy() const { return data_[4]; } - double SrcTke() const { return data_[5]; } - double SrcOmg() const { return data_[6]; } - - squareMatrix CalcTurbSrc(const unique_ptr &, const primVars &, + squareMatrix CalcTurbSrc(const unique_ptr &, const primitiveView &, const tensor &, const vector3d &, const vector3d &, const vector3d &, const unique_ptr &, const double &, const double &, const double &, const double &, const double &); - inline source & operator+=(const source &); - inline source & operator-=(const source &); - inline source & operator*=(const source &); - inline source & operator/=(const source &); - - inline source & operator+=(const double &); - inline source & operator-=(const double &); - inline source & operator*=(const double &); - inline source & operator/=(const double &); - - inline source operator+(const double &s) const { - auto lhs = *this; - return lhs += s; - } - inline source operator-(const double &s) const { - auto lhs = *this; - return lhs -= s; - } - inline source operator*(const double &s) const { - auto lhs = *this; - return lhs *= s; - } - inline source operator/(const double &s) const { - auto lhs = *this; - return lhs /= s; - } - - friend inline const source operator-(const double &lhs, source rhs); - friend inline const source operator/(const double &lhs, source rhs); - // destructor ~source() noexcept {} }; -// function definitions ------------------------------------- +ostream &operator<<(ostream &os, const source &); -// operator overload for addition -source & source::operator+=(const source &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] += arr.data_[rr]; - } - return *this; -} - -// operator overload for subtraction with a scalar -source & source::operator-=(const source &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] -= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise multiplication -source & source::operator*=(const source &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] *= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise division -source & source::operator/=(const source &arr) { - for (auto rr = 0; rr < NUMVARS; rr++) { - data_[rr] /= arr.data_[rr]; - } - return *this; -} - -inline const source operator+(source lhs, const source &rhs) { - return lhs += rhs; -} - -inline const source operator-(source lhs, const source &rhs) { - return lhs -= rhs; -} - -inline const source operator*(source lhs, const source &rhs) { - return lhs *= rhs; -} - -inline const source operator/(source lhs, const source &rhs) { - return lhs /= rhs; -} - -// operator overloads for double ------------------------------------- -// operator overload for addition -source & source::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; - } - return *this; -} - -// operator overload for subtraction with a scalar -source & source::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; - } - return *this; -} - -// operator overload for elementwise multiplication -source & source::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; - } - return *this; -} - -// operator overload for elementwise division -source & source::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; - } - return *this; -} - -inline const source operator+(const double &lhs, source rhs) { - return rhs += lhs; -} - -inline const source operator-(const double &lhs, source rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs - rhs.data_[rr]; - } - return rhs; -} - -inline const source operator*(const double &lhs, source rhs) { - return rhs *= lhs; -} - -inline const source operator/(const double &lhs, source rhs) { - for (auto rr = 0; rr < NUMVARS; rr++) { - rhs.data_[rr] = lhs / rhs.data_[rr]; - } - return rhs; -} -ostream &operator<<(ostream &os, const source &); +// function definitions ------------------------------------- + #endif diff --git a/include/spectralRadius.hpp b/include/spectralRadius.hpp new file mode 100644 index 0000000..85dc4c4 --- /dev/null +++ b/include/spectralRadius.hpp @@ -0,0 +1,205 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef SPECTRALRADIUSHEADERDEF +#define SPECTRALRADIUSHEADERDEF + +/* This header contains the functions to calculate the inviscid and viscous + * spectral radii + */ + +#include // string +#include // max +#include "vector3d.hpp" // vector3d +#include "primitive.hpp" +#include "arrayView.hpp" +#include "physicsModels.hpp" + +using std::max; +using std::min; + +/*Function to return the inviscid spectral radius for one direction (i, j, or k) +given a cell state, equation of state, and 2 face area vectors + +L = 0.5 * (A1 + A2) * (|Vn| + SoS) + +In the above equation L is the spectral radius in either the i, j, or k +direction. A1 and A2 are the two face areas in that direction. Vn is the +cell velocity normal to that direction. SoS is the speed of sound at the cell + */ +template +double InvCellSpectralRadius(const T &state, + const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, + const physics &phys) { + // state -- primitive state variables + // fAreaL -- face area of lower face in either i, j, or k direction + // fAreaR -- face area of upper face in either i, j, or k direction + // phys -- physics models + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + // normalize face areas + const auto normAvg = (0.5 * (fAreaL.UnitVector() + + fAreaR.UnitVector())).Normalize(); + // average area magnitude + const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); + + // return spectral radius + return (fabs(state.Velocity().DotProd(normAvg)) + state.SoS(phys)) * fMag; +} + +template +double InvFaceSpectralRadius(const T &state, + const unitVec3dMag &fArea, + const physics &phys) { + // state -- primitive state variables + // fArea -- face area + // phys -- physics models + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + // return spectral radius + return 0.5 * fArea.Mag() * + (fabs(state.Velocity().DotProd(fArea.UnitVector())) + state.SoS(phys)); +} + +/*Function to calculate the viscous spectral radius for one direction (i, j, or +k). + +L = max(4/(3*rho), g/rho) * mu/Pr * A^2 / V + +In the above equation L is the viscous spectral radius for a given direction (i, +j, or k). Rho is the density at the cell center. G is gamma, mu is viscosity, +and Pr is the Prandtl number (all at the cell center). A is the average face area +of the given direction (i, j, k), and V is the cell volume. This implementation +comes from Blazek. + */ +template +double ViscCellSpectralRadius( + const T &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, const physics &phys, + const double &vol, const double &mu, const double &mut) { + // state -- primitive state variables + // fAreaL -- face area of lower face in either i, j, or k direction + // fAreaR -- face area of upper face in either i, j, or k direction + // phys -- physics models + // vol -- cell volume + // mu -- laminar viscosity + // mut -- turbulent viscosity + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + // average area magnitude + const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); + const auto t = state.Temperature(phys.EoS()); + const auto maxTerm = + max(4.0 / (3.0 * state.Rho()), + phys.Thermodynamic()->Gamma(t, state.MassFractions()) / state.Rho()); + // viscous term + const auto viscTerm = + phys.Transport()->NondimScaling() * + (mu / phys.Thermodynamic()->Prandtl(t, state.MassFractions()) + + mut / phys.Turbulence()->TurbPrandtlNumber()); + + // return viscous spectral radius + return maxTerm * viscTerm * fMag * fMag / vol; +} + +template +double ViscFaceSpectralRadius(const T &state, const unitVec3dMag &fArea, + const physics &phys, const double &dist, + const double &mu, const double &mut) { + // state -- primitive state variables + // fArea -- face area + // phys -- physics models + // dist -- distacne from cell center to cell center + // mu -- laminar viscosity + // mut -- turbulent viscosity + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + const auto t = state.Temperature(phys.EoS()); + const auto maxTerm = + max(4.0 / (3.0 * state.Rho()), + phys.Thermodynamic()->Gamma(t, state.MassFractions()) / state.Rho()); + // viscous term + const auto viscTerm = + phys.Transport()->NondimScaling() * + (mu / phys.Thermodynamic()->Prandtl(t, state.MassFractions()) + + mut / phys.Turbulence()->TurbPrandtlNumber()); + + // return viscous spectral radius + return fArea.Mag() / dist * maxTerm * viscTerm; +} + +template +double CellSpectralRadius(const T &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, + const physics &phys, const double &vol, + const double &mu, const double &mut, + const bool &isViscous) { + // state -- primitive state variables + // fAreaL -- face area of lower face in either i, j, or k direction + // fAreaR -- face area of upper face in either i, j, or k direction + // phys -- physics models + // vol -- cell volume + // mu -- laminar viscosity + // mut -- turbulent viscosity + // isViscous -- flag that is true if simulation is viscous + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + auto specRad = InvCellSpectralRadius(state, fAreaL, fAreaR, phys); + + if (isViscous) { + // factor 2 because viscous spectral radius is not halved (Blazek 6.53) + specRad += + 2.0 * ViscCellSpectralRadius(state, fAreaL, fAreaR, phys, vol, mu, mut); + } + return specRad; +} + +template +double FaceSpectralRadius(const T &state, const unitVec3dMag &fArea, + const physics &phys, const double &dist, + const double &mu, const double &mut, + const bool &isViscous) { + // state -- primitive state variables + // fAreaL -- face area + // phys -- physics models + // dist -- distance from cell center to cell center + // mu -- laminar viscosity + // mut -- turbulent viscosity + // isViscous -- flag that is true if simulation is viscous + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + auto specRad = InvFaceSpectralRadius(state, fArea, phys); + + if (isViscous) { + specRad += ViscFaceSpectralRadius(state, fArea, phys, dist, mu, mut); + } + return specRad; +} + +#endif diff --git a/include/tensor.hpp b/include/tensor.hpp index 5b10651..baf6839 100644 --- a/include/tensor.hpp +++ b/include/tensor.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,13 +26,14 @@ // any files that depend on the header. Leaving the implementation in // streamlines the compiling process. -#include // sqrt() +#include // sqrt() #include // ostream #include // is_arithmetic +#include // accumulate +#include +#include #include "vector3d.hpp" -#define TENSORSIZE 9 - using std::ostream; using std::endl; @@ -42,7 +43,7 @@ class tensor { static_assert(std::is_arithmetic::value, "tensor requires an arithmetic type!"); - T data_[TENSORSIZE]; + T data_[9]; // private member functions int GetLoc(const int &rr, const int &cc) const { @@ -69,6 +70,13 @@ class tensor { tensor& operator=(const tensor&) = default; // member functions + // provide begin and end so std::begin and std::end can be used + // use lower case to conform with std::begin, std::end + auto begin() noexcept {return std::begin(data_);} + const auto begin() const noexcept {return std::begin(data_);} + auto end() noexcept {return std::end(data_);} + const auto end() const noexcept {return std::end(data_);} + // operator overloads T& operator()(const int &rr, const int &cc) { return data_[this->GetLoc(rr, cc)]; @@ -105,11 +113,6 @@ class tensor { return lhs /= s; } - template - friend inline const tensor operator-(const TT &lhs, tensor rhs); - template - friend inline const tensor operator/(const TT &lhs, tensor rhs); - // assignment of data members void SetXX(const T &val) { data_[0] = val; } void SetXY(const T &val) { data_[1] = val; } @@ -132,6 +135,10 @@ class tensor { T ZY() const { return data_[7]; } T ZZ() const { return data_[8]; } + vector3d X() const { return {data_[0], data_[1], data_[2]}; } + vector3d Y() const { return {data_[3], data_[4], data_[5]}; } + vector3d Z() const { return {data_[6], data_[7], data_[8]}; } + // math functions T Trace() const { return data_[0] + data_[4] + data_[8]; } tensor Transpose() const; @@ -142,7 +149,12 @@ class tensor { void Identity(); void Zero(); int Size() const {return 3;} - + tensor RemoveComponent(const vector3d &) const; + vector3d LinearCombination(const vector3d &) const; + T Sum() const { + return std::accumulate(std::begin(data_), std::end(data_), T(0)); + } + // destructor ~tensor() noexcept {} }; @@ -150,36 +162,32 @@ class tensor { // operator overload for addition template tensor & tensor::operator+=(const tensor &ten) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - data_[rr] += ten.data_[rr]; - } + std::transform(this->begin(), this->end(), ten.begin(), this->begin(), + std::plus()); return *this; } // operator overload for subtraction with a scalar template tensor & tensor::operator-=(const tensor &ten) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - data_[rr] -= ten.data_[rr]; - } + std::transform(this->begin(), this->end(), ten.begin(), this->begin(), + std::minus()); return *this; } // operator overload for elementwise multiplication template tensor & tensor::operator*=(const tensor &ten) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - data_[rr] *= ten.data_[rr]; - } + std::transform(this->begin(), this->end(), ten.begin(), this->begin(), + std::multiplies()); return *this; } // operator overload for elementwise division template tensor & tensor::operator/=(const tensor &ten) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - data_[rr] /= ten.data_[rr]; - } + std::transform(this->begin(), this->end(), ten.begin(), this->begin(), + std::divides()); return *this; } @@ -207,36 +215,32 @@ inline const tensor operator/(tensor lhs, const tensor &rhs) { // operator overload for addition template tensor & tensor::operator+=(const T &scalar) { - for (auto &val : data_) { - val += scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val += scalar; }); return *this; } // operator overload for subtraction with a scalar template tensor & tensor::operator-=(const T &scalar) { - for (auto &val : data_) { - val -= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val -= scalar; }); return *this; } // operator overload for elementwise multiplication template tensor & tensor::operator*=(const T &scalar) { - for (auto &val : data_) { - val *= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val *= scalar; }); return *this; } // operator overload for elementwise division template tensor & tensor::operator/=(const T &scalar) { - for (auto &val : data_) { - val /= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val /= scalar; }); return *this; } @@ -247,9 +251,7 @@ inline const tensor operator+(const T &lhs, tensor rhs) { template inline const tensor operator-(const T &lhs, tensor rhs) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - rhs.data_[rr] = lhs - rhs.data_[rr]; - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs - val; }); return rhs; } @@ -260,9 +262,7 @@ inline const tensor operator*(const T &lhs, tensor rhs) { template inline const tensor operator/(const T &lhs, tensor rhs) { - for (auto rr = 0; rr < TENSORSIZE; rr++) { - rhs.data_[rr] = lhs / rhs.data_[rr]; - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs / val; }); return rhs; } @@ -344,27 +344,15 @@ void tensor::Identity() { // Function to zero a tensor template void tensor::Zero() { - T var = 0; - data_[0] = var; - data_[1] = var; - data_[2] = var; - data_[3] = var; - data_[4] = var; - data_[5] = var; - data_[6] = var; - data_[7] = var; - data_[8] = var; + std::fill(this->begin(), this->end(), T(0)); } // Function to return the double dot product of two tensors // Aij Bij template T tensor::DoubleDotTrans(const tensor &temp) const { - return data_[0] * temp.data_[0] + data_[1] * temp.data_[1] + - data_[2] * temp.data_[2] + data_[3] * temp.data_[3] + - data_[4] * temp.data_[4] + data_[5] * temp.data_[5] + - data_[6] * temp.data_[6] + data_[7] * temp.data_[7] + - data_[8] * temp.data_[8]; + auto prod = *this * temp; + return prod.Sum(); } // Function to return the double dot product of two tensors @@ -372,11 +360,32 @@ T tensor::DoubleDotTrans(const tensor &temp) const { template T tensor::DoubleDot(const tensor &temp) const { return data_[0] * temp.data_[0] + data_[1] * temp.data_[3] + - data_[2] * temp.data_[6] + data_[3] * temp.data_[1] + - data_[4] * temp.data_[4] + data_[5] * temp.data_[7] + - data_[6] * temp.data_[2] + data_[7] * temp.data_[5] + - data_[8] * temp.data_[8]; + data_[2] * temp.data_[6] + data_[3] * temp.data_[1] + + data_[4] * temp.data_[4] + data_[5] * temp.data_[7] + + data_[6] * temp.data_[2] + data_[7] * temp.data_[5] + + data_[8] * temp.data_[8]; } +// function to remove the components that are aligned with a given direction +template +tensor tensor::RemoveComponent(const vector3d &dir) const { + auto x = this->X(); + x -= x.DotProd(dir) * dir; + auto y = this->Y(); + y -= y.DotProd(dir) * dir; + auto z = this->Z(); + z -= z.DotProd(dir) * dir; + return {x, y, z}; +} + +// function to scale the rows of the tensor by a scale factor and sum them +// together +template +vector3d tensor::LinearCombination(const vector3d &vec) const { + auto comb = this->X() * vec.X(); + comb += this->Y() * vec.Y(); + comb += this->Z() * vec.Z(); + return comb; +} #endif diff --git a/include/thermodynamic.hpp b/include/thermodynamic.hpp index 943b991..5cc0ca9 100644 --- a/include/thermodynamic.hpp +++ b/include/thermodynamic.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,10 +20,15 @@ // This header file contains the thermodynamic model classes #include #include +#include using std::cout; using std::cerr; using std::endl; +using std::vector; + +// forward class declarations +class fluid; // abstract base class for thermodynamic model class thermodynamic { @@ -41,13 +46,30 @@ class thermodynamic { thermodynamic& operator=(const thermodynamic&) = default; // Member functions for abstract base class - virtual double Gamma(const double &t) const = 0; - virtual double Prandtl(const double &t) const = 0; - virtual double Cp(const double &t) const = 0; - virtual double Cv(const double &t) const = 0; - virtual double SpecEnergy(const double& t) const = 0; - virtual double SpecEnthalpy(const double& t) const = 0; - virtual double TemperatureFromSpecEnergy(const double& e) const = 0; + virtual int NumSpecies() const = 0; + double SpeciesGamma(const double& t, const int& ss) const { + return this->SpeciesCp(t, ss) / this->SpeciesCv(t, ss); + } + double Gamma(const double& t, const vector& mf) const { + return this->Cp(t, mf) / this->Cv(t, mf); + } + double Prandtl(const double& t, const vector& mf) const { + const auto gamma = this->Gamma(t, mf); + return (4.0 * gamma) / (9.0 * gamma - 5.0); + } + double Cp(const double& t, const vector& mf) const; + double Cv(const double& t, const vector& mf) const; + + virtual double SpeciesSpecEnergy(const double& t, const int& ss) const = 0; + virtual double SpecEnergy(const double& t, + const vector& mf) const = 0; + virtual double SpeciesSpecEnthalpy(const double& t, const int& ss) const = 0; + virtual double SpecEnthalpy(const double& t, + const vector& mf) const = 0; + virtual double TemperatureFromSpecEnergy(const double& e, + const vector& mf) const = 0; + virtual double SpeciesCp(const double& t, const int& ss) const = 0; + virtual double SpeciesCv(const double& t, const int& ss) const = 0; // Destructor virtual ~thermodynamic() noexcept {} @@ -56,34 +78,38 @@ class thermodynamic { // thermodynamic model for calorically perfect gas. // Cp and Cv are constants class caloricallyPerfect : public thermodynamic { - const double gamma_; + vector n_; + vector gasConst_; public: // Constructor - explicit caloricallyPerfect(const double &n) : gamma_(1.0 / n + 1.0) {} - caloricallyPerfect() : caloricallyPerfect(1.4) {} - - // move constructor and assignment operator - caloricallyPerfect(caloricallyPerfect&&) noexcept = default; - caloricallyPerfect& operator=(caloricallyPerfect&&) noexcept = default; - - // copy constructor and assignment operator - caloricallyPerfect(const caloricallyPerfect&) = default; - caloricallyPerfect& operator=(const caloricallyPerfect&) = default; + caloricallyPerfect(const vector&, const double&, const double&); // Member functions - double Gamma(const double &t) const override {return gamma_;} - double Prandtl(const double& t) const override { - return (4.0 * gamma_) / (9.0 * gamma_ - 5.0); + int NumSpecies() const override { return n_.size(); } + const double& N(const int &ss) const { return n_[ss]; } + const double& R(const int &ss) const { return gasConst_[ss]; } + double SpeciesSpecEnergy(const double& t, const int& ss) const override { + return this->SpeciesCv(t, ss) * t; } - double Cp(const double& t) const override { return 1.0 / (gamma_ - 1.0); } - double Cv(const double& t) const override { - return 1.0 / (gamma_ * (gamma_ - 1.0)); + double SpecEnergy(const double& t, const vector& mf) const override { + return this->Cv(t, mf) * t; + } + double SpeciesSpecEnthalpy(const double& t, const int& ss) const override { + return this->SpeciesCp(t, ss) * t; + } + double SpecEnthalpy(const double& t, + const vector& mf) const override { + return this->Cp(t, mf) * t; + } + double TemperatureFromSpecEnergy(const double& e, + const vector& mf) const override; + double SpeciesCp(const double& t, const int& ss) const override { + return this->R(ss) * ((this->N(ss) + 1.0)); + } + double SpeciesCv(const double& t, const int& ss) const override { + return this->R(ss) * this->N(ss); } - - double SpecEnergy(const double& t) const override {return this->Cv(t) * t;} - double SpecEnthalpy(const double& t) const override {return this->Cp(t) * t;} - double TemperatureFromSpecEnergy(const double& e) const override; // Destructor ~caloricallyPerfect() noexcept {} @@ -91,52 +117,49 @@ class caloricallyPerfect : public thermodynamic { // thermodynamic model for thermally perfect gas // Cp and Cv are functions of T -class thermallyPerfect : public thermodynamic { - const double n_; - const double vibTemp_; - const double nonDimR_; +class thermallyPerfect : public caloricallyPerfect { + vector> vibTemp_; // private member functions - double ThetaV(const double& t) const { return vibTemp_ / (2.0 * t); } + double ThetaV(const double& t, const int &ss, const int& ii) const { + return vibTemp_[ss][ii] / (2.0 * t); + } - public: - // Constructor - thermallyPerfect(const double& n, const double& vt) - : n_(n), vibTemp_(vt), nonDimR_(n / (n + 1.0)) {} - thermallyPerfect() : thermallyPerfect(1.4, 3056.0) {} + double VibEqCpCvTerm(const double &t, const int &ss) const { + auto vibEq = 0.0; + for (auto ii = 0U; ii < vibTemp_[ss].size(); ++ii) { + const auto tv = this->ThetaV(t, ss, ii); + vibEq += pow(tv / sinh(tv), 2.0); + } + return vibEq; + } - // move constructor and assignment operator - thermallyPerfect(thermallyPerfect&&) noexcept = default; - thermallyPerfect& operator=(thermallyPerfect&&) noexcept = default; + double VibEqTerm(const double &t, const int &ss) const { + auto vibEq = 0.0; + for (auto &vt : vibTemp_[ss]) { + vibEq += vt / (exp(vt / t) - 1.0); + } + return vibEq; + } - // copy constructor and assignment operator - thermallyPerfect(const thermallyPerfect&) = default; - thermallyPerfect& operator=(const thermallyPerfect&) = default; + public: + // Constructor + thermallyPerfect(const vector& fl, const double& tRef, + const double& aRef); // Member functions - double Gamma(const double& t) const override { - return this->Cp(t) / this->Cv(t); - } - double Prandtl(const double& t) const override { - return (4.0 * this->Gamma(t)) / (9.0 * this->Gamma(t) - 5.0); + double SpeciesSpecEnergy(const double& t, const int& ss) const override; + double SpecEnergy(const double& t, const vector& mf) const override; + double SpeciesSpecEnthalpy(const double& t, const int& ss) const override; + double SpecEnthalpy(const double& t, const vector& mf) const override; + double TemperatureFromSpecEnergy(const double& e, + const vector& mf) const override; + double SpeciesCp(const double& t, const int& ss) const override { + return this->R(ss) * ((this->N(ss) + 1.0) + this->VibEqCpCvTerm(t, ss)); } - double Cp(const double& t) const override { - const auto tv = this->ThetaV(t); - return nonDimR_ * ((n_ + 1.0) + pow(tv / sinh(tv), 2.0)); + double SpeciesCv(const double& t, const int& ss) const override { + return this->R(ss) * (this->N(ss) + this->VibEqCpCvTerm(t, ss)); } - double Cv(const double& t) const override { - const auto tv = this->ThetaV(t); - return nonDimR_ * (n_ + pow(tv / sinh(tv), 2.0)); - } - - double SpecEnergy(const double& t) const override { - return nonDimR_ * (n_ * t + vibTemp_ / (exp(vibTemp_ / t) - 1.0)); - } - double SpecEnthalpy(const double& t) const override { - return nonDimR_ * ((n_ + 1) * t + vibTemp_ / (exp(vibTemp_ / t) - 1.0)); - } - - double TemperatureFromSpecEnergy(const double& e) const override; // Destructor ~thermallyPerfect() noexcept {} diff --git a/include/transport.hpp b/include/transport.hpp index 00e344a..4e3d878 100644 --- a/include/transport.hpp +++ b/include/transport.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,20 +21,35 @@ #include // sqrt #include +#include #include "vector3d.hpp" #include "thermodynamic.hpp" +using std::vector; using std::unique_ptr; +// forward class declarations +class fluid; + // abstract base class for transport models class transport { - const double scaling_; - const double invScaling_; + double scaling_; + double invScaling_; + + protected: + void SetScaling(const double &rho, const double &l, const double &mu, + const double &a) { + scaling_ = mu / (rho * a * l); + invScaling_ = 1.0 / scaling_; + } public: // Constructor - transport(const double &rho, const double &l, const double &mu, const double &a) - : scaling_(mu / (rho * a * l)), invScaling_(rho * a * l / mu) {} + transport() : scaling_(0), invScaling_(0) {} + transport(const double &rho, const double &l, const double &mu, + const double &a) { + this->SetScaling(rho, l, mu, a); + } // move constructor and assignment operator transport(transport&&) noexcept = default; @@ -45,20 +60,25 @@ class transport { transport& operator=(const transport&) = default; // Member functions for abstract base class - virtual double Viscosity(const double&) const = 0; - virtual double EffectiveViscosity(const double&) const = 0; - virtual double Lambda(const double&) const = 0; - virtual double ConstC1() const = 0; - virtual double ConstS() const = 0; + virtual int NumSpecies() const = 0; + virtual double SpeciesViscosity(const double &, const int &) const = 0; + virtual double SpeciesConductivity(const double &, const int &) const = 0; + virtual double Viscosity(const double &, const vector &) const = 0; + virtual double EffectiveViscosity(const double &, + const vector &) const = 0; + virtual double Lambda(const double &) const = 0; virtual double TRef() const = 0; virtual double MuRef() const = 0; - virtual double Conductivity(const double &, const double &, - const unique_ptr &) const = 0; - virtual double TurbConductivity(const double &, const double &, const double &, - const unique_ptr &) const = 0; - - double NondimScaling() const {return scaling_;} + virtual double Conductivity(const double &, const vector &) const = 0; + virtual double EffectiveConductivity(const double &, + const vector &) const = 0; + virtual double TurbConductivity(const double &, const double &, + const double &, + const unique_ptr &, + const vector &mf) const = 0; + double NondimScaling() const { return scaling_; } double InvNondimScaling() const {return invScaling_;} + virtual vector MoleFractions(const vector &) const = 0; // Destructor virtual ~transport() noexcept {} @@ -67,26 +87,26 @@ class transport { // this class models viscous transport using Sutherland's law class sutherland : public transport { - const double cOne_; - const double S_; - const double tRef_; - const double muRef_; - const double bulkVisc_; + vector viscC1_; + vector viscS_; + vector condC1_; + vector condS_; + vector molarMass_; + double tRef_; + double muMixRef_; + double kNonDim_; + double bulkVisc_ = 0.0; + + // private member functions + double WilkesVisc(const vector &, const vector &) const; + double WilkesCond(const vector &, const vector &) const; public: // Constructors // Stoke's hypothesis -- bulk viscosity = 0 // Sutherland's Law -- mu = muref * (C1 * Tref^1.5) / (T + S_) - sutherland(const double &c, const double &s, const double &t, const double &r, - const double &l, const double &a) - : transport(r, l, c * pow(t, 1.5) / (t + s), a), - cOne_(c), - S_(s), - tRef_(t), - muRef_(cOne_ * pow(tRef_, 1.5) / (tRef_ + S_)), - bulkVisc_(0.0) {} - sutherland(const double &t, const double &r, const double &l, const double &a) - : sutherland(1.458e-6, 110.4, t, r, l, a) {} + sutherland(const vector &, const double &, const double &, + const double &, const double &, const vector &); // move constructor and assignment operator sutherland(sutherland&&) noexcept = default; @@ -97,25 +117,34 @@ class sutherland : public transport { sutherland& operator=(const sutherland&) = default; // Member functions - double Viscosity(const double&) const override; - double EffectiveViscosity(const double&) const override; - double Lambda(const double&) const override; - double ConstC1() const override {return cOne_;} - double ConstS() const override {return S_;} + int NumSpecies() const override { return molarMass_.size(); } + double SpeciesViscosity(const double &, const int &) const override; + double SpeciesConductivity(const double &, const int &) const override; + double Viscosity(const double &, const vector &) const override; + double EffectiveViscosity(const double &, + const vector &) const override; + double Lambda(const double &) const override; double TRef() const override {return tRef_;} - double MuRef() const override {return muRef_;} - double Conductivity(const double &mu, const double &t, - const unique_ptr &thermo) const override { - return mu * thermo->Cp(t) / thermo->Prandtl(t); - } - double TurbConductivity( - const double &eddyVisc, const double &prt, const double &t, - const unique_ptr &thermo) const override { - return eddyVisc * thermo->Cp(t) / prt; + double MuRef() const override {return muMixRef_;} + double Conductivity(const double &, const vector &) const override; + double EffectiveConductivity(const double &, + const vector &) const override; + double TurbConductivity(const double &eddyVisc, const double &prt, + const double &t, + const unique_ptr &thermo, + const vector &mf) const override { + return eddyVisc * thermo->Cp(t, mf) / prt; } + vector MoleFractions(const vector &) const override; // Destructor ~sutherland() noexcept {} }; + +// -------------------------------------------------------------------------- +// function declarations + + + #endif diff --git a/include/turbulence.hpp b/include/turbulence.hpp index 4ae2503..01036a6 100644 --- a/include/turbulence.hpp +++ b/include/turbulence.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,14 +27,17 @@ #include #include "vector3d.hpp" // vector3d #include "tensor.hpp" // tensor +#include "matrix.hpp" // squareMatrix using std::string; using std::unique_ptr; // forward class declaration -class primVars; +class primitive; class transport; -class squareMatrix; +template +class arrayView; +using primitiveView = arrayView; class turbModel { const string eddyViscMethod_; @@ -55,105 +58,207 @@ class turbModel { // member functions string EddyViscMethod() const {return eddyViscMethod_;} tensor MeanStrainRate(const tensor &) const; - virtual double EddyViscNoLim(const primVars &state) const; + template + double EddyViscNoLim(const T &state) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->EddyViscosityNoLim(view); + } + virtual double EddyViscosityNoLim(const primitiveView &state) const; virtual double TurbPrandtlNumber() const {return 0.9;} + virtual double TurbSchmidtNumber() const {return 0.7;} virtual double TkeMin() const {return 1.0e-20;} virtual double OmegaMin() const {return 1.0e-20;} + virtual double TurbMinN(const int &ii) const { + MSG_ASSERT(ii == 0 || ii ==1, "turbulence index out of range"); + return ii == 0 ? this->TkeMin() : this->OmegaMin(); + } virtual double SigmaK(const double &f1) const {return 0.0;} virtual double SigmaW(const double &f1) const {return 0.0;} virtual double WallSigmaK() const {return 0.0;} virtual double WallSigmaW() const {return 0.0;} virtual bool UseUnlimitedEddyVisc() const {return false;} virtual bool UsePhi() const {return false;} - virtual double EddyVisc(const primVars &state, + virtual double EddyVisc(const primitive &state, const tensor &vGrad, const unique_ptr &trans, const double &f2, const double &length) const {return 0.0;} virtual double WallBeta() const {return 1.0;} virtual double BetaStar() const {return 0.0;} - virtual double SrcSpecRad(const primVars &state, + virtual double SrcSpecRad(const primitiveView &state, const unique_ptr &trans, const double &vol, const double &phi = 1.0) const {return 0.0;} - virtual squareMatrix InviscidJacobian(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const; - virtual squareMatrix InviscidConvJacobian( - const primVars &state, const unitVec3dMag &fArea) const; - virtual squareMatrix InviscidDissJacobian( - const primVars &state, const unitVec3dMag &fArea) const; - virtual double InviscidCellSpecRad(const primVars &state, - const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR) const; - virtual double InviscidFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const; - virtual squareMatrix ViscousJacobian(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, const double &mut, - const double &f1) const; - virtual double ViscCellSpecRad(const primVars &state, - const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR, - const double &mu, - const unique_ptr &trans, - const double &vol, const double &mut, - const double &f1) const { + + template + squareMatrix InviscidJacobian(const T &state, + const unitVec3dMag &fArea, + const bool &positive) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->InvJac(view, fArea, positive); + } + virtual squareMatrix InvJac(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const; + template + squareMatrix InviscidConvJacobian(const T &state, + const unitVec3dMag &fArea) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->InviscidConvectiveJacobian(view, fArea); + } + virtual squareMatrix InviscidConvectiveJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const; + + template + squareMatrix InviscidDissJacobian(const T &state, + const unitVec3dMag &fArea) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->InviscidDissipationJacobian(view, fArea); + } + virtual squareMatrix InviscidDissipationJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const; + + template + double InviscidCellSpecRad(const T &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->InviscidCellSpectralRadius(view, fAreaL, fAreaR); + } + virtual double InviscidCellSpectralRadius( + const primitiveView &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR) const; + + template + double InviscidFaceSpecRad(const T &state, const unitVec3dMag &fArea, + const bool &positive) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->InviscidFaceSpectralRadius(view, fArea); + } + virtual double InviscidFaceSpectralRadius(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const; + + template + squareMatrix ViscousJacobian(const T &state, + const unitVec3dMag &fArea, + const double &mu, + const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->ViscJac(view, fArea, mu, trans, dist, mut, f1); + } + virtual squareMatrix ViscJac(const primitiveView &state, + const unitVec3dMag &fArea, + const double &mu, + const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const; + + template + double ViscCellSpecRad(const T &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, const double &mu, + const unique_ptr &trans, const double &vol, + const double &mut, const double &f1) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->ViscousCellSpectralRadius(view, fAreaL, fAreaR, mu, trans, vol, + mut, f1); + } + virtual double ViscousCellSpectralRadius(const primitiveView &state, + const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, + const double &mu, + const unique_ptr &trans, + const double &vol, const double &mut, + const double &f1) const { return 0.0; } - virtual double ViscFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, const double &mut, - const double &f1) const { + + template + double ViscFaceSpecRad(const T &state, const unitVec3dMag &fArea, + const double &mu, const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + auto view = state.GetView(); + return this->ViscousFaceSpectralRadius(view, fArea, mu, trans, dist, mut, + f1); + } + virtual double ViscousFaceSpectralRadius( + const primitiveView &state, const unitVec3dMag &fArea, + const double &mu, const unique_ptr &trans, const double &dist, + const double &mut, const double &f1) const { return 0.0; } - tensor BoussinesqReynoldsStress(const primVars &state, + + tensor BoussinesqReynoldsStress(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans, const double &mut) const; - double ReynoldsStressDDotVelGrad(const primVars &state, + double ReynoldsStressDDotVelGrad(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans, const double &mut) const; - double TkeDestruction(const primVars &state, const double &phi = 1.0) const; - double OmegaDestruction(const primVars &state) const; - double CrossDiffusion(const primVars &state, + double TkeDestruction(const primitiveView &state, + const double &phi = 1.0) const; + double OmegaDestruction(const primitiveView &state) const; + double CrossDiffusion(const primitiveView &state, const vector3d &kGrad, const vector3d &wGrad) const; - double CellSpectralRadius(const primVars &state, - const unitVec3dMag &fAreaL, + template + double CellSpectralRadius(const T &state, const unitVec3dMag &fAreaL, const unitVec3dMag &fAreaR, const double &mu, const unique_ptr &trans, const double &vol, const double &mut, const double &f1, const bool &addSrc) const; - double FaceSpectralRadius(const primVars &state, - const unitVec3dMag &fArea, const double &mu, + template + double FaceSpectralRadius(const T &state, const unitVec3dMag &fArea, + const double &mu, const unique_ptr &trans, const double &dist, const double &mut, const double &f1, const bool &positive) const; - virtual squareMatrix CalcTurbSrc(const primVars &state, - const tensor &velGrad, - const vector3d &kGrad, - const vector3d &wGrad, - const unique_ptr &trans, - const double &vol, - const double &mut, const double &f1, - const double &f2, const double &width, - double &ksrc, double &wsrc) const; - virtual squareMatrix TurbSrcJac(const primVars &state, + + virtual squareMatrix CalcTurbSrc( + const primitiveView &state, const tensor &velGrad, + const vector3d &kGrad, const vector3d &wGrad, + const unique_ptr &trans, const double &vol, const double &mut, + const double &f1, const double &f2, const double &width, + vector &turbSrc) const; + virtual squareMatrix TurbSrcJac(const primitiveView &state, const double &beta, const unique_ptr &trans, const double &vol, const double &phi = 1.0) const; // abstract functions (need one for abstract base class) - virtual void EddyViscAndBlending(const primVars &state, + virtual void EddyViscAndBlending(const primitive &state, const tensor &vGrad, const vector3d &kGrad, const vector3d &wGrad, @@ -167,6 +272,64 @@ class turbModel { virtual ~turbModel() noexcept {} }; + +// member function to calculate the spectral radius of the turbulence equations +template +double turbModel::CellSpectralRadius( + const T &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, const double &mu, + const unique_ptr &trans, const double &vol, const double &mut, + const double &f1, const bool &addSrc) const { + // state -- primitive variables + // fAreaL -- area at left face + // fAreaR -- area at right face + // mu -- laminar viscosity + // trans -- viscous transport model + // vol -- cell volume + // mut -- turbulent viscosity + // f1 -- first blending coefficient + // addSrc -- flag to determine if source jacobian spectral radius should be + // included + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + auto specRad = this->InviscidCellSpectralRadius(state, fAreaL, fAreaR); + // factor of 2 because viscous spectral radius is not halved (Blazek 6.53) + specRad += 2.0 * this->ViscousCellSpectralRadius(state, fAreaL, fAreaR, mu, + trans, vol, mut, f1); + if (addSrc) { + // minus sign because source terms are on RHS + specRad -= this->SrcSpecRad(state, trans, vol); + } + return specRad; +} + +template +double turbModel::FaceSpectralRadius( + const T &state, const unitVec3dMag &fArea, const double &mu, + const unique_ptr &trans, const double &dist, const double &mut, + const double &f1, const bool &positive) const { + // state -- primitive variables + // fArea -- face area + // mu -- laminar viscosity + // trans -- viscous transport model + // dist -- distance from cell center to cell center + // mut -- turbulent viscosity + // f1 -- first blending coefficient + // positive -- flag to add or subtract inviscid dissipation + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + + auto specRad = this->InviscidFaceSpectralRadius(state, fArea, positive); + specRad += + this->ViscousFaceSpectralRadius(state, fArea, mu, trans, dist, mut, f1); + return specRad; +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- class turbNone : public turbModel { public: // constructor @@ -182,32 +345,36 @@ class turbNone : public turbModel { turbNone& operator=(const turbNone&) = default; // member functions - void EddyViscAndBlending(const primVars &state, const tensor &vGrad, + void EddyViscAndBlending(const primitive &state, const tensor &vGrad, const vector3d &kGrad, const vector3d &wGrad, const double &mu, const double &wallDist, const unique_ptr &trans, const double &length, double &mut, double &f1, double &f2) const override {} - double EddyViscNoLim(const primVars &state) const override { return 0.0; } - double InviscidCellSpecRad( - const primVars &state, const unitVec3dMag &fAreaL, + double EddyViscosityNoLim(const primitiveView &state) const override { + return 0.0; + } + double InviscidCellSpectralRadius( + const primitiveView &state, const unitVec3dMag &fAreaL, const unitVec3dMag &fAreaR) const override { return 0.0; } - double InviscidFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const bool &postive) const override { + double InviscidFaceSpectralRadius(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &postive) const override { return 0.0; } - squareMatrix InviscidJacobian(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const override; - squareMatrix InviscidConvJacobian( - const primVars &state, const unitVec3dMag &fArea) const override; - squareMatrix InviscidDissJacobian( - const primVars &state, const unitVec3dMag &fArea) const override; + squareMatrix InvJac(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const override; + squareMatrix InviscidConvectiveJacobian( + const primitiveView &state, + const unitVec3dMag &fArea) const override; + squareMatrix InviscidDissipationJacobian( + const primitiveView &state, + const unitVec3dMag &fArea) const override; double TkeMin() const override {return 0.0;} double OmegaMin() const override {return 0.0;} @@ -218,6 +385,8 @@ class turbNone : public turbModel { ~turbNone() noexcept {} }; +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- class turbKWWilcox : public turbModel { const double gamma_ = 0.52; const double betaStar_ = 0.09; @@ -230,14 +399,14 @@ class turbKWWilcox : public turbModel { // private member functions double SigmaD(const vector3d&, const vector3d&) const; - double Xw(const primVars &, const tensor &, + double Xw(const primitiveView &, const tensor &, const unique_ptr &) const; - double FBeta(const primVars &, const tensor &, + double FBeta(const primitiveView &, const tensor &, const unique_ptr &) const; - double Beta(const primVars &, const tensor &, + double Beta(const primitiveView &, const tensor &, const unique_ptr &) const; tensor StrainKI(const tensor &) const; - double OmegaTilda(const primVars&, const tensor&, + double OmegaTilda(const primitive &, const tensor&, const unique_ptr&) const; public: @@ -254,47 +423,46 @@ class turbKWWilcox : public turbModel { turbKWWilcox& operator=(const turbKWWilcox&) = default; // member functions - squareMatrix CalcTurbSrc(const primVars &, const tensor &, + squareMatrix CalcTurbSrc(const primitiveView &, const tensor &, const vector3d &, const vector3d &, const unique_ptr &, const double &, const double &, const double &, const double &, - const double &, double &, double &) const override; - double EddyVisc(const primVars&, const tensor &, + const double &, vector &) const override; + double EddyVisc(const primitive&, const tensor &, const unique_ptr &, const double &, const double &) const override; - void EddyViscAndBlending(const primVars &, const tensor &, + void EddyViscAndBlending(const primitive &, const tensor &, const vector3d &, const vector3d &, const double &, const double &, const unique_ptr &, const double &, double &, double &, double &) const override; bool UseUnlimitedEddyVisc() const override { return true; } - double SrcSpecRad(const primVars &, const unique_ptr &, + double SrcSpecRad(const primitiveView &, const unique_ptr &, const double &, const double & = 1.0) const override; - squareMatrix ViscousJacobian(const primVars &, - const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - double ViscCellSpecRad(const primVars &, - const unitVec3dMag &, - const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - double ViscFaceSpecRad(const primVars &, - const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - - squareMatrix TurbSrcJac(const primVars &, const double &, + squareMatrix ViscJac(const primitiveView &, const unitVec3dMag &, + const double &, const unique_ptr &, + const double &, const double &, + const double &) const override; + double ViscousCellSpectralRadius(const primitiveView &, + const unitVec3dMag &, + const unitVec3dMag &, const double &, + const unique_ptr &, + const double &, const double &, + const double &) const override; + double ViscousFaceSpectralRadius(const primitiveView &, + const unitVec3dMag &, const double &, + const unique_ptr &, + const double &, const double &, + const double &) const override; + + squareMatrix TurbSrcJac(const primitiveView &, const double &, const unique_ptr &, const double &, const double & = 1.0) const override; double TurbPrandtlNumber() const override {return prt_;} double WallBeta() const override {return beta0_;} - double TurbLengthScale(const primVars &state, + double TurbLengthScale(const primitiveView &state, const unique_ptr &) const; double Gamma() const {return gamma_;} @@ -316,6 +484,8 @@ class turbKWWilcox : public turbModel { ~turbKWWilcox() noexcept {} }; +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- class turbKWSst : public turbModel { const double betaStar_ = 0.09; const double sigmaK1_ = 0.85; @@ -333,11 +503,11 @@ class turbKWSst : public turbModel { // private member functions double F1(const double &, const double &, const double &) const; double F2(const double &, const double &) const; - double Alpha1(const primVars &, const unique_ptr &, - const double &) const; - double Alpha2(const primVars &, const unique_ptr &, const double &, + double Alpha1(const primitive &, const unique_ptr &, const double &) const; - double Alpha3(const primVars &, const double &, const double &) const; + double Alpha2(const primitive &, const unique_ptr &, + const double &, const double &) const; + double Alpha3(const primitive &, const double &, const double &) const; public: // constructor @@ -354,42 +524,52 @@ class turbKWSst : public turbModel { // member functions double BlendedCoeff(const double &, const double &, const double &) const; - double CDkw(const primVars &, const vector3d &, - const vector3d &) const; + + template + double CDkw(const T &state, const vector3d &kGrad, + const vector3d &wGrad) const { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + return std::max( + 2.0 * state.Rho() * sigmaW2_ / state.Omega() * kGrad.DotProd(wGrad), + 1.0e-10); + } + virtual squareMatrix CalcTurbSrc( - const primVars &, const tensor &, const vector3d &, + const primitiveView &, const tensor &, const vector3d &, const vector3d &, const unique_ptr &, const double &, - const double &, const double &, const double &, const double &, double &, - double &) const override; - double EddyVisc(const primVars &, const tensor &, + const double &, const double &, const double &, const double &, + vector &) const override; + double EddyVisc(const primitive &, const tensor &, const unique_ptr &, const double &, const double &) const override; - void EddyViscAndBlending(const primVars &, const tensor &, + void EddyViscAndBlending(const primitive &, const tensor &, const vector3d &, const vector3d &, const double &, const double &, const unique_ptr &, const double &, double &, double &, double &) const override; - virtual double SrcSpecRad(const primVars &, const unique_ptr &, - const double &, + virtual double SrcSpecRad(const primitiveView &, + const unique_ptr &, const double &, const double & = 1.0) const override; - squareMatrix ViscousJacobian(const primVars &, const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - double ViscCellSpecRad(const primVars &, - const unitVec3dMag &, - const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - double ViscFaceSpecRad(const primVars &, - const unitVec3dMag &, - const double &, const unique_ptr &, - const double &, const double &, - const double &) const override; - - virtual squareMatrix TurbSrcJac(const primVars &, const double &, + squareMatrix ViscJac(const primitiveView &, const unitVec3dMag &, + const double &, const unique_ptr &, + const double &, const double &, + const double &) const override; + double ViscousCellSpectralRadius(const primitiveView &, + const unitVec3dMag &, + const unitVec3dMag &, const double &, + const unique_ptr &, + const double &, const double &, + const double &) const override; + double ViscousFaceSpectralRadius(const primitiveView &, + const unitVec3dMag &, const double &, + const unique_ptr &, + const double &, const double &, + const double &) const override; + + virtual squareMatrix TurbSrcJac(const primitiveView &, const double &, const unique_ptr &, const double &, const double & = 1.0) const override; @@ -410,7 +590,7 @@ class turbKWSst : public turbModel { double A1() const {return a1_;} double BetaStar() const override {return betaStar_;} double TkeProd2DestRatio() const {return kProd2Dest_;} - double TurbLengthScale(const primVars &state, + double TurbLengthScale(const primitiveView &state, const unique_ptr &) const; // use coefficients from 1 because they are smaller @@ -431,14 +611,16 @@ class turbKWSst : public turbModel { virtual ~turbKWSst() noexcept {} }; - +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- class turbSstDes : public turbKWSst { const double cdes1_ = 0.78; const double cdes2_ = 0.61; // private member functions - double Phi(const primVars &state, const double &cdes, const double &width, - const double &f2, const unique_ptr &trans) const; + double Phi(const primitiveView &state, const double &cdes, + const double &width, const double &f2, + const unique_ptr &trans) const; public: // constructor @@ -454,13 +636,13 @@ class turbSstDes : public turbKWSst { turbSstDes& operator=(const turbSstDes&) = default; - squareMatrix CalcTurbSrc(const primVars &, const tensor &, + squareMatrix CalcTurbSrc(const primitiveView &, const tensor &, const vector3d &, const vector3d &, const unique_ptr &, const double &, const double &, const double &, const double &, - const double &, double &, double &) const override; + const double &, vector &) const override; - double SrcSpecRad(const primVars &, const unique_ptr &, + double SrcSpecRad(const primitiveView &, const unique_ptr &, const double &, const double &) const override; double CDes1() const {return cdes1_;} @@ -476,7 +658,8 @@ class turbSstDes : public turbKWSst { ~turbSstDes() noexcept {} }; - +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- class turbWale : public turbModel { const double cw_ = 0.544; @@ -495,11 +678,11 @@ class turbWale : public turbModel { turbWale(const turbWale &model) : turbModel(model) {} turbWale& operator=(const turbWale&) = default; - double EddyVisc(const primVars &state, const tensor &vGrad, + double EddyVisc(const primitive &state, const tensor &vGrad, const unique_ptr &trans, const double &f2, const double &length) const override; - void EddyViscAndBlending(const primVars &state, const tensor &vGrad, + void EddyViscAndBlending(const primitive &state, const tensor &vGrad, const vector3d &kGrad, const vector3d &wGrad, const double &mu, const double &wallDist, @@ -520,9 +703,9 @@ class turbWale : public turbModel { }; - +// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- // function declarations - #endif diff --git a/include/uncoupledScalar.hpp b/include/uncoupledScalar.hpp index 80c2052..9dd7eee 100644 --- a/include/uncoupledScalar.hpp +++ b/include/uncoupledScalar.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ #include // cout #include // max +#include +#include "arrayView.hpp" using std::cout; using std::endl; @@ -27,7 +29,7 @@ using std::cerr; using std::ostream; // forward class declarations -class genArray; +class varArray; // This class holds variables that may be different for each set of // equations being solved. For example the spectral radii of the flow @@ -68,9 +70,28 @@ class uncoupledScalar { turbVar_ = 0.0; } - genArray ArrayMult(genArray) const; + template ::value>> + T ArrayMult(T arr) const { + for (auto ii = 0; ii < arr.TurbulenceIndex(); ++ii) { + arr[ii] *= flowVar_; + } + for (auto ii = arr.TurbulenceIndex(); ii < arr.Size(); ++ii) { + arr[ii] *= turbVar_; + } + return arr; + } + template ::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>> + auto ArrayMult(const T &arrView) const { + auto arr = arrView.CopyData(); + return this->ArrayMult(arr); + } - inline uncoupledScalar & operator+=(const uncoupledScalar &); + inline uncoupledScalar &operator+=(const uncoupledScalar &); inline uncoupledScalar & operator-=(const uncoupledScalar &); inline uncoupledScalar & operator*=(const uncoupledScalar &); inline uncoupledScalar & operator/=(const uncoupledScalar &); diff --git a/include/utility.hpp b/include/utility.hpp index 994e095..437d267 100644 --- a/include/utility.hpp +++ b/include/utility.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include "mpi.h" // parallelism #include "vector3d.hpp" // vector3d #include "multiArray3d.hpp" // multiArray3d +#include "blkMultiArray3d.hpp" // blkMultiArray3dd #include "tensor.hpp" // tensor #include "macros.hpp" @@ -32,24 +33,17 @@ using std::unique_ptr; // forward class declarations class procBlock; -class eos; +class physics; class transport; -class thermodynamic; class input; -class genArray; -class turbModel; -class fluxJacobian; +class residual; +class matMultiArray3d; class kdtree; class resid; -class primVars; +class primitive; +class varArray; // function definitions -template -inline T FaceReconCentral(const T &, const T &, const vector &); -template -inline T FaceReconCentral4th(const T &, const T &, const T &, const T&, - const vector &); - tensor VectorGradGG(const vector3d &, const vector3d &, const vector3d &, const vector3d &, const vector3d &, const vector3d &, @@ -68,35 +62,24 @@ vector3d ScalarGradGG( void SwapGeomSlice(connection &, procBlock &, procBlock &); void GetBoundaryConditions(vector &, const input &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, vector &, - const int &, const MPI_Datatype &); + const physics &phys, vector &, + const int &); vector> GetViscousFaceCenters(const vector &); void CalcWallDistance(vector &, const kdtree &); -void AssignSolToTimeN(vector &, const unique_ptr &, - const unique_ptr &); +void AssignSolToTimeN(vector &, const physics &phys); void AssignSolToTimeNm1(vector &); -void ExplicitUpdate(vector &, const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const int &, genArray &, - resid &); -double ImplicitUpdate(vector &, vector> &, - const input &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const int &, genArray &, - resid &, const vector &, const int &, - const MPI_Datatype &); - -void SwapImplicitUpdate(vector> &, - const vector &, const int &, - const MPI_Datatype &, const int &); +void ExplicitUpdate(vector &, const input &, const physics &phys, + const int &, residual &, resid &); +double ImplicitUpdate(vector &, vector &, + const input &, const physics &phys, const int &, + residual &, resid &, const vector &, + const int &); + +void SwapImplicitUpdate(vector> &, + const vector &, const int &, const int &); void SwapTurbVars(vector &, const vector &, const int &, const int &); void SwapWallDist(vector &, const vector &, const int &, @@ -105,24 +88,18 @@ void SwapEddyViscAndGradients(vector &, const vector &, const int &, const MPI_Datatype &, const MPI_Datatype &, const int &); -void CalcResidual(vector &, vector> &, - const unique_ptr &, - const unique_ptr &, const unique_ptr &, - const input &, const unique_ptr &, +void CalcResidual(vector &, vector &, + const physics &phys, const input &, const vector &, const int &, const MPI_Datatype &, const MPI_Datatype &); void CalcTimeStep(vector &, const input &); -// void GetSolMMinusN(vector> &, const vector &, -// const vector> &, -// const unique_ptr &, const input &, const int &); - // function to reorder block by hyperplanes vector> HyperplaneReorder(const int &, const int &, const int &); void ResizeArrays(const vector &, const input &, - vector> &); + vector &); vector3d TauNormal(const tensor &, const vector3d &, const double &, const double &, @@ -137,66 +114,37 @@ template double StencilWidth(const T &, const int &, const int &); template -T Derivative2nd(const double &, const double &, const double &, +auto Derivative2nd(const double &, const double &, const double &, const T &, const T &, const T &); -primVars Beta0(const double &, const double &, const double &, - const primVars &, const primVars &, const primVars &); -primVars Beta1(const double &, const double &, const double &, - const primVars &, const primVars &, const primVars &); -primVars Beta2(const double &, const double &, const double &, - const primVars &, const primVars &, const primVars &); -primVars BetaIntegral(const primVars &, const primVars &, const double &, - const double &); -primVars BetaIntegral(const primVars &, const primVars &, const double &, - const double &, const double &); - -tensor CalcVelGradTSL(const primVars&, const primVars&, +tensor CalcVelGradTSL(const primitive&, const primitive&, const vector3d&, const double&); kdtree CalcTreeFromCloud(const string &, const input &, - const unique_ptr &, vector &); - -// --------------------------------------------------------------------------- -// inline function definitions - -// function to reconstruct cell variables to the face using central -// differences -template -T FaceReconCentral(const T &varU, const T &varD, - const vector &cellWidth) { - // varU -- variable at the cell center of the upwind cell - // varD -- variable at the cell center of the downwind cell - // cellWidth -- width of cells in stencil + const unique_ptr &, vector &, + vector &); - // get coefficients - const auto coeffs = LagrangeCoeff(cellWidth, 1, 0, 0); +string GetEnvironmentVariable(const string &); - // reconstruct with central difference - return coeffs[0] * varD + coeffs[1] * varU; -} +double Kronecker(const int &, const int &); -// function to reconstruct cell variables to the face using central -// differences (4th order) +// --------------------------------------------------------------------------- +// inline function definitions template -T FaceReconCentral4th(const T &varU2, const T &varU1, const T &varD1, - const T &varD2, const vector &cellWidth) { - // varU2 -- variable at the cell center of the second upwind cell - // varU1 -- variable at the cell center of the first upwind cell - // varD1 -- variable at the cell center of the first downwind cell - // varD2 -- variable at the cell center of the second downwind cell - // cellWidth -- width of cells in stencil - - // get coefficients - const auto coeffs = LagrangeCoeff(cellWidth, 3, 1, 1); - - // reconstruct with central difference - return coeffs[0] * varU2 + coeffs[1] * varU1 + coeffs[2] * varD1 + - coeffs[3] * varD2; +double StencilWidth(const T &cellWidth, const int &start, const int &end) { + auto width = 0.0; + if (end > start) { + width = std::accumulate(std::begin(cellWidth) + start, + std::begin(cellWidth) + end, 0.0); + } else if (start > end) { // width is negative + width = -1.0 * std::accumulate(std::begin(cellWidth) + end, + std::begin(cellWidth) + start, 0.0); + } + return width; } template -T Derivative2nd(const double &x_0, const double &x_1, const double &x_2, +auto Derivative2nd(const double &x_0, const double &x_1, const double &x_2, const T &y_0, const T &y_1, const T &y_2) { const auto fwdDiff1stOrder = (y_2 - y_1) / (0.5 * (x_2 + x_1)); const auto bckDiff1stOrder = (y_1 - y_0) / (0.5 * (x_1 + x_0)); diff --git a/include/varArray.hpp b/include/varArray.hpp new file mode 100644 index 0000000..7343b49 --- /dev/null +++ b/include/varArray.hpp @@ -0,0 +1,580 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef VARARRAYHEADERDEF +#define VARARRAYHEADERDEF + +#include +#include +#include +#include +#include +#include +#include +#include "macros.hpp" + +using std::ostream; +using std::vector; + +// forward declarations +template +class arrayView; + +// Class to hold an array of variables. Length is equal to number of equations +// being solved for. +class varArray { + vector data_; + int momentumIndex_; + int energyIndex_; + int turbulenceIndex_; + + public: + // constructor + varArray() {} + varArray(const int &numEqns, const int &numSpecies, const double &val) + : data_(numEqns, val), + momentumIndex_(numSpecies), + energyIndex_(momentumIndex_ + 3), + turbulenceIndex_(energyIndex_ + 1) { + MSG_ASSERT(numEqns > numSpecies && numEqns >= 5, + "number of equations should be greater than number of species"); + } + varArray(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies, 0.0) {} + varArray(const vector::const_iterator &b, + const vector::const_iterator &e, const int &numSpecies) + : data_(b, e), + momentumIndex_(numSpecies), + energyIndex_(momentumIndex_ + 3), + turbulenceIndex_(energyIndex_ + 1) { + MSG_ASSERT(static_cast(data_.size()) > numSpecies && data_.size() >= 5U, + "number of equations should be greater than number of species"); + } + + // move constructor and assignment operator + varArray(varArray&&) noexcept = default; + varArray& operator=(varArray&&) noexcept = default; + + // copy constructor and assignment operator + varArray(const varArray&) = default; + varArray& operator=(const varArray&) = default; + + // member functions + int Size() const { return data_.size(); } + int NumSpecies() const { return momentumIndex_; } + int NumTurbulence() const { return this->Size() - turbulenceIndex_; } + bool IsMultiSpecies() const { return this->NumSpecies() > 1; } + bool HasTurbulenceData() const { return this->Size() != turbulenceIndex_; } + int MomentumXIndex() const { return momentumIndex_; } + int MomentumYIndex() const { return momentumIndex_ + 1; } + int MomentumZIndex() const { return momentumIndex_ + 2; } + int EnergyIndex() const { return energyIndex_; } + int TurbulenceIndex() const { return turbulenceIndex_; } + double SpeciesSum() const { + return std::accumulate(std::begin(data_), + std::begin(data_) + this->NumSpecies(), 0.0); + } + + const double &SpeciesN(const int &ii) const { + MSG_ASSERT(ii < momentumIndex_, "requesting species variable out of range"); + return (*this)[ii]; + } + const double &MomentumX() const { return (*this)[momentumIndex_]; } + const double &MomentumY() const { return (*this)[momentumIndex_ + 1]; } + const double &MomentumZ() const { return (*this)[momentumIndex_ + 2]; } + const double &Energy() const { return (*this)[energyIndex_]; } + const double &TurbulenceN(const int &ii) const { + MSG_ASSERT(turbulenceIndex_ + ii < this->Size(), + "requesting turbulence variable out of range"); + return (*this)[turbulenceIndex_ + ii]; + } + + void Zero() { std::fill(std::begin(data_), std::end(data_), 0.0); } + double Sum() { + return std::accumulate(std::begin(data_), std::end(data_), 0.0); + } + void SquareRoot() { + std::for_each(std::begin(data_), std::end(data_), + [](double &val) { val = sqrt(val); }); + } + bool IsZero() const { + return std::all_of(std::begin(data_), std::end(data_), + [](const double &val) { return val == 0.0; }); + } + varArray Squared() const; + + // provide begin and end so std::begin and std::end can be used + // use lower case to conform with std::begin, std::end + auto begin() noexcept {return data_.begin();} + const auto begin() const noexcept {return data_.begin();} + auto end() noexcept {return data_.end();} + const auto end() const noexcept {return data_.end();} + + arrayView GetView() const; + + // operator overloads + const double & operator[](const int &r) const { return data_[r]; } + double & operator[](const int &r) { return data_[r]; } + + // destructor + virtual ~varArray() noexcept {} +}; + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// function declarations ---------------------------------------------------- +// operator overload for addition +template ::value>> +T & operator+=(T &lhs, const T &rhs) { + MSG_ASSERT(lhs.Size() == rhs.Size(), "array types must be same size"); + for (auto rr = 0; rr < lhs.Size(); ++rr) { + lhs[rr] += rhs[rr]; + } + return lhs; +} + +// operator overload for different type addition - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +& operator+=(T1 &lhs, const T2 &rhs) { + return lhs += dynamic_cast(rhs); +} + +// operator overload for different type addition - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +& operator+=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) += rhs; +} + +// operator overload for different type addition - T2/T1 not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +& operator+=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) += dynamic_cast(rhs); +} + +// -------------------------------------------------------------------------- +// operator overload for subtraction +template ::value>> +T & operator-=(T &lhs, const T &rhs) { + MSG_ASSERT(lhs.Size() == rhs.Size(), "array types must be same size"); + for (auto rr = 0; rr < lhs.Size(); ++rr) { + lhs[rr] -= rhs[rr]; + } + return lhs; +} + +// operator overload for different type subtraction - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +& operator-=(T1 &lhs, const T2 &rhs) { + return lhs -= dynamic_cast(rhs); +} + +// operator overload for different type subtraction - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +& operator-=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) -= rhs; +} + +// operator overload for different type subtraction - T2/T1 not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +& operator-=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) -= dynamic_cast(rhs); +} + +// -------------------------------------------------------------------------- +// operator overload for elementwise multiplication +template ::value>> +T & operator*=(T &lhs, const T &rhs) { + MSG_ASSERT(lhs.Size() == rhs.Size(), "array types must be same size"); + for (auto rr = 0; rr < lhs.Size(); ++rr) { + lhs[rr] *= rhs[rr]; + } + return lhs; +} + +// operator overload for different type multiplication - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +& operator*=(T1 &lhs, const T2 &rhs) { + return lhs *= dynamic_cast(rhs); +} + +// operator overload for different type multiplication - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +& operator*=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) *= rhs; +} + +// operator overload for different type addition - T2/T1 not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +& operator*=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) *= dynamic_cast(rhs); +} + +// -------------------------------------------------------------------------- +// operator overload for elementwise division +template ::value>> +T & operator/=(T &lhs, const T &rhs) { + MSG_ASSERT(lhs.Size() == rhs.Size(), "array types must be same size"); + for (auto rr = 0; rr < lhs.Size(); ++rr) { + lhs[rr] /= rhs[rr]; + } + return lhs; +} + +// operator overload for different type division - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +& operator/=(T1 &lhs, const T2 &rhs) { + return lhs /= dynamic_cast(rhs); +} + +// operator overload for different type division - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +& operator/=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) /= rhs; +} + +// operator overload for different type division - T2/T1 not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +& operator/=(T1 &lhs, const T2 &rhs) { + return dynamic_cast(lhs) /= dynamic_cast(rhs); +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// operator overload for same type addition +template ::value>> +inline const T operator+(T lhs, const T &rhs) { + return lhs += rhs; +} + +// operator overload for different type addition - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +operator+(T1 lhs, const T2 &rhs) { + return lhs += rhs; +} + +// operator overload for different type addition - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +operator+(T1 lhs, const T2 &rhs) { + return lhs += rhs; +} + +// operator overload for different type addition - T1/T2 are not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +operator+(T1 lhs, const T2 &rhs) { + return lhs += rhs; +} + +// operator overload for same type subtraction +template ::value>> +inline const T operator-(T lhs, const T &rhs) { + return lhs -= rhs; +} + +// operator overload for different type subtraction - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +operator-(T1 lhs, const T2 &rhs) { + return lhs -= rhs; +} + +// operator overload for different type subtraction - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +operator-(T1 lhs, const T2 &rhs) { + return lhs -= rhs; +} + +// operator overload for different type subtraction - T1/T2 are not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +operator-(T1 lhs, const T2 &rhs) { + return lhs -= rhs; +} + + +// operator overload for same type multiplication +template ::value>> +inline const T operator*(T lhs, const T &rhs) { + return lhs *= rhs; +} + +// operator overload for different type multiplication - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +operator*(T1 lhs, const T2 &rhs) { + return lhs *= rhs; +} + +// operator overload for different type multiplication - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +operator*(T1 lhs, const T2 &rhs) { + return lhs *= rhs; +} + +// operator overload for different type multiplication - T1/T2 are not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +operator*(T1 lhs, const T2 &rhs) { + return lhs *= rhs; +} + +// operator overload for same type division +template ::value>> +inline const T operator/(T lhs, const T &rhs) { + return lhs /= rhs; +} + +// operator overload for different type division - T1 is base of T2 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T1> +operator/(T1 lhs, const T2 &rhs) { + return lhs /= rhs; +} + +// operator overload for different type division - T2 is base of T1 +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + std::is_base_of::value, T2> +operator/(T1 lhs, const T2 &rhs) { + return lhs /= rhs; +} + +// operator overload for different type division - T1/T2 are not base/derived +template +inline const typename std::enable_if_t::value && + std::is_base_of::value && + !(std::is_base_of::value || + std::is_base_of::value), varArray> +operator/(T1 lhs, const T2 &rhs) { + return lhs /= rhs; +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// operator overloads for double -------------------------------------------- +// operator overload for addition +template ::value>> +T & operator+=(T &lhs, const double &scalar) { + for (auto ii = 0; ii < lhs.Size(); ++ii) { + lhs[ii] += scalar; + } + return lhs; +} + +template ::value>> +inline T operator+(T lhs, const double &s) { + return lhs += s; +} + +// operator overload for subtraction with a scalar +template ::value>> +T & operator-=(T &lhs, const double &scalar) { + for (auto ii = 0; ii < lhs.Size(); ++ii) { + lhs[ii] -= scalar; + } + return lhs; +} + +template ::value>> +inline T operator-(T lhs, const double &s) { + return lhs -= s; +} + +// operator overload for elementwise multiplication +template ::value>> +T & operator*=(T & lhs, const double &scalar) { + for (auto ii = 0; ii < lhs.Size(); ++ii) { + lhs[ii] *= scalar; + } + return lhs; +} + +template ::value>> +inline T operator*(T lhs, const double &s) { + return lhs *= s; +} + +// operator overload for elementwise division +template ::value>> +T & operator/=(T &lhs, const double &scalar) { + for (auto ii = 0; ii < lhs.Size(); ++ii) { + lhs[ii] /= scalar; + } + return lhs; +} + +template ::value>> +inline T operator/(T lhs, const double &s) { + return lhs /= s; +} + +template ::value>> +inline const T operator+(const double &lhs, T rhs) { + return rhs += lhs; +} + +template ::value>> +inline const T operator-(const double &lhs, T rhs) { + for (auto rr = 0; rr < rhs.Size(); ++rr) { + rhs[rr] = lhs - rhs[rr]; + } + return rhs; +} + +template ::value>> +inline const T operator*(const double &lhs, T rhs) { + return rhs *= lhs; +} + +template ::value>> +inline const T operator/(const double &lhs, T rhs) { + for (auto rr = 0; rr < rhs.Size(); ++rr) { + rhs[rr] = lhs / rhs[rr]; + } + return rhs; +} + +template ::value>> +ostream &operator<<(ostream &os, const T &m) { + for (auto rr = 0; rr < m.Size(); ++rr) { + os << m[rr] << std::endl; + } + return os; +} + +// -------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// Derived wrapper classes for different variable types +// -------------------------------------------------------------------------- +class residual : public varArray { + public: + // constructor + residual(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies) {} + residual(const vector::const_iterator &b, + const vector::const_iterator &e, const int &numSpecies) + : varArray(b, e, numSpecies) {} + + // move constructor and assignment operator + residual(residual&&) noexcept = default; + residual& operator=(residual&&) noexcept = default; + + // copy constructor and assignment operator + residual(const residual&) = default; + residual& operator=(const residual&) = default; + + // member functions + const double & MassN(const int &ii) const { return this->SpeciesN(ii); } + void GlobalReduceMPI(const int &); + + arrayView GetView() const; + + // destructor + virtual ~residual() noexcept {} +}; + + +#endif diff --git a/include/vector3d.hpp b/include/vector3d.hpp index cf7cce9..f56077f 100644 --- a/include/vector3d.hpp +++ b/include/vector3d.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,8 +28,9 @@ #include // sqrt() #include // ostream #include // is_arithmetic - -#define LENGTH 3 +#include +#include +#include using std::ostream; @@ -39,7 +40,7 @@ class vector3d { static_assert(std::is_arithmetic::value, "vector3d requires an arithmetic type!"); - T data_[LENGTH]; + T data_[3]; public: // constructor @@ -63,6 +64,13 @@ class vector3d { bool operator!=(const vector3d &v1) const {return !(*this == v1);} bool CompareWithTol(const vector3d &v2, const double &tol = 1.0e-10) const; + // provide begin and end so std::begin and std::end can be used + // use lower case to conform with std::begin, std::end + auto begin() noexcept {return std::begin(data_);} + const auto begin() const noexcept {return std::begin(data_);} + auto end() noexcept {return std::end(data_);} + const auto end() const noexcept {return std::end(data_);} + inline vector3d & operator+=(const vector3d &); inline vector3d & operator-=(const vector3d &); inline vector3d & operator*=(const vector3d &); @@ -180,36 +188,32 @@ class unitVec3dMag { // operator overload for addition template vector3d & vector3d::operator+=(const vector3d &vec) { - for (auto rr = 0; rr < LENGTH; rr++) { - data_[rr] += vec[rr]; - } + std::transform(this->begin(), this->end(), vec.begin(), this->begin(), + std::plus()); return *this; } // operator overload for subtraction with a scalar template vector3d & vector3d::operator-=(const vector3d &vec) { - for (auto rr = 0; rr < LENGTH; rr++) { - data_[rr] -= vec[rr]; - } + std::transform(this->begin(), this->end(), vec.begin(), this->begin(), + std::minus()); return *this; } // operator overload for elementwise multiplication template vector3d & vector3d::operator*=(const vector3d &vec) { - for (auto rr = 0; rr < LENGTH; rr++) { - data_[rr] *= vec[rr]; - } + std::transform(this->begin(), this->end(), vec.begin(), this->begin(), + std::multiplies()); return *this; } // operator overload for elementwise division template vector3d & vector3d::operator/=(const vector3d &vec) { - for (auto rr = 0; rr < LENGTH; rr++) { - data_[rr] /= vec[rr]; - } + std::transform(this->begin(), this->end(), vec.begin(), this->begin(), + std::divides()); return *this; } @@ -237,36 +241,32 @@ inline const vector3d operator/(vector3d lhs, const vector3d &rhs) { // operator overload for addition template vector3d & vector3d::operator+=(const T &scalar) { - for (auto &val : data_) { - val += scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val += scalar; }); return *this; } // operator overload for subtraction with a scalar template vector3d & vector3d::operator-=(const T &scalar) { - for (auto &val : data_) { - val -= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val -= scalar; }); return *this; } // operator overload for elementwise multiplication template vector3d & vector3d::operator*=(const T &scalar) { - for (auto &val : data_) { - val *= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val *= scalar; }); return *this; } // operator overload for elementwise division template vector3d & vector3d::operator/=(const T &scalar) { - for (auto &val : data_) { - val /= scalar; - } + std::for_each(this->begin(), this->end(), + [&scalar](auto &val) { val /= scalar; }); return *this; } @@ -277,9 +277,7 @@ inline const vector3d operator+(const T &lhs, vector3d rhs) { template inline const vector3d operator-(const T &lhs, vector3d rhs) { - for (auto rr = 0; rr < LENGTH; rr++) { - rhs[rr] = lhs - rhs[rr]; - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs - val; }); return rhs; } @@ -290,9 +288,7 @@ inline const vector3d operator*(const T &lhs, vector3d rhs) { template inline const vector3d operator/(const T &lhs, vector3d rhs) { - for (auto rr = 0; rr < LENGTH; rr++) { - rhs[rr] = lhs / rhs[rr]; - } + std::for_each(rhs.begin(), rhs.end(), [&lhs](auto &val) { val = lhs / val; }); return rhs; } @@ -305,8 +301,7 @@ ostream &operator<<(ostream &os, const vector3d &v) { // Function to calculate the dot product of two vectors template T vector3d::DotProd(const vector3d&v2) const { - return data_[0] * v2.data_[0] + data_[1] * v2.data_[1] + - data_[2] * v2.data_[2]; + return std::inner_product(this->begin(), this->end(), v2.begin(), T(0)); } // operator overload for comparison @@ -359,7 +354,7 @@ T vector3d::MagSq() const { // Function to sum the elements in the vector template T vector3d::SumElem() const { - return data_[0] + data_[1] + data_[2]; + return std::accumulate(this->begin(), this->end(), T(0)); } // Function to calculate the distance between two vector3ds @@ -371,8 +366,8 @@ T vector3d::Distance(const vector3d&v2) const { // Function to calculate the distance squared between two vector3ds template T vector3d::DistSq(const vector3d&v2) const { - return pow(data_[0] - v2.data_[0], 2) + pow(data_[1] - v2.data_[1], 2) + - pow(data_[2] - v2.data_[2], 2); + auto diff = *this - v2; + return diff.MagSq(); } // Function to normalize a vector3d into a unit vector @@ -384,9 +379,7 @@ vector3d vector3d::Normalize() const { // Function to zero out a vector template void vector3d::Zero() { - for (auto &val : data_) { - val = 0; - } + std::fill(this->begin(), this->end(), T(0)); } diff --git a/include/viscousFlux.hpp b/include/viscousFlux.hpp index 70e1574..d2b3991 100644 --- a/include/viscousFlux.hpp +++ b/include/viscousFlux.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,10 +19,10 @@ #define VISCFLUXHEADERDEF // define the macro #include // cout -#include // unique_ptr +#include #include "vector3d.hpp" // vector3d #include "tensor.hpp" // tensor -#include "macros.hpp" +#include "varArray.hpp" using std::cout; using std::endl; @@ -31,23 +31,18 @@ using std::ostream; using std::unique_ptr; // forward class declarations -class primVars; -class eos; -class transport; -class thermodynamic; +class primitive; +class physics; class turbModel; class squareMatrix; struct wallVars; -class viscousFlux { - double data_[NUMVARS - 1]; // viscous flux for x-momentum equation - // viscous flux for y-momentum equation - // viscous flux for z-momentum equation - // viscous flux for energy equation - +class viscousFlux : public varArray { public: // constructors - viscousFlux() : data_{0.0} {} + viscousFlux() : varArray() {} + viscousFlux(const int &numEqns, const int &numSpecies) + : varArray(numEqns, numSpecies) {} // move constructor and assignment operator viscousFlux(viscousFlux&&) noexcept = default; @@ -58,170 +53,26 @@ class viscousFlux { viscousFlux& operator=(const viscousFlux&) = default; // member functions - double MomX() const { return data_[0]; } - double MomY() const { return data_[1]; } - double MomZ() const { return data_[2]; } - double Engy() const { return data_[3]; } - double MomK() const { return data_[4]; } - double MomO() const { return data_[5]; } - - void CalcFlux(const tensor &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &eqnState, const vector3d &, + void CalcFlux(const tensor &, const physics &, + const vector3d &, const vector3d &, const vector3d &, const vector3d &, - const vector3d &, const unique_ptr &, - const primVars &, const double &, const double &, - const double &); - wallVars CalcWallFlux(const tensor &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const vector3d &, + const vector> &, const primitive &, + const double &, const double &, const double &); + wallVars CalcWallFlux(const tensor &, const physics &, const vector3d &, const vector3d &, - const vector3d &, const unique_ptr &, - const primVars &, const double &, const double &, + const vector3d &, const vector3d &, + const primitive &, const double &, const double &, const double &); void CalcWallLawFlux(const vector3d &, const double &, const double &, const double &, const vector3d &, const vector3d &, const vector3d &, const vector3d &, const unique_ptr &); - inline viscousFlux &operator+=(const viscousFlux &); - inline viscousFlux & operator-=(const viscousFlux &); - inline viscousFlux & operator*=(const viscousFlux &); - inline viscousFlux & operator/=(const viscousFlux &); - - inline viscousFlux & operator+=(const double &); - inline viscousFlux & operator-=(const double &); - inline viscousFlux & operator*=(const double &); - inline viscousFlux & operator/=(const double &); - - inline viscousFlux operator+(const double &s) const { - auto lhs = *this; - return lhs += s; - } - inline viscousFlux operator-(const double &s) const { - auto lhs = *this; - return lhs -= s; - } - inline viscousFlux operator*(const double &s) const { - auto lhs = *this; - return lhs *= s; - } - inline viscousFlux operator/(const double &s) const { - auto lhs = *this; - return lhs /= s; - } - - friend inline const viscousFlux operator-(const double &lhs, viscousFlux rhs); - friend inline const viscousFlux operator/(const double &lhs, viscousFlux rhs); - // destructor ~viscousFlux() noexcept {} }; // function definitions -// operator overload for addition -viscousFlux & viscousFlux::operator+=(const viscousFlux &arr) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - data_[rr] += arr.data_[rr]; - } - return *this; -} - -// operator overload for subtraction with a scalar -viscousFlux & viscousFlux::operator-=(const viscousFlux &arr) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - data_[rr] -= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise multiplication -viscousFlux & viscousFlux::operator*=(const viscousFlux &arr) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - data_[rr] *= arr.data_[rr]; - } - return *this; -} - -// operator overload for elementwise division -viscousFlux & viscousFlux::operator/=(const viscousFlux &arr) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - data_[rr] /= arr.data_[rr]; - } - return *this; -} - -inline const viscousFlux operator+(viscousFlux lhs, const viscousFlux &rhs) { - return lhs += rhs; -} - -inline const viscousFlux operator-(viscousFlux lhs, const viscousFlux &rhs) { - return lhs -= rhs; -} - -inline const viscousFlux operator*(viscousFlux lhs, const viscousFlux &rhs) { - return lhs *= rhs; -} - -inline const viscousFlux operator/(viscousFlux lhs, const viscousFlux &rhs) { - return lhs /= rhs; -} - -// operator overloads for double ------------------------------------- -// operator overload for addition -viscousFlux & viscousFlux::operator+=(const double &scalar) { - for (auto &val : data_) { - val += scalar; - } - return *this; -} - -// operator overload for subtraction with a scalar -viscousFlux & viscousFlux::operator-=(const double &scalar) { - for (auto &val : data_) { - val -= scalar; - } - return *this; -} - -// operator overload for elementwise multiplication -viscousFlux & viscousFlux::operator*=(const double &scalar) { - for (auto &val : data_) { - val *= scalar; - } - return *this; -} - -// operator overload for elementwise division -viscousFlux & viscousFlux::operator/=(const double &scalar) { - for (auto &val : data_) { - val /= scalar; - } - return *this; -} - -inline const viscousFlux operator+(const double &lhs, viscousFlux rhs) { - return rhs += lhs; -} - -inline const viscousFlux operator-(const double &lhs, viscousFlux rhs) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - rhs.data_[rr] = lhs - rhs.data_[rr]; - } - return rhs; -} - -inline const viscousFlux operator*(const double &lhs, viscousFlux rhs) { - return rhs *= lhs; -} - -inline const viscousFlux operator/(const double &lhs, viscousFlux rhs) { - for (auto rr = 0; rr < NUMVARS - 1; rr++) { - rhs.data_[rr] = lhs / rhs.data_[rr]; - } - return rhs; -} - ostream &operator<<(ostream &os, const viscousFlux &); #endif diff --git a/include/wallData.hpp b/include/wallData.hpp index 12c1d59..7013081 100644 --- a/include/wallData.hpp +++ b/include/wallData.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ using std::shared_ptr; // forward declarations class input; class eos; -class primVars; +class primitive; // structure to hold wall variables struct wallVars { @@ -48,26 +48,39 @@ struct wallVars { double frictionVelocity_ = 0.0; double tke_ = 0.0; double sdr_ = 0.0; + vector mf_; + + // constructor + explicit wallVars(const int &ns) : mf_(ns, 0.0) {} + wallVars() : wallVars(0) {} bool SwitchToLowRe() const {return yplus_ < 10.;} + void Pack(char *(&), const int &, int &, const MPI_Datatype &) const; + void PackSize(int &, const MPI_Datatype &) const; + void Unpack(char *(&), const int &, int &, const MPI_Datatype &, + const int &); }; class wallData { double inviscidForce_; double viscousForce_; + int numSpecies_; shared_ptr bcData_; boundarySurface surf_; multiArray3d data_; public: // constructor - wallData(const boundarySurface &surf, const shared_ptr &bc) + wallData(const boundarySurface &surf, const shared_ptr &bc, + const int &numSpecies) : inviscidForce_(0.0), viscousForce_(0.0), + numSpecies_(numSpecies), bcData_(bc), surf_(surf), - data_(surf.NumI(), surf.NumJ(), surf.NumK(), 0) {} - wallData() : wallData(boundarySurface(), nullptr) {} + data_(surf.NumI(), surf.NumJ(), surf.NumK(), 0, 1, + wallVars(numSpecies)) {} + wallData() : wallData(boundarySurface(), nullptr, 0) {} // move constructor and assignment operator wallData(wallData &&) = default; @@ -82,6 +95,7 @@ class wallData { int NumJ() const { return data_.NumJ(); } int NumK() const { return data_.NumK(); } int Size() const { return data_.Size(); } + int NumSpecies() const { return numSpecies_; } double InviscidForce() const { return inviscidForce_; } double ViscousForce() const { return viscousForce_; } vector3d WallShearStress(const int &ii, const int &jj, @@ -92,6 +106,8 @@ class wallData { double WallEddyViscosity(const int &ii, const int &jj, const int &kk) const; double WallViscosity(const int &ii, const int &jj, const int &kk) const; double WallDensity(const int &ii, const int &jj, const int &kk) const; + vector WallMassFractions(const int &ii, const int &jj, const int &kk) const; + vector WallDensityVec(const int &ii, const int &jj, const int &kk) const; double WallTke(const int &ii, const int &jj, const int &kk) const; double WallSdr(const int &ii, const int &jj, const int &kk) const; double WallPressure(const int &ii, const int &jj, const int &kk, @@ -99,8 +115,8 @@ class wallData { double WallFrictionVelocity(const int &ii, const int &jj, const int &kk) const; vector3d WallVelocity() const {return bcData_->Velocity();} - primVars WallState(const int &ii, const int &jj, const int &kk, - const unique_ptr &eqnState) const; + void WallState(const int &ii, const int &jj, const int &kk, + const unique_ptr &eqnState, primitive &wState) const; int WallVarsSize() const { return data_.Size(); } void PackWallData(char *(&), const int &, int &, const MPI_Datatype &) const; void PackSize(int &, const MPI_Datatype &) const; diff --git a/include/wallLaw.hpp b/include/wallLaw.hpp index 399e4d0..f8f9127 100644 --- a/include/wallLaw.hpp +++ b/include/wallLaw.hpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,15 +22,13 @@ #include "vector3d.hpp" #include "tensor.hpp" -#include "primVars.hpp" +#include "primitive.hpp" +#include "arrayView.hpp" using std::unique_ptr; // forward class declaration -class eos; -class transport; -class thermodynamic; -class turbModel; +class physics; struct wallVars; class wallLaw { @@ -38,7 +36,7 @@ class wallLaw { const double vonKarmen_; const double wallConst_; const double wallDist_; - const primVars state_; + const primitive state_; double yplus0_; double beta_; @@ -60,29 +58,25 @@ class wallLaw { void UpdateGamma(const unique_ptr &, const double &); void CalcYplusWhite(); double CalcHeatFlux(const unique_ptr &) const; - void SetWallVars(const double &, const unique_ptr &, - const unique_ptr &, - const unique_ptr &); - void EddyVisc(const unique_ptr &, const unique_ptr &); + void SetWallVars(const double &, const physics &); + void EddyVisc(const physics &); void CalcVelocities(const double &, const double &); - void CalcTurbVars(const unique_ptr &, const unique_ptr &, - const unique_ptr &, double &, double &); + void CalcTurbVars(const physics &, double &, double &); double CalcYplusRoot(const double &) const; double ShearStressMag() const {return uStar_ * uStar_ * rhoW_;}; void CalcRecoveryFactor(const unique_ptr &, const double &); - double CalcWallTemperature(const unique_ptr &, - const unique_ptr &, - const double &) const; + double CalcWallTemperature(const physics &, const double &) const; public: // constructor - wallLaw(const double &k, const double &c, const primVars &s, const double &d, + template + wallLaw(const double &k, const double &c, const T &s, const double &d, const bool &isRANS) : isRANS_(isRANS), vonKarmen_(k), wallConst_(c), wallDist_(d), - state_(s), + state_(s.begin(), s.end(), s.NumSpecies()), yplus0_(std::exp(-k * c)), beta_(0.0), gamma_(0.0), @@ -96,7 +90,11 @@ class wallLaw { muW_(0.0), mutW_(0.0), kW_(0.0), - recoveryFactor_(0.0) {} + recoveryFactor_(0.0) { + static_assert(std::is_same::value || + std::is_same::value, + "T requires primitive or primativeView type"); + } // move constructor and assignment operator wallLaw(wallLaw&&) = default; @@ -110,22 +108,13 @@ class wallLaw { double VonKarmen() const { return vonKarmen_; } double WallConstant() const { return wallConst_; } wallVars AdiabaticBCs(const vector3d &, const vector3d &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const bool &); + const vector &, const physics &, const bool &); wallVars HeatFluxBCs(const vector3d &, const vector3d &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, + const vector &, const physics &, const double &, const bool &); wallVars IsothermalBCs(const vector3d &, const vector3d &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, - const unique_ptr &, const double &, - const bool &); + const vector &, const physics &, + const double &, const bool &); // destructor ~wallLaw() noexcept {} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 743e4bf..db555f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ project (aither) # set version number set (aither_VERSION_MAJOR 0) -set (aither_VERSION_MINOR 6) +set (aither_VERSION_MINOR 8) set (aither_VERSION_PATCH 0) message (STATUS "Cmake version ${CMAKE_VERSION}") @@ -13,6 +13,7 @@ message (STATUS "Library path: ${CMAKE_LIBRARY_PATH}") message (STATUS "Prefix path: ${CMAKE_PREFIX_PATH}") message (STATUS "Module path: ${CMAKE_MODULE_PATH}") message (STATUS "Build type is: ${CMAKE_BUILD_TYPE}") +message (STATUS "System name: ${CMAKE_SYSTEM_NAME}") # add include directories include_directories(${CMAKE_SOURCE_DIR}/include) @@ -28,19 +29,22 @@ configure_file ( set(sources main.cpp boundaryConditions.cpp + conserved.cpp eos.cpp fluid.cpp fluxJacobian.cpp - genArray.cpp + ghostStates.cpp input.cpp inputStates.cpp inviscidFlux.cpp kdtree.cpp + limiter.cpp + matMultiArray3d.cpp matrix.cpp output.cpp parallel.cpp plot3d.cpp - primVars.cpp + primitive.cpp procBlock.cpp range.cpp resid.cpp @@ -51,6 +55,7 @@ set(sources turbulence.cpp uncoupledScalar.cpp utility.cpp + varArray.cpp viscousFlux.cpp wallData.cpp wallLaw.cpp @@ -77,31 +82,31 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() # set additional c++ flags for all build types -if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} /O2 /DNDEBUG") +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS}") else() - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native -O3 -DNDEBUG") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -Wall -pedantic") endif() # release build type -if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") - set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS}") +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS} /O2 /DNDEBUG") else() - set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native -DNDEBUG") endif() # debug build type -if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_SPEC_FLAGS} /Wall /Od /PROFILE") else() set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -O0 -ggdb -pg --coverage") endif() # create profile build type -if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") - set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} /PROFILE") +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} /PROFILE /DNDEBUG") else() - set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -pg") + set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -pg -DNDEBUG") endif() # set compiler flags based on release type @@ -140,3 +145,7 @@ install (TARGETS aither aitherStatic aitherShared FILE (GLOB files "${CMAKE_SOURCE_DIR}/include/*.hpp") install (FILES ${files} DESTINATION include) install (FILES "${PROJECT_BINARY_DIR}/macros.hpp" DESTINATION include) + +# install fluid database files +FILE (GLOB files "${CMAKE_SOURCE_DIR}/fluidDatabase/*.dat") +install (FILES ${files} DESTINATION fluidDatabase) diff --git a/src/boundaryConditions.cpp b/src/boundaryConditions.cpp index a1f1a4b..1f23480 100644 --- a/src/boundaryConditions.cpp +++ b/src/boundaryConditions.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ #include // max #include // string #include // vector +#include +#include #include "boundaryConditions.hpp" #include "vector3d.hpp" // vector3d #include "plot3d.hpp" // plot3dBlock @@ -87,6 +89,21 @@ bool boundarySurface::operator==(const boundarySurface &surf) const { return isEqualType && isEqualData; } +bool boundarySurface::operator<(const boundarySurface &s) const { + if (this->SurfaceType() == s.SurfaceType()) { + auto count = 0; + for (auto &self : data_) { + if (self != s.data_[count]) { + return self < s.data_[count]; + } + count++; + } + return false; + } else { + return this->SurfaceType() < s.SurfaceType(); + } +} + // Member function to return the boundary condition type given the // i,j,k face coordinates and the surface type boundarySurface boundaryConditions::GetBCSurface(const int &i, const int &j, @@ -145,6 +162,7 @@ boundarySurface boundaryConditions::GetBCSurface(const int &i, const int &j, } } else { cerr << "ERROR: Surface type " << surf << " is not recognized!" << endl; + exit(EXIT_FAILURE); } return surface; @@ -160,11 +178,10 @@ void boundaryConditions::AssignFromInput(const int &surfCounter, // surfCounter -- index at which to place data // tokens -- vector of strings read from input file - boundarySurface bcSurf_(tokens[0], stoi(tokens[1]), - stoi(tokens[2]), stoi(tokens[3]), - stoi(tokens[4]), stoi(tokens[5]), - stoi(tokens[6]), stoi(tokens[7])); - surfs_[surfCounter] = bcSurf_; + boundarySurface bcSurf(tokens[0], stoi(tokens[1]), stoi(tokens[2]), + stoi(tokens[3]), stoi(tokens[4]), stoi(tokens[5]), + stoi(tokens[6]), stoi(tokens[7])); + surfs_[surfCounter] = bcSurf; } /* Member function to determine of what sides of a boundary condition surface @@ -468,6 +485,55 @@ vector GetConnectionBCs(const vector &bc, return connections; } +/* Function to go through the boundary conditions and pair the connection + BCs for a single block and determine their orientation */ +map> GetBlockInterConnBCs( + const vector &bc, const vector &grid, + const int &blk) { + // bc -- vector of boundaryConditions for all blocks + // grid -- vector of plot3Dblocks for entire computational mesh + MSG_ASSERT(blk < static_cast(bc.size()), "block out of range"); + MSG_ASSERT(blk < static_cast(grid.size()), "block out of range"); + + map> selfConnections; + for (auto jj = 0; jj < bc[blk].NumSurfaces(); ++jj) { + // if boundary condition is connection, store data + if (bc[blk].GetBCTypes(jj) == "interblock") { + const auto selfSurf = bc[blk].GetSurface(jj); + // create patch + // don't care about rank, local position, or borders - use dummy values + array border = {false, false, false, false}; + const auto rank = 0; + const auto locPos = 0; + patch selfPatch(selfSurf, grid[blk], blk, border, rank, locPos); + + // search through partner block and find all matches + const auto &partnerBC = bc[selfSurf.PartnerBlock()]; + for (auto ii = 0; ii < partnerBC.NumSurfaces(); ++ii) { + if (partnerBC.GetBCTypes(ii) == "interblock") { + const auto partnerSurf = partnerBC.GetSurface(ii); + if (partnerSurf.PartnerBlock() == blk && + selfSurf.PartnerSurface() == partnerSurf.SurfaceType() && + partnerSurf.PartnerSurface() == selfSurf.SurfaceType() && + partnerSurf != selfSurf) { + patch partPatch(partnerSurf, grid[selfSurf.PartnerBlock()], + selfSurf.PartnerBlock(), border, rank, locPos); + // Test for match + // need orientation relative to partner + connection match(partPatch, selfPatch); + if (match.TestPatchMatch(partPatch, selfPatch)) { // match found + selfConnections.insert(std::make_pair( + selfSurf, std::make_pair(partnerSurf, match.Orientation()))); + } + } + } + } + } + } + return selfConnections; +} + + /* Function to take in two patches and return if they are matched. If there is a match it uses the patches to modify the given connection to contain the information on this match. @@ -1013,14 +1079,41 @@ int boundaryConditions::BlockDimK() const { return dim; } +vector> boundaryConditions::CGridPairs( + const int &blk) const { + vector> pairs; + for (auto ii = 0U; ii < surfs_.size(); ++ii) { + // find interblock with connection to current bc + if (surfs_[ii].BCType() == "interblock" && + surfs_[ii].PartnerBlock() == blk) { + for (auto jj = ii + 1; jj < surfs_.size(); ++jj) { + // find second interblock with connection to current bc + if (surfs_[jj].BCType() == "interblock" && + surfs_[jj].PartnerBlock() == blk) { + // check that same surface is connected to itself and that ranges + // match + // WARNING - if a cgrid has more than one pair of connections that + // have the same ranges, it may not get matched correctly - this + // shouldn't be the case with properly formatted grid BCs from + // Pointwise + if (surfs_[ii].PartnerSurface() == surfs_[jj].PartnerSurface() && + surfs_[ii].RangeDir1().Size() == surfs_[jj].RangeDir1().Size() && + surfs_[ii].RangeDir2().Size() == surfs_[jj].RangeDir2().Size()) { + pairs.push_back(std::make_pair(surfs_[ii], surfs_[jj])); + } + } + } + } + } + return pairs; +} /* Member function to split boundary conditions along a given direction at a given index. The calling instance retains the lower portion of the split, and the returned instance is the upper portion. */ -boundaryConditions boundaryConditions::Split(const string &dir, const int &ind, - const int &numBlk, - const int &newBlkNum, - vector &aSurf) { +boundaryConditions boundaryConditions::Split( + const string &dir, const int &ind, const int &numBlk, const int &newBlkNum, + vector &aSurf) { // dir -- direction to split it (i, j, k) // ind -- index of cell to split at // (this index is the last cell that remains in the lower split) @@ -1037,18 +1130,23 @@ boundaryConditions boundaryConditions::Split(const string &dir, const int &ind, boundaryConditions lower(0, 0, 0); boundaryConditions upper(0, 0, 0); - aSurf = vector(0); + const auto cGridPairs = this->CGridPairs(numBlk); + + aSurf.resize(0); auto insertedSplit = false; for (auto &lowSurf : surfs_) { - auto surfDir = lowSurf.Direction3(); - - if (lowSurf.IsConnection() && !(dir == "i" && lowSurf.SurfaceType() == 1) && + // effected interblocks are not lower surfaces parallel to split, or cgrids + if (lowSurf.BCType() == "interblock" && + !(dir == "i" && lowSurf.SurfaceType() == 1) && !(dir == "j" && lowSurf.SurfaceType() == 3) && - !(dir == "k" && lowSurf.SurfaceType() == 5)) { + !(dir == "k" && lowSurf.SurfaceType() == 5) && + lowSurf.PartnerBlock() != numBlk) { aSurf.push_back(lowSurf); } + auto surfDir = lowSurf.Direction3(); + // this block is only executed once, to insert the interface surface for the // lower and upper splits if (!insertedSplit && dir == surfDir) { //--------------------------------- @@ -1108,44 +1206,100 @@ boundaryConditions boundaryConditions::Split(const string &dir, const int &ind, upper.numSurfK_++; } insertedSplit = true; - } //----------------------------------------------------------------------- + } + // loop over cgrid pairs and update surfaces if a pair is split + // add to altered surfaces if a cgrid is broken in 2 auto split = false, low = false; - auto upSurf = lowSurf.Split(dir, ind, split, low); - if (split) { // if split push split to lower/upper bcs - lower.surfs_.push_back(lowSurf); - upper.surfs_.push_back(upSurf); - if (surfDir == "i") { - lower.numSurfI_++; - upper.numSurfI_++; - } else if (surfDir == "j") { - lower.numSurfJ_++; - upper.numSurfJ_++; - } else { - lower.numSurfK_++; - upper.numSurfK_++; + for (auto cpair : cGridPairs) { + if (cpair.first == lowSurf) { + auto upSurf = cpair.first.Split(dir, ind, split, low); + if (split) { // need to split partner + // cgrid connection is always reversed + auto revInd = cpair.second.Max(dir) - ind; + // both surfaces belong to upper + upSurf = cpair.second.Split(dir, revInd, split, low, false); + // lower split should connect to self (newblk), upper split to old blk + cpair.second.UpdateTagForSplitJoin(newBlkNum); + lowSurf.UpdateTagForSplitJoin(newBlkNum); + // need to subtract split index from result + if (dir == "i") { + cpair.second.MoveI(-ind); + upSurf.MoveI(-ind); + } else if (dir == "j") { + cpair.second.MoveJ(-ind); + upSurf.MoveJ(-ind); + } else { + cpair.second.MoveK(-ind); + upSurf.MoveK(-ind); + } + upper.surfs_.push_back(cpair.second); + upper.surfs_.push_back(upSurf); + if (cpair.second.Direction3() == "i") { + upper.numSurfI_++; + } else if (cpair.second.Direction3() == "j") { + upper.numSurfJ_++; + } else { + upper.numSurfK_++; + } + } else if (low) { + // cgrid broken into 2 blocks, lower needs to be updated to partner + // with new block + lowSurf.UpdateTagForSplitJoin(newBlkNum); + } + break; } - } else if (low) { // surface only on low side of split - lower.surfs_.push_back(lowSurf); - if (surfDir == "i") { - lower.numSurfI_++; - } else if (surfDir == "j") { - lower.numSurfJ_++; - } else { - lower.numSurfK_++; + } + + // split cgrids were already added, don't add them again + auto alreadyAdded = false; + for (auto cpair : cGridPairs) { + cpair.first.Split(dir, ind, split, low); + if (lowSurf == cpair.second && split) { + alreadyAdded = true; + break; } - } else { // surface only on upper side of split - upper.surfs_.push_back(upSurf); - if (surfDir == "i") { - upper.numSurfI_++; - } else if (surfDir == "j") { - upper.numSurfJ_++; - } else { - upper.numSurfK_++; + } + + if (!alreadyAdded) { + auto upSurf = lowSurf.Split(dir, ind, split, low); + if (split) { // if split push split to lower/upper bcs + lower.surfs_.push_back(lowSurf); + upper.surfs_.push_back(upSurf); + if (surfDir == "i") { + lower.numSurfI_++; + upper.numSurfI_++; + } else if (surfDir == "j") { + lower.numSurfJ_++; + upper.numSurfJ_++; + } else { + lower.numSurfK_++; + upper.numSurfK_++; + } + } else if (low) { // surface only on low side of split + lower.surfs_.push_back(lowSurf); + if (surfDir == "i") { + lower.numSurfI_++; + } else if (surfDir == "j") { + lower.numSurfJ_++; + } else { + lower.numSurfK_++; + } + } else { // surface only on upper side of split + upper.surfs_.push_back(upSurf); + if (surfDir == "i") { + upper.numSurfI_++; + } else if (surfDir == "j") { + upper.numSurfJ_++; + } else { + upper.numSurfK_++; + } } } } + std::sort(std::begin(lower.surfs_), std::end(lower.surfs_)); + std::sort(std::begin(upper.surfs_), std::end(upper.surfs_)); (*this) = lower; return upper; } @@ -1154,259 +1308,247 @@ boundaryConditions boundaryConditions::Split(const string &dir, const int &ind, one of its connection partners has been altered. The connection partner may have been split, its block number updated, or both. In order to correctly match up the dependents of the connection must be updated for the split.*/ -void boundaryConditions::DependentSplit(const boundarySurface &surf, - const plot3dBlock &part, - const plot3dBlock &self, - const int &sblk, const string &dir, - const int &ind, const int &lblk, - const int &ublk) { - // surf -- boundarySurface of partner block - // part -- plot3dBlock that surf is assigned to - // self -- plot3dBlock that (*this) is assigned to +void boundaryConditions::DependentSplit(const boundarySurface &partSurf, + boundarySurface selfSurf, + const int &orientation, const int &sblk, + const string &dir, const int &ind, + const int &lblk, const int &ublk) { + // partSurf -- boundarySurface of partner block + // selfSurf -- boundarySurface in this block + // orientation -- orientation of partSurf with this BC // sblk -- block number of self // dir -- direction that partner split was in // ind -- index of split // lblk -- lower block number in partner split // ublk -- upper block number in partner split - // dummy value used because connection is only used to test for match - array border = {false, false, false, false}; - - const patch partner(surf, part, lblk, border); // create patch for partner - - // loop over all surfaces - for (auto ii = 0; ii < this->NumSurfaces(); ii++) { - // create patch for candidate match - auto lowSurf = this->GetSurface(ii); - const patch candidate(lowSurf, self, sblk, border); - - connection match(candidate, partner); - if (match.TestPatchMatch(candidate, partner)) { // match found - // determine direction and index to split surface - string candDir = ""; - auto candInd = 0; - if (match.Orientation() == 1) { // same orientation - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; // candInd doesn't matter for dir 3 b/c block cannot - // be split, only partner block updated - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + // get iterator of self surface + auto selfIter = std::find(std::begin(surfs_), std::end(surfs_), selfSurf); + MSG_ASSERT(selfIter != std::end(surfs_), "couldn't find surface"); + + // determine direction and index to split surface + string candDir = ""; + auto candInd = 0; + if (orientation == 1) { // same orientation + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; // candInd doesn't matter for dir 3 b/c block cannot + // be split, only partner block updated + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 2) { // D1/D2 swapped - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 2) { // D1/D2 swapped + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 3) { // D1 reversed - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = surf.Max1() - ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 3) { // D1 reversed + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = partSurf.Max1() - ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 4) { // D1/D2 swapped, D1 reversed - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = surf.Max1() - ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 4) { // D1/D2 swapped, D1 reversed + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = partSurf.Max1() - ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 5) { // D1/D2 swapped, D2 reversed - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = surf.Max2() - ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 5) { // D1/D2 swapped, D2 reversed + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = partSurf.Max2() - ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 6) { // D2 reversed - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = surf.Max2() - ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 6) { // D2 reversed + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = partSurf.Max2() - ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else if (match.Orientation() == 7) { // D1/D2 swapped and reversed - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = surf.Max1() - ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = surf.Max2() - ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } + } else if (orientation == 7) { // D1/D2 swapped and reversed + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = partSurf.Max1() - ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = partSurf.Max2() - ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } - } else { // D1/D2 reversed (orientation 8) - if (surf.Direction1() == dir) { - // split was in direction 1 of partner, needs to be direction 1 - // of candidate - candDir = lowSurf.Direction1(); - candInd = surf.Max1() - ind - surf.Min1() + lowSurf.Min1(); - } else if (surf.Direction2() == dir) { - // split was in direction 2 of partner, needs to be direction 2 - // of candidate - candDir = lowSurf.Direction2(); - candInd = surf.Max2() - ind - surf.Min2() + lowSurf.Min2(); - } else if (surf.Direction3() == dir) { - // split was in direction 3 of partner, needs to be direction 3 - // of candidate - candDir = lowSurf.Direction3(); - candInd = ind; - } else { - cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " - "Direction " - << dir << " is not recognized." << endl; - cerr << "Please choose i, j, or k." << endl; - exit(EXIT_FAILURE); - } - } + } else { // D1/D2 reversed (orientation 8) + if (partSurf.Direction1() == dir) { + // split was in direction 1 of partner, needs to be direction 1 + // of candidate + candDir = selfSurf.Direction1(); + candInd = partSurf.Max1() - ind - partSurf.Min1() + selfSurf.Min1(); + } else if (partSurf.Direction2() == dir) { + // split was in direction 2 of partner, needs to be direction 2 + // of candidate + candDir = selfSurf.Direction2(); + candInd = partSurf.Max2() - ind - partSurf.Min2() + selfSurf.Min2(); + } else if (partSurf.Direction3() == dir) { + // split was in direction 3 of partner, needs to be direction 3 + // of candidate + candDir = selfSurf.Direction3(); + candInd = ind; + } else { + cerr << "ERROR: Error in boundaryConditions::DependentSplit(). " + "Direction " + << dir << " is not recognized." << endl; + cerr << "Please choose i, j, or k." << endl; + exit(EXIT_FAILURE); + } + } - // split matched surface - auto split = false, low = false; - const auto upSurf = lowSurf.DependentSplit( - candDir, candInd, sblk, lblk, ublk, split, low, match.Orientation()); + // split matched surface + auto split = false, low = false; + // use the upper block if the split was parallel to the partner surface, + // and the partner surface was an 'upper' surface + auto useUpperBlock = + (dir == partSurf.Direction3() && partSurf.IsUpper()) ? true : false; - // assign boundarySurface back into boundaryConditions, if surface - // wasn't split partner block was updated - if (!split && !low) { - surfs_[ii] = upSurf; - } else { - surfs_[ii] = lowSurf; - } + const auto upSurf = selfSurf.DependentSplit(candDir, candInd, sblk, + (useUpperBlock ? ublk : lblk), + ublk, split, low, orientation); - // if surface was split, insert it into the vector of boundarySurfaces - // and adjust the surface numbers - if (split) { - // boundary surface was split, insert new surface into bcs - surfs_.insert(surfs_.begin() + ii, upSurf); - if (upSurf.SurfaceType() <= 2) { // i-surface - numSurfI_++; - } else if (upSurf.SurfaceType() <= 4) { // j-surface - numSurfJ_++; - } else { - numSurfK_++; - } - } + // assign boundarySurface back into boundaryConditions, if surface + // wasn't split partner block was updated + *selfIter = (!split && !low) ? upSurf : selfSurf; - break; + // if surface was split, insert it into the vector of boundarySurfaces + // and adjust the surface numbers + if (split) { + // boundary surface was split, insert new surface into bcs + surfs_.insert(selfIter, upSurf); + if (upSurf.SurfaceType() <= 2) { // i-surface + numSurfI_++; + } else if (upSurf.SurfaceType() <= 4) { // j-surface + numSurfJ_++; + } else { + numSurfK_++; } } } @@ -2548,9 +2690,11 @@ void boundarySurface::Join(const boundarySurface &upper, const string &dir, // member function to split a boundarySurface. The calling instance retains // the lower portion of the split, and the returned instance retains the upper // portion. This is used to split connections -boundarySurface boundarySurface::DependentSplit( - const string &dir, const int &ind, const int &sBlk, int lBlk, - int uBlk, bool &split, bool &low, const int &orientation) { +boundarySurface boundarySurface::DependentSplit(const string &dir, + const int &ind, const int &sBlk, + int lBlk, int uBlk, bool &split, + bool &low, + const int &orientation) { // dir -- direction to split the surface in // ind -- index at which to split the surface // sBlk -- block number that *this surface belongs to @@ -2579,17 +2723,17 @@ boundarySurface boundarySurface::DependentSplit( uBlk = lBlk; } } else if (low) { - // if c-grid split & boundary on lower side, partner block should be upper + // boundary on lower side, partner block should be upper if (sBlk == lBlk) { lBlk = uBlk; } } else { - // if c-grid split & boundary on upper side, partner block should be lower + // boundary on upper side, partner block should be lower if (sBlk == uBlk) { uBlk = lBlk; } } - } else if (isReversed) { + } else if (isReversed && split) { std::swap(lBlk, uBlk); } diff --git a/src/conserved.cpp b/src/conserved.cpp new file mode 100644 index 0000000..a80a975 --- /dev/null +++ b/src/conserved.cpp @@ -0,0 +1,41 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include // cout +#include "conserved.hpp" +#include "arrayView.hpp" + +using std::cout; +using std::endl; +using std::cerr; + +// ------------------------------------------------------------------ +// functions for conserved class + +arrayView conserved::GetView() const { + return {this->begin(), this->end(), this->NumSpecies()}; +} + + +// operation overload for << - allows use of cout, cerr, etc. +ostream &operator<<(ostream &os, const conserved &m) { + for (auto rr = 0; rr < m.Size(); rr++) { + os << m[rr] << endl; + } + return os; +} + + diff --git a/src/eos.cpp b/src/eos.cpp index 7173399..a41f012 100644 --- a/src/eos.cpp +++ b/src/eos.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,52 +17,100 @@ #include // cout #include // exit() #include "eos.hpp" +#include "macros.hpp" +#include "fluid.hpp" using std::cout; using std::endl; using std::cerr; +// constructor +idealGas::idealGas(const vector &fl, const double &tRef, + const double &aRef) { + const auto numSpecies = fl.size(); + gasConst_.reserve(numSpecies); + for (auto &f : fl) { + // nondimensionalize gas constant + gasConst_.push_back(f.GasConstant() * tRef / (aRef * aRef)); + } +} + // Member functions for idealGas class // These functions calculate values using the ideal gas equation of state // P = rho * R * T double idealGas::PressFromEnergy(const unique_ptr &thermo, - const double &rho, const double &energy, + const vector &rho, + const double &energy, const double &vel) const { - const auto specEnergy = energy - 0.5 * vel *vel; - const auto temperature = thermo->TemperatureFromSpecEnergy(specEnergy); + const auto specEnergy = energy - 0.5 * vel * vel; + const auto rhoSum = std::accumulate(rho.begin(), rho.end(), 0.0); + vector mf(rho.size()); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = rho[ii] / rhoSum; + } + const auto temperature = thermo->TemperatureFromSpecEnergy(specEnergy, mf); return this->PressureRT(rho, temperature); } -double idealGas::PressureRT(const double &rho, +double idealGas::PressureRT(const vector &rho, const double &temperature) const { - return temperature * rho / gammaRef_; + MSG_ASSERT(this->NumSpecies() == static_cast(rho.size()), + "species size mismatch"); + auto p = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + p += rho[ss] * gasConst_[ss] * temperature; + } + return p; } double idealGas::SpecEnergy(const unique_ptr &thermo, - const double &t) const { - return thermo->SpecEnergy(t); + const double &t, const vector &mf) const { + return thermo->SpecEnergy(t, mf); } double idealGas::Energy(const double &specEn, const double &vel) const { return specEn + 0.5 * vel * vel; } +double idealGas::SpeciesEnthalpy(const unique_ptr &thermo, + const double &t, const double &vel, + const int &ss) const { + return thermo->SpeciesSpecEnthalpy(t, ss) + 0.5 * vel * vel; +} + double idealGas::Enthalpy(const unique_ptr &thermo, - const double &t, const double &vel) const { - return thermo->SpecEnthalpy(t) + 0.5 * vel * vel; + const double &t, const double &vel, + const vector &mf) const { + return thermo->SpecEnthalpy(t, mf) + 0.5 * vel * vel; } -double idealGas::SoS(const double &pressure, const double &rho) const { - return sqrt(gammaRef_ * pressure / rho); +double idealGas::SoS(const unique_ptr &thermo, + const double &pressure, const vector &rho) const { + MSG_ASSERT(this->NumSpecies() == static_cast(rho.size()), + "species size mismatch"); + const auto rhoSum = std::accumulate(rho.begin(), rho.end(), 0.0); + vector mf(rho.size()); + for (auto ii = 0U; ii < mf.size(); ++ii) { + mf[ii] = rho[ii] / rhoSum; + } + const auto t = this->Temperature(pressure, rho); + const auto gamma = thermo->Gamma(t, mf); + return sqrt(gamma * pressure / rhoSum); } double idealGas::Temperature(const double &pressure, - const double &rho) const { - return pressure * gammaRef_ / rho; + const vector &rho) const { + MSG_ASSERT(this->NumSpecies() == static_cast(rho.size()), + "species size mismatch"); + auto rhoR = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + rhoR += rho[ss] * gasConst_[ss]; + } + return pressure / rhoR; } -double idealGas::PressureDim(const double &rho, - const double &temperature) const { - return rho * gasConst_ * temperature; +double idealGas::DensityTP(const double &temp, const double &press, + const vector &mf) const { + auto R = this->MixtureGasConstant(mf); + return press / (R * temp); } - diff --git a/src/fluid.cpp b/src/fluid.cpp index fc102ac..5b79acb 100644 --- a/src/fluid.cpp +++ b/src/fluid.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,8 +17,10 @@ #include // cout #include #include +#include #include "fluid.hpp" #include "inputStates.hpp" +#include "utility.hpp" using std::cout; using std::endl; @@ -44,10 +46,8 @@ fluid::fluid(string &str, const string name) { str.erase(0, end); // parameter counters - auto nCount = 0; - auto massCount = 0; - auto vibCount = 0; auto nameCount = 0; + auto mfCount = 0; for (auto &token : tokens) { auto param = Tokenize(token, "="); @@ -56,15 +56,9 @@ fluid::fluid(string &str, const string name) { exit(EXIT_FAILURE); } - if (param[0] == "n") { - n_ = stod(RemoveTrailing(param[1], ",")); - nCount++; - } else if (param[0] == "molarMass") { - molarMass_ = stod(RemoveTrailing(param[1], ",")); - massCount++; - } else if (param[0] == "vibrationalTemperature") { - vibTemp_ = stod(RemoveTrailing(param[1], ",")); - vibCount++; + if (param[0] == "referenceMassFraction") { + massFracRef_ = stod(RemoveTrailing(param[1], ",")); + mfCount++; } else if (param[0] == "name") { name_ = RemoveTrailing(param[1], ","); nameCount++; @@ -76,26 +70,78 @@ fluid::fluid(string &str, const string name) { } // sanity checks - // optional variables - if (nCount > 1 || nameCount > 1 || vibCount > 1 || massCount > 1) { - cerr << "ERROR. For " << name << ", name, n, vibrationalTemperature, and " - << "molarMass can only be specified once." << endl; + // required variables + if (nameCount != 1 || mfCount != 1) { + cerr << "ERROR. For fluid 'name' and 'referenceMassFraction' must be " + "specified" + << endl; exit(EXIT_FAILURE); } - if (name != "fluid") { cerr << "ERROR. To specify fluid, properties must be enclosed in fluid()." << endl; } + + // get data from fluid database + this->GetDatabaseProperties(name_); } void fluid::Nondimensionalize(const double &tRef) { if (!this->IsNondimensional()) { - vibTemp_ /= tRef; + std::for_each(vibTemp_.begin(), vibTemp_.end(), + [&tRef](auto &val) { val /= tRef; }); this->SetNondimensional(true); } } +void fluid::GetDatabaseProperties(const string &name) { + auto fname = name + ".dat"; + // open database file -- first try run directory, then fluid database + ifstream datFile(fname, std::ios::in); + if (datFile.fail()) { + auto databaseFile = + GetEnvironmentVariable("AITHER_FLUID_DATABASE") + "/" + fname; + datFile.open(databaseFile, std::ios::in); + if (datFile.fail()) { + cerr << "ERROR: Error in fluid::GetDatabaseProperties(). File " << fname + << " did not open correctly!!!" << endl; + exit(EXIT_FAILURE); + } + } + + string line = ""; + while (getline(datFile, line)) { + // remove leading and trailing whitespace and ignore comments + line = Trim(line); + + if (line.length() > 0) { // only proceed if line has data + // split line at variable separator + auto tokens = Tokenize(line, ":", 2); + // search to see if first token corresponds to any keywords + auto key = tokens[0]; + + if (key == "n") { + n_ = std::stod(tokens[1]); + } else if (key == "molarMass") { + molarMass_ = std::stod(tokens[1]) / 1000.; // convert to kg/mol + } else if (key == "vibrationalTemperature") { + vibTemp_ = ReadVectorXd(tokens[1]); + } else if (key == "sutherlandViscosityC1") { + transportViscosity_[0] = std::stod(tokens[1]); + } else if (key == "sutherlandViscosityS") { + transportViscosity_[1] = std::stod(tokens[1]); + } else if (key == "sutherlandConductivityC1") { + transportConductivity_[0] = std::stod(tokens[1]); + } else if (key == "sutherlandConductivityS") { + transportConductivity_[1] = std::stod(tokens[1]); + } + } + } + + // close database file + datFile.close(); +} + // function to read initial condition state from string vector ReadFluidList(ifstream &inFile, string &str) { vector fluidList; @@ -145,8 +191,8 @@ vector ReadFluidList(ifstream &inFile, string &str) { } ostream &operator<<(ostream &os, const fluid &fl) { - os << "fluid(name=" << fl.Name() << "; n=" << fl.N() - << "; molarMass=" << fl.MolarMass() - << "; vibrationalTemperature=" << fl.VibrationalTemperature() << ")"; + auto vt = fl.VibrationalTemperature(); + os << "fluid(name=" << fl.Name() + << "; referenceMassFraction=" << fl.MassFractionRef() << ")"; return os; } \ No newline at end of file diff --git a/src/fluxJacobian.cpp b/src/fluxJacobian.cpp index 0142ab5..dbaa82b 100644 --- a/src/fluxJacobian.cpp +++ b/src/fluxJacobian.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,454 +16,164 @@ #include // cout #include // sqrt -#include #include #include // max #include "fluxJacobian.hpp" #include "turbulence.hpp" // turbModel #include "input.hpp" // input -#include "primVars.hpp" // primVars -#include "genArray.hpp" // genArray +#include "primitive.hpp" // primitive #include "inviscidFlux.hpp" // ConvectiveFluxUpdate #include "utility.hpp" // TauNormal #include "transport.hpp" // transport model #include "eos.hpp" // equation of state #include "thermodynamic.hpp" // thermodynamic model +#include "conserved.hpp" // conserved +#include "spectralRadius.hpp" +#include "matrix.hpp" +#include "physicsModels.hpp" using std::cout; using std::endl; using std::cerr; using std::vector; using std::string; -using std::unique_ptr; -// constructor -// if constructed with two doubles, create scalar squareMatrix -fluxJacobian::fluxJacobian(const double &flow, const double &turb) { - flowJacobian_ = squareMatrix(1); - flowJacobian_ += flow; - - turbJacobian_ = squareMatrix(1); - turbJacobian_ += turb; +// member functions +void fluxJacobian::AddToFlowJacobian(const squareMatrix &jac) { + MSG_ASSERT(flowSize_ == jac.Size(), "matrix sizes don't match"); + std::transform(this->begin(), this->beginTurb(), jac.begin(), this->begin(), + std::plus()); } - -// if constructed with two intss, create scalar squareMatrix with given size -fluxJacobian::fluxJacobian(const int &flowSize, const int &turbSize) { - flowJacobian_ = squareMatrix(flowSize); - turbJacobian_ = squareMatrix(turbSize); +void fluxJacobian::SubtractFromFlowJacobian(const squareMatrix &jac) { + MSG_ASSERT(flowSize_ == jac.Size(), "matrix sizes don't match"); + std::transform(this->begin(), this->beginTurb(), jac.begin(), this->begin(), + std::minus()); } - -// member functions -// member function to multiply the flux jacobians with a genArray -genArray fluxJacobian::ArrayMult(genArray arr) const { - if (this->IsScalar()) { - arr[0] *= flowJacobian_(0, 0); - arr[1] *= flowJacobian_(0, 0); - arr[2] *= flowJacobian_(0, 0); - arr[3] *= flowJacobian_(0, 0); - arr[4] *= flowJacobian_(0, 0); - - arr[5] *= turbJacobian_(0, 0); - arr[6] *= turbJacobian_(0, 0); - } else { - arr = flowJacobian_.ArrayMult(arr); - arr = turbJacobian_.ArrayMult(arr, flowJacobian_.Size()); - } - return arr; +void fluxJacobian::AddToTurbJacobian(const squareMatrix &jac) { + MSG_ASSERT(turbSize_ == jac.Size(), "matrix sizes don't match"); + std::transform(this->beginTurb(), this->end(), jac.begin(), this->beginTurb(), + std::plus()); } - -bool fluxJacobian::IsScalar() const { - return (flowJacobian_.Size() > 1) ? false : true; +void fluxJacobian::SubtractFromTurbJacobian(const squareMatrix &jac) { + MSG_ASSERT(turbSize_ == jac.Size(), "matrix sizes don't match"); + std::transform(this->beginTurb(), this->end(), jac.begin(), this->beginTurb(), + std::minus()); } -// function to take the inverse of a flux jacobian -void fluxJacobian::Inverse(const bool &isRANS) { - flowJacobian_.Inverse(); - - if (isRANS) { - turbJacobian_.Inverse(); - } +void fluxJacobian::MultFlowJacobian(const double &fac) { + std::for_each(this->begin(), this->beginTurb(), + [&fac](auto &val) { val *= fac; }); } - -/* Function to calculate Rusanov flux jacobian. The Rusanov flux is defined as -shown below. - - F = 0.5 * (F(Ul) + F(Ur) - L(Ul, Ur) * (Ur - Ul) - -Differentiating by the left and right states gives the left and right flux -jacobians. - - dF_Ul = 0.5 * (A(Ul) + L(Ul, Ur)) - dF_Ur = 0.5 * (A(Ur) - L(Ul, Ur)) - -In the above equations the dissipation term L is held constant during -differentiation. A represents the convective flux jacobian matrix. - */ -void fluxJacobian::RusanovFluxJacobian(const primVars &state, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unitVec3dMag &area, - const bool &positive, const input &inp, - const unique_ptr &turb) { - // state -- primative variables at face - // eqnState -- equation of state - // thermo -- thermodynamic model - // area -- face area vector - // positive -- flag to determine whether to add or subtract dissipation - // inp -- input variables - // turb -- turbulence model - - // face inviscid spectral radius - const auto specRad = state.InvFaceSpectralRadius(area, thermo, eqnState); - - // form dissipation matrix based on spectral radius - fluxJacobian dissipation(inp.NumFlowEquations(), inp.NumTurbEquations()); - dissipation.flowJacobian_.Identity(); - dissipation.flowJacobian_ *= specRad; - - // begin jacobian calculation - this->InvFluxJacobian(state, eqnState, thermo, area, inp, turb); - - // compute turbulent dissipation if necessary - if (inp.IsRANS()) { - // multiply by 0.5 b/c averaging with convection matrix - dissipation.turbJacobian_ = 0.5 * turb->InviscidDissJacobian(state, area); - } - - positive ? (*this) += dissipation : (*this) -= dissipation; +void fluxJacobian::MultTurbJacobian(const double &fac) { + std::for_each(this->beginTurb(), this->end(), + [&fac](auto &val) { val *= fac; }); } -// function to calculate inviscid flux jacobian -void fluxJacobian::InvFluxJacobian(const primVars &state, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unitVec3dMag &area, - const input &inp, - const unique_ptr &turb) { - // state -- primative variables at face - // eqnState -- ideal gas equation of state - // thermo -- thermodynamic model - // area -- face area vector - // inp -- input variables - // turb -- turbulence model - - const auto t = state.Temperature(eqnState); - const auto velNorm = state.Velocity().DotProd(area.UnitVector()); - const auto gammaMinusOne = thermo->Gamma(t) - 1.0; - const auto phi = 0.5 * gammaMinusOne * state.Velocity().MagSq(); - const auto a1 = thermo->Gamma(t) * state.Energy(eqnState, thermo) - phi; - const auto a3 = thermo->Gamma(t) - 2.0; - - // begin jacobian calculation - flowJacobian_ = squareMatrix(inp.NumFlowEquations()); - turbJacobian_ = squareMatrix(inp.NumTurbEquations()); - - // calculate flux derivatives wrt left state - // column zero - flowJacobian_(0, 0) = 0.0; - flowJacobian_(1, 0) = phi * area.UnitVector().X() - state.U() * velNorm; - flowJacobian_(2, 0) = phi * area.UnitVector().Y() - state.V() * velNorm; - flowJacobian_(3, 0) = phi * area.UnitVector().Z() - state.W() * velNorm; - flowJacobian_(4, 0) = velNorm * (phi - a1); - - // column one - flowJacobian_(0, 1) = area.UnitVector().X(); - flowJacobian_(1, 1) = velNorm - a3 * area.UnitVector().X() * state.U(); - flowJacobian_(2, 1) = state.V() * area.UnitVector().X() - - gammaMinusOne * state.U() * area.UnitVector().Y(); - flowJacobian_(3, 1) = state.W() * area.UnitVector().X() - - gammaMinusOne * state.U() * area.UnitVector().Z(); - flowJacobian_(4, 1) = a1 * area.UnitVector().X() - gammaMinusOne * state.U() - * velNorm; - - // column two - flowJacobian_(0, 2) = area.UnitVector().Y(); - flowJacobian_(1, 2) = state.U() * area.UnitVector().Y() - - gammaMinusOne * state.V() * area.UnitVector().X(); - flowJacobian_(2, 2) = velNorm - a3 * area.UnitVector().Y() * state.V(); - flowJacobian_(3, 2) = state.W() * area.UnitVector().Y() - - gammaMinusOne * state.V() * area.UnitVector().Z(); - flowJacobian_(4, 2) = a1 * area.UnitVector().Y() - gammaMinusOne * state.V() - * velNorm; - - // column three - flowJacobian_(0, 3) = area.UnitVector().Z(); - flowJacobian_(1, 3) = state.U() * area.UnitVector().Z() - - gammaMinusOne * state.W() * area.UnitVector().X(); - flowJacobian_(2, 3) = state.V() * area.UnitVector().Z() - - gammaMinusOne * state.W() * area.UnitVector().Y(); - flowJacobian_(3, 3) = velNorm - a3 * area.UnitVector().Z() * state.W(); - flowJacobian_(4, 3) = a1 * area.UnitVector().Z() - gammaMinusOne * state.W() - * velNorm; - - // column four - flowJacobian_(0, 4) = 0.0; - flowJacobian_(1, 4) = gammaMinusOne * area.UnitVector().X(); - flowJacobian_(2, 4) = gammaMinusOne * area.UnitVector().Y(); - flowJacobian_(3, 4) = gammaMinusOne * area.UnitVector().Z(); - flowJacobian_(4, 4) = thermo->Gamma(t) * velNorm; - - // multiply by 0.5 b/c averaging with dissipation matrix - flowJacobian_ *= 0.5 * area.Mag(); - - // turbulent jacobian here - if (inp.IsRANS()) { - // multiply by 0.5 b/c averaging with dissipation matrix - turbJacobian_ = 0.5 * turb->InviscidConvJacobian(state, area); - } +fluxJacobian fluxJacobian::FlowMatMult(const fluxJacobian &jac2) const { + MSG_ASSERT(this->FlowSize() == jac2.FlowSize(), + "Mismatch in flux jacobian size"); + fluxJacobian result(this->FlowSize(), this->TurbSize()); + MatrixMultiply(this->begin(), jac2.begin(), result.begin(), this->FlowSize()); + return result; } -/* Function to calculate approximate Roe flux jacobian. The Roe flux is -defined as shown below. - - F = 0.5 * (F(Ul) + F(Ur) - Aroe(Ul, Ur) * (Ur - Ul) - -Differentiating by the left and right states gives the left and right flux -jacobians. - - dF_Ul = 0.5 * (A(Ul) + Aroe(Ul, Ur)) - dF_Ur = 0.5 * (A(Ur) - Aroe(Ul, Ur)) - -In the above equations the Roe matrix Aroe is held constant during -differentiation. A represents the convective flux jacobian matrix. - */ -void fluxJacobian::ApproxRoeFluxJacobian( - const primVars &left, const primVars &right, - const unique_ptr &eqnState, const unique_ptr &thermo, - const unitVec3dMag &area, const bool &positive, const input &inp, - const unique_ptr &turb) { - // left -- primative variables from left side - // right -- primative variables from right side - // eqnState -- equation of state - // thermo -- thermodynamic model - // area -- face area vector - // positive -- flag to determine whether to add or subtract dissipation - // inp -- input variables - // turb -- turbulence model - - // compute Roe averaged state - const auto roeAvg = RoeAveragedState(left, right); - - // compute Roe matrix - fluxJacobian roeMatrix; - roeMatrix.InvFluxJacobian(roeAvg, eqnState, thermo, area, inp, turb); - - // compute convective flux jacobian - positive ? this->InvFluxJacobian(left, eqnState, thermo, area, inp, turb) : - this->InvFluxJacobian(right, eqnState, thermo, area, inp, turb); - - positive ? (*this) += roeMatrix : (*this) -= roeMatrix; +fluxJacobian fluxJacobian::TurbMatMult(const fluxJacobian &jac2) const { + MSG_ASSERT(this->TurbSize() == jac2.TurbSize(), + "Mismatch in flux jacobian size"); + fluxJacobian result(this->FlowSize(), this->TurbSize()); + MatrixMultiply(this->beginTurb(), jac2.beginTurb(), result.beginTurb(), + this->TurbSize()); + return result; } -// change of variable matrix going from primative to conservative variables -// from Dwight -void fluxJacobian::DelPrimativeDelConservative( - const primVars &state, const unique_ptr &thermo, - const unique_ptr &eqnState, const input &inp) { - // state -- primative variables - // thermo -- thermodynamic model - // inp -- input variables - - const auto t = state.Temperature(eqnState); - const auto gammaMinusOne = thermo->Gamma(t) - 1.0; - const auto invRho = 1.0 / state.Rho(); - - flowJacobian_ = squareMatrix(inp.NumFlowEquations()); - turbJacobian_ = squareMatrix(inp.NumTurbEquations()); - - // assign column 0 - flowJacobian_(0, 0) = 1.0; - flowJacobian_(1, 0) = -invRho * state.U(); - flowJacobian_(2, 0) = -invRho * state.V(); - flowJacobian_(3, 0) = -invRho * state.W(); - flowJacobian_(4, 0) = 0.5 * gammaMinusOne * - state.Velocity().DotProd(state.Velocity()); - - // assign column 1 - flowJacobian_(1, 1) = invRho; - flowJacobian_(4, 1) = -gammaMinusOne * state.U(); - - // assign column 2 - flowJacobian_(2, 2) = invRho; - flowJacobian_(4, 2) = -gammaMinusOne * state.V(); - // assign column 3 - flowJacobian_(3, 3) = invRho; - flowJacobian_(4, 3) = -gammaMinusOne * state.W(); - // assign column 4 - flowJacobian_(4, 4) = gammaMinusOne; - - // turbulent jacobian here - if (inp.IsRANS()) { - turbJacobian_(0, 0) = invRho; - turbJacobian_(1, 1) = invRho; +// non-member functions +// ---------------------------------------------------------------------------- +ostream &operator<<(ostream &os, const fluxJacobian &jacobian) { + // print flow jacobian + for (auto rr = 0; rr < jacobian.FlowSize(); ++rr) { + for (auto cc = 0; cc < jacobian.FlowSize(); ++cc) { + os << jacobian.FlowJacobian(rr, cc); + if (cc != (jacobian.FlowSize() - 1)) { + os << ", "; + } else { + os << endl; + } + } } -} - -// approximate thin shear layer jacobian following implementation in Dwight. -// does not use any gradients -void fluxJacobian::ApproxTSLJacobian(const primVars &state, - const double &lamVisc, - const double &turbVisc, const double &f1, - const unique_ptr &eqnState, - const unique_ptr &trans, - const unique_ptr &thermo, - const unitVec3dMag &area, - const double &dist, - const unique_ptr &turb, - const input &inp, const bool &left, - const tensor &vGrad) { - // state -- primative variables - // eos -- equation of state - // trans -- viscous transport model - // area -- face area vector - // dist -- distance from cell center to cell center - // turb -- turbulence model - // inp -- input variables - // left -- flag that is negative if using left state - // vGrad -- velocity gradient - flowJacobian_ = squareMatrix(inp.NumFlowEquations()); - turbJacobian_ = squareMatrix(inp.NumTurbEquations()); - - const auto t = state.Temperature(eqnState); - const auto mu = trans->NondimScaling() * lamVisc; - const auto mut = trans->NondimScaling() * turbVisc; - const auto velNorm = state.Velocity().DotProd(area.UnitVector()); - - const auto tauNorm = TauNormal(vGrad, area.UnitVector(), mu, mut, trans); - - auto fac = left ? -1.0 : 1.0; - - constexpr auto third = 1.0 / 3.0; - - // assign column 0 - flowJacobian_(4, 0) = - -(trans->Conductivity(mu, t, thermo) + - trans->TurbConductivity(mut, turb->TurbPrandtlNumber(), t, thermo)) * - state.Temperature(eqnState) / ((mu + mut) * state.Rho()); - - // assign column 1 - flowJacobian_(1, 1) = third * area.UnitVector().X() * area.UnitVector().X() - + 1.0; - flowJacobian_(2, 1) = third * area.UnitVector().X() * area.UnitVector().Y(); - flowJacobian_(3, 1) = third * area.UnitVector().X() * area.UnitVector().Z(); - flowJacobian_(4, 1) = fac * 0.5 * dist / (mu + mut) * tauNorm.X() + - third * area.UnitVector().X() * velNorm + state.U(); - - // assign column 2 - flowJacobian_(1, 2) = third * area.UnitVector().Y() * area.UnitVector().X(); - flowJacobian_(2, 2) = third * area.UnitVector().Y() * area.UnitVector().Y() - + 1.0; - flowJacobian_(3, 2) = third * area.UnitVector().Y() * area.UnitVector().Z(); - flowJacobian_(4, 2) = fac * 0.5 * dist / (mu + mut) * tauNorm.Y() + - third * area.UnitVector().Y() * velNorm + state.V(); - - // assign column 3 - flowJacobian_(1, 3) = third * area.UnitVector().Z() * area.UnitVector().X(); - flowJacobian_(2, 3) = third * area.UnitVector().Z() * area.UnitVector().Y(); - flowJacobian_(3, 3) = third * area.UnitVector().Z() * area.UnitVector().Z() - + 1.0; - flowJacobian_(4, 3) = fac * 0.5 * dist / (mu + mut) * tauNorm.Z() + - third * area.UnitVector().Z() * velNorm + state.W(); - - // assign column 4 - flowJacobian_(4, 4) = - (trans->Conductivity(mu, t, thermo) + - trans->TurbConductivity(mut, turb->TurbPrandtlNumber(), t, thermo)) / - ((mu + mut) * state.Rho()); - - flowJacobian_ *= area.Mag() * (mu + mut) / dist; - - fluxJacobian prim2Cons; - prim2Cons.DelPrimativeDelConservative(state, thermo, eqnState, inp); - flowJacobian_ = flowJacobian_.MatMult(prim2Cons.flowJacobian_); - - // calculate turbulent jacobian if necessary - if (inp.IsRANS()) { - turbJacobian_ = fac * turb->ViscousJacobian(state, area, lamVisc, trans, - dist, turbVisc, f1); - // Don't need to multiply by prim2Cons b/c jacobian is already wrt - // conservative variables + // print turbulence jacobian + for (auto rr = 0; rr < jacobian.TurbSize(); ++rr) { + for (auto cc = 0; cc < jacobian.TurbSize(); ++cc) { + os << jacobian.TurbJacobian(rr, cc); + if (cc != (jacobian.TurbSize() - 1)) { + os << ", "; + } else { + os << endl; + } + } } -} - -// non-member functions -// ---------------------------------------------------------------------------- -ostream &operator<<(ostream &os, const fluxJacobian &jacobian) { - os << jacobian.FlowJacobian() << endl; - os << jacobian.TurbulenceJacobian() << endl; return os; } -genArray RusanovScalarOffDiagonal(const primVars &state, const genArray &update, +varArray RusanovScalarOffDiagonal(const primitiveView &state, + const varArrayView &update, const unitVec3dMag &fArea, const double &mu, const double &mut, const double &f1, const double &dist, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const bool &isViscous, const bool &positive) { - // state -- primative variables at off diagonal + const physics &phys, const bool &isViscous, + const bool &positive) { + // state -- primitive variables at off diagonal // update -- conserved variable update at off diagonal // fArea -- face area vector on off diagonal boundary // mu -- laminar viscosity // mut -- turbulent viscosity // f1 -- first blending coefficient // dist -- distance from cell center to cell center across face on diagonal - // eos -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // isViscous -- flag to determine if simulation is viscous // positive -- flag to determine whether to add or subtract dissipation // calculate updated state const auto stateUpdate = - state.UpdateWithConsVars(eqnState, thermo, update, turb); + state.UpdateWithConsVars(phys, update); // calculate updated convective flux auto fluxChange = - 0.5 * fArea.Mag() * ConvectiveFluxUpdate(state, stateUpdate, eqnState, - thermo, fArea.UnitVector()); + 0.5 * fArea.Mag() * + ConvectiveFluxUpdate(state, stateUpdate, phys, fArea.UnitVector()); // zero out turbulence quantities b/c spectral radius is like full jacobian - fluxChange[5] = 0.0; - fluxChange[6] = 0.0; + for (auto ii = 0; ii < fluxChange.NumTurbulence(); ++ii) { + fluxChange[fluxChange.TurbulenceIndex() + ii] = 0.0; + } // can't use stored cell spectral radius b/c it has contributions from i, j, k const uncoupledScalar specRad( - state.FaceSpectralRadius(fArea, thermo, eqnState, trans, dist, mu, mut, - turb, isViscous), - turb->FaceSpectralRadius(state, fArea, mu, trans, dist, mut, f1, - positive)); + FaceSpectralRadius(state, fArea, phys, dist, mu, mut, isViscous), + phys.Turbulence()->FaceSpectralRadius(state, fArea, mu, phys.Transport(), + dist, mut, f1, positive)); return positive ? fluxChange + specRad.ArrayMult(update) : fluxChange - specRad.ArrayMult(update); } -genArray RusanovBlockOffDiagonal( - const primVars &state, const genArray &update, +varArray RusanovBlockOffDiagonal( + const primitiveView &state, const varArrayView &update, const unitVec3dMag &fArea, const double &mu, const double &mut, - const double &f1, const double &dist, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb, const input &inp, const bool &positive, - const tensor &vGrad) { - // state -- primative variables at off diagonal + const double &f1, const double &dist, const physics &phys, const input &inp, + const bool &positive, const tensor &vGrad) { + // state -- primitive variables at off diagonal // update -- conserved variable update at off diagonal // fArea -- face area vector on off diagonal boundary // mu -- laminar viscosity // mut -- turbulent viscosity // f1 -- first blending coefficient // dist -- distance from cell center to cell center across face on diagonal - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // inp -- input variables // positive -- flag to determine whether to add or subtract dissipation // vGrad -- velocity gradient @@ -471,30 +181,26 @@ genArray RusanovBlockOffDiagonal( fluxJacobian jacobian(inp.NumFlowEquations(), inp.NumTurbEquations()); // calculate inviscid jacobian - jacobian.RusanovFluxJacobian(state, eqnState, thermo, fArea, positive, inp, - turb); + jacobian.RusanovFluxJacobian(state, phys, fArea, positive, inp); // add viscous contribution if (inp.IsViscous()) { fluxJacobian viscJac(inp.NumFlowEquations(), inp.NumTurbEquations()); - viscJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, thermo, - fArea, dist, turb, inp, positive, vGrad); + viscJac.ApproxTSLJacobian(state, mu, mut, f1, phys, fArea, dist, inp, + positive, vGrad); positive ? jacobian -= viscJac : jacobian += viscJac; } return jacobian.ArrayMult(update); } -genArray OffDiagonal(const primVars &offDiag, const primVars &diag, - const genArray &update, const unitVec3dMag &fArea, - const double &mu, const double &mut, const double &f1, - const double &dist, const tensor &vGrad, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, const input &inp, - const bool &positive) { - // offDiag -- primative variables at off diagonal - // diag -- primative variables at diagonal +varArray OffDiagonal(const primitiveView &offDiag, const primitiveView &diag, + const varArrayView &update, + const unitVec3dMag &fArea, const double &mu, + const double &mut, const double &f1, const double &dist, + const tensor &vGrad, const physics &phys, + const input &inp, const bool &positive) { + // offDiag -- primitive variables at off diagonal + // diag -- primitive variables at diagonal // update -- conserved variable update at off diagonal // fArea -- face area vector on off diagonal boundary // mu -- laminar viscosity @@ -502,31 +208,26 @@ genArray OffDiagonal(const primVars &offDiag, const primVars &diag, // f1 -- first blending coefficient // dist -- distance from cell center to cell center across face on diagonal // vGrad -- velocity gradient - // eos -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // input -- input variables // positive -- flag to determine whether to add or subtract dissipation - genArray offDiagonal(0.0); + varArray offDiagonal; if (inp.InvFluxJac() == "rusanov") { if (inp.IsBlockMatrix()) { offDiagonal = RusanovBlockOffDiagonal(offDiag, update, fArea, mu, mut, f1, - dist, eqnState, thermo, trans, turb, - inp, positive, vGrad); + dist, phys, inp, positive, vGrad); } else { - offDiagonal = RusanovScalarOffDiagonal(offDiag, update, fArea, mu, mut, - f1, dist, eqnState, thermo, trans, - turb, inp.IsViscous(), positive); + offDiagonal = + RusanovScalarOffDiagonal(offDiag, update, fArea, mu, mut, f1, dist, + phys, inp.IsViscous(), positive); } } else if (inp.InvFluxJac() == "approximateRoe") { // always use flux change off diagonal with roe method - offDiagonal = RoeOffDiagonal(offDiag, diag, update, fArea, mu, mut, - f1, dist, eqnState, thermo, trans, turb, - inp.IsViscous(), inp.IsRANS(), - positive); + offDiagonal = + RoeOffDiagonal(offDiag, diag, update, fArea, mu, mut, f1, dist, phys, + inp.IsViscous(), inp.IsRANS(), positive); } else { cerr << "ERROR: Error in OffDiagonal(), inviscid flux jacobian method of " << inp.InvFluxJac() << " is not recognized!" << endl; @@ -536,30 +237,21 @@ genArray OffDiagonal(const primVars &offDiag, const primVars &diag, return offDiagonal; } - -genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, - const genArray &update, - const unitVec3dMag &fArea, - const double &mu, const double &mut, - const double &dist, const double &f1, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const bool &isViscous, const bool &isRANS, - const bool &positive) { - // offDiag -- primative variables at off diagonal - // diag -- primative variables at diagonal +varArray RoeOffDiagonal(const primitiveView &offDiag, const primitiveView &diag, + const varArrayView &update, + const unitVec3dMag &fArea, const double &mu, + const double &mut, const double &dist, const double &f1, + const physics &phys, const bool &isViscous, + const bool &isRANS, const bool &positive) { + // offDiag -- primitive variables at off diagonal + // diag -- primitive variables at diagonal // update -- conserved variable update at off diagonal // fArea -- face area vector on off diagonal boundary // dist -- distance from cell center to cell center // mu -- laminar viscosity at off diagonal // mut -- turbulent viscosity at off diagonal // f1 -- first blending coefficient at off diagonal - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // isViscous -- flag to determine if simulation is viscous // isRANS -- flag to determine if simulation is turbulent // positive -- flag to determine whether to add or subtract dissipation @@ -570,29 +262,26 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, const auto areaNorm = fArea.UnitVector(); // calculate Roe flux with old variables - const auto oldFlux = RoeFlux(offDiag, diag, eqnState, thermo, areaNorm); + const auto oldFlux = RoeFlux(offDiag, diag, phys, areaNorm); // calculate updated Roe flux on off diagonal - const auto stateUpdate = - offDiag.UpdateWithConsVars(eqnState, thermo, update, turb); + const auto stateUpdate = offDiag.UpdateWithConsVars(phys, update); - const auto newFlux = positive ? - RoeFlux(stateUpdate, diag, eqnState, thermo, areaNorm) : - RoeFlux(diag, stateUpdate, eqnState, thermo, areaNorm); + const auto newFlux = positive ? RoeFlux(stateUpdate, diag, phys, areaNorm) + : RoeFlux(diag, stateUpdate, phys, areaNorm); // don't need 0.5 factor on roe flux because RoeFlux function already does it - const auto fluxChange = fArea.Mag() * (newFlux - oldFlux).ConvertToGenArray(); + const auto fluxChange = fArea.Mag() * (newFlux - oldFlux); // add contribution for viscous terms uncoupledScalar specRad(0.0, 0.0); if (isViscous) { specRad.AddToFlowVariable( - offDiag.ViscFaceSpectralRadius(fArea, thermo, eqnState, trans, dist, mu, - mut, turb)); + ViscFaceSpectralRadius(offDiag, fArea, phys, dist, mu, mut)); if (isRANS) { - specRad.AddToTurbVariable(turb->ViscFaceSpecRad(offDiag, fArea, mu, trans, - dist, mut, f1)); + specRad.AddToTurbVariable(phys.Turbulence()->ViscFaceSpecRad( + offDiag, fArea, mu, phys.Transport(), dist, mut, f1)); } } @@ -600,33 +289,3 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, fluxChange - specRad.ArrayMult(update); } -void fluxJacobian::MultiplyOnDiagonal(const double &val, - const bool &isRANS) { - // val -- value to multiply along diagonal - // isRANS -- flag identifiying if simulation is turbulent - - for (auto ii = 0; ii < flowJacobian_.Size(); ii++) { - flowJacobian_(ii, ii) *= val; - } - - if (isRANS) { - for (auto ii = 0; ii < turbJacobian_.Size(); ii++) { - turbJacobian_(ii, ii) *= val; - } - } -} - -void fluxJacobian::AddOnDiagonal(const double &val, const bool &isRANS) { - // val -- value to multiply along diagonal - // isRANS -- flag identifiying if simulation is turbulent - - for (auto ii = 0; ii < flowJacobian_.Size(); ii++) { - flowJacobian_(ii, ii) += val; - } - - if (isRANS) { - for (auto ii = 0; ii < turbJacobian_.Size(); ii++) { - turbJacobian_(ii, ii) += val; - } - } -} diff --git a/src/genArray.cpp b/src/genArray.cpp deleted file mode 100644 index 04de74c..0000000 --- a/src/genArray.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) - - Aither is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Aither is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include // exit() -#include // cout -#include -#include "genArray.hpp" -#include "uncoupledScalar.hpp" -#include "mpi.h" - -using std::cout; -using std::endl; -using std::cerr; - -// constructor -genArray::genArray(const uncoupledScalar &a) { - data_[0] = a.FlowVariable(); - data_[1] = a.FlowVariable(); - data_[2] = a.FlowVariable(); - data_[3] = a.FlowVariable(); - data_[4] = a.FlowVariable(); - - data_[5] = a.TurbVariable(); - data_[6] = a.TurbVariable(); -} - -// ------------------------------------------------------------------ -// functions for genArray class - -// operation overload for << - allows use of cout, cerr, etc. -ostream &operator<<(ostream &os, const genArray &m) { - for (auto rr = 0; rr < NUMVARS; rr++) { - os << m[rr] << endl; - } - return os; -} - -// member function to zero the matrix -void genArray::Zero() { - for (auto &val : data_) { - val = 0.0; - } -} - -// member function to sum column matrix -double genArray::Sum() { - auto sum = 0.0; - for (auto &val : data_) { - sum += val; - } - return sum; -} - -// member function to square root each element -void genArray::SquareRoot() { - for (auto &val : data_) { - val = sqrt(val); - } -} - -// member function to sum the residuals from all processors -void genArray::GlobalReduceMPI(const int &rank, const int &numEqns) { - // Get residuals from all processors - if (rank == ROOTP) { - MPI_Reduce(MPI_IN_PLACE, &data_[0], numEqns, MPI_DOUBLE, MPI_SUM, - ROOTP, MPI_COMM_WORLD); - } else { - MPI_Reduce(&data_[0], &data_[0], numEqns, MPI_DOUBLE, MPI_SUM, ROOTP, - MPI_COMM_WORLD); - } -} diff --git a/src/ghostStates.cpp b/src/ghostStates.cpp new file mode 100644 index 0000000..830a835 --- /dev/null +++ b/src/ghostStates.cpp @@ -0,0 +1,710 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include "primitive.hpp" +#include "input.hpp" // input +#include "physicsModels.hpp" +#include "utility.hpp" +#include "wallLaw.hpp" +#include "wallData.hpp" +#include "ghostStates.hpp" + +using std::cout; +using std::endl; +using std::cerr; +using std::vector; +using std::string; +using std::max; +using std::min; +using std::unique_ptr; + + +// member function to return the state of the appropriate ghost cell +/* + +In the diagram below Ui represents the interior state. This should be represnted +by (*this). Ug1 and Ug2 are the first and second layers of ghost cells +respectively. They are the output of the function. The input "layer" determines +whether Ug1 or Ug2 is output for BCs that use extrapolation. Reflected boundaries +(slipWall, viscousWall) do not use the layer input. Instead Ui+1 must be +specified as (*this) to output Ug2. + +____________________|___________ +| | | | +| | | | +| Ug2 | Ug1 | Ui | +| | | | +| | | | +|_________|_________|__________| + | + boundary face + +Currently the following boundary conditions are supported: slipWall, +viscousWall, characteristic, stagnationInlet, pressureOutlet, subsonicInflow, +subsonicOutflow, supersonicInflow, supersonicOutflow, inlet +*/ +primitive GetGhostState(const primitiveView &interior, const string &bcType, + const vector3d &areaVec, const double &wallDist, + const int &surf, const input &inputVars, const int &tag, + const physics &phys, wallVars &wVars, const int &layer, + const double &nuW, const double &dt, const primitive &stateN, + const vector3d &pressGrad, + const tensor &velGrad, const double &avgMach, + const double &maxMach) { + // interior -- primitive state at interior cell + // bcType -- type of boundary condition to supply ghost cell for + // areaVec -- unit area vector of boundary face + // surf -- surface type [1-6] + // wallDist -- distance from cell center to nearest wall boundary + // inputVar -- all input variables + // tag -- boundary condition tag + // phys -- physics models + // layer -- layer of ghost cell to return (1st (closest) or 2nd (farthest)) + // nuW -- wall adjacent kinematic viscosity + // dt -- cell time step nearest to wall boundary + // stateN -- solution at boundary adjacent cell at time n + // pressGrad -- pressure gradient in adjcent cell + // velGrad -- velocity gradient in adjacent cell + // avgMach -- average mach number on surface patch + // maxMach -- maximum mach number on surface patch + + // the instance of primitive being acted upon should be the interior cell + // bordering the boundary + + // set ghost state equal to boundary state to start + auto ghost = interior.CopyData(); + + // face area vector (should always point out of domain) + // at lower surface normal should point out of domain for ghost cell calc + const auto isLower = surf % 2 == 1; + const auto normArea = isLower ? -1.0 * areaVec : areaVec; + + // get equation indices + const auto imx = ghost.MomentumXIndex(); + const auto imy = ghost.MomentumYIndex(); + const auto imz = ghost.MomentumZIndex(); + const auto ie = ghost.EnergyIndex(); + const auto it = ghost.TurbulenceIndex(); + + // slip wall boundary condition + // ---------------------------------------------------------------------- + // slipWall is implemented as a reflection of the interior states so that + // there is no mass flow across the boundary. + if (bcType == "slipWall") { // for slip wall state should be reflected across + // boundary face, density and pressure stay equal + // to the boundary cell + const auto interiorVel = interior.Velocity(); + const auto normVelCellCenter = interiorVel.DotProd(normArea); + + // for a slip wall the velocity of the boundary cell center is reflected + // across the boundary face to get the velocity at the ghost cell center + const auto ghostVel = interiorVel - 2.0 * normArea * normVelCellCenter; + + ghost[imx] = ghostVel.X(); + ghost[imy] = ghostVel.Y(); + ghost[imz] = ghostVel.Z(); + + // numerical BCs for rho and pressure, same as boundary state + // numerical BCs for turbulence variables + + // viscous wall boundary condition + // ------------------------------------------------------------------------- + // viscous wall uses the interior density and pressure, but flips the sign + // on the velocity so that the velocity at the boundary is 0. + } else if (bcType == "viscousWall") { // for viscous wall velocity at face + // should be 0.0, density and pressure + // stay equal to the boundary cell + const auto &bcData = inputVars.BCData(tag); + + // ghost cell velocity at cell center is set to opposite of velocity at + // boundary cell center so that velocity at face will be zero + // only true for low-Re wall treatment + const auto velWall = bcData->Velocity(); + const auto ghostVel = 2.0 * velWall - interior.Velocity(); + ghost[imx] = ghostVel.X(); + ghost[imy] = ghostVel.Y(); + ghost[imz] = ghostVel.Z(); + const auto mf = interior.MassFractions(); + + if (bcData->IsIsothermal()) { //----------------------------------------- + const auto tWall = bcData->Temperature(); + // for wall law ghost velocity and turbulence variables calculated + // simultaneously + if (bcData->IsWallLaw()) { + wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), interior, + wallDist, inputVars.IsRANS()); + wVars = wl.IsothermalBCs(normArea, velWall, mf, phys, tWall, isLower); + + if (wVars.SwitchToLowRe()) { + const auto tGhost = 2.0 * tWall - interior.Temperature(phys.EoS()); + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + } else { + // use wall law heat flux to get ghost cell density + // need turbulent contribution because eddy viscosity is not 0 at wall + // assume mass fractions at wall are same as interior + const auto kappa = + phys.Transport()->EffectiveConductivity(wVars.temperature_, mf) + + phys.Transport()->TurbConductivity( + wVars.turbEddyVisc_, phys.Turbulence()->TurbPrandtlNumber(), + wVars.temperature_, phys.Thermodynamic(), mf); + // 2x wall distance as gradient length + const auto tGhost = tWall - wVars.heatFlux_ / kappa * 2.0 * wallDist; + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + } + + if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { + ghost[it] = 2.0 * wVars.tke_ - interior.Tke(); + ghost[it + 1] = 2.0 * wVars.sdr_ - interior.Omega(); + if (layer > 1) { + ghost[it] = layer * ghost[it] - wVars.tke_; + ghost[it + 1] = layer * ghost[it + 1] - wVars.sdr_; + } + } + } else { // low-Re wall treatment + const auto tGhost = 2.0 * tWall - interior.Temperature(phys.EoS()); + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + } + } else if (bcData->IsConstantHeatFlux()) { //----------------------------- + // must nondimensionalize heat flux + const auto qWall = bcData->HeatFlux(); + if (bcData->IsWallLaw()) { + wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), interior, + wallDist, inputVars.IsRANS()); + wVars = wl.HeatFluxBCs(normArea, velWall, mf, phys, qWall, isLower); + + if (wVars.SwitchToLowRe()) { + // don't need turbulent contribution b/c eddy viscosity is 0 at wall + const auto t = interior.Temperature(phys.EoS()); + const auto mf = interior.MassFractions(); + const auto kappa = phys.Transport()->EffectiveConductivity(t, mf); + // 2x wall distance as gradient length + const auto tGhost = + interior.Temperature(phys.EoS()) - qWall / kappa * 2.0 * wallDist; + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + } else { + // use wall law wall temperature to get ghost cell density + const auto tGhost = + 2.0 * wVars.temperature_ - interior.Temperature(phys.EoS()); + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + } + + if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { + ghost[it] = 2.0 * wVars.tke_ - interior.Tke(); + ghost[it + 1] = 2.0 * wVars.sdr_ - interior.Omega(); + if (layer > 1) { + ghost[it] = layer * ghost[it] - wVars.tke_; + ghost[it + 1] = layer * ghost[it + 1] - wVars.sdr_; + } + } + } else { // low-Re wall treatment + // don't need turbulent contribution b/c eddy viscosity is 0 at wall + const auto t = interior.Temperature(phys.EoS()); + const auto mf = interior.MassFractions(); + const auto kappa = phys.Transport()->EffectiveConductivity(t, mf); + // 2x wall distance as gradient length + const auto tGhost = + interior.Temperature(phys.EoS()) - qWall / kappa * 2.0 * wallDist; + const auto rho = phys.EoS()->DensityTP(tGhost, ghost.P(), mf); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + // numerical BCs for pressure, same as boundary state + } + } else { // default is adiabatic ----------------------------------------- + if (bcData->IsWallLaw()) { + wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), interior, + wallDist, inputVars.IsRANS()); + wVars = wl.AdiabaticBCs(normArea, velWall, mf, phys, isLower); + + if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { + ghost[it] = 2.0 * wVars.tke_ - interior.Tke(); + ghost[it + 1] = 2.0 * wVars.sdr_ - interior.Omega(); + if (layer > 1) { + ghost[it] = layer * ghost[it] - wVars.tke_; + ghost[it + 1] = layer * ghost[it + 1] - wVars.sdr_; + } + } + } + // numerical BCs for pressure, density - same as boundary state + } + + // turbulence bcs + // for wall law, turbulence bcs are already calculated, unless low Re model + // should be used + if (inputVars.IsRANS() && (!bcData->IsWallLaw() || wVars.SwitchToLowRe())) { + // tke at cell center is set to opposite of tke at boundary cell center + // so that tke at face will be zero + ghost[it] = -1.0 * interior.Tke(); + + const auto wWall = phys.Transport()->NondimScaling() * + phys.Transport()->NondimScaling() * 60.0 * nuW / + (wallDist * wallDist * phys.Turbulence()->WallBeta()); + ghost[it + 1] = 2.0 * wWall - interior.Omega(); + + if (layer > 1) { + ghost[it + 1] = layer * ghost[it + 1] - wWall; + } + } + + // characteristic boundary condition + // ------------------------------------------------------------------------- + // this is a characteristic based boundary condition which is appropriate + // for subsonic and supersonic flow. It automatically switches between + // inflow and outflow as needed. It also automatically determines the number + // of characteristics that need to be specified at the boundary (subsonic vs + // supersonic) + } else if (bcType == "characteristic") { + const auto &bcData = inputVars.BCData(tag); + // freestream variables + const auto freeVel = bcData->Velocity(); + primitive freeState(inputVars.NumEquations(), inputVars.NumSpecies()); + const auto freeRho = bcData->Density(); + const auto freeMf = bcData->MassFractions(); + for (auto &mf : freeMf) { + auto ind = inputVars.SpeciesIndex(mf.first); + freeState[ind] = freeRho * mf.second; + } + freeState[imx] = freeVel.X(); + freeState[imy] = freeVel.Y(); + freeState[imz] = freeVel.Z(); + freeState[ie] = bcData->Pressure(); + + // internal variables + const auto velIntNorm = interior.Velocity().DotProd(normArea); + const auto SoSInt = interior.SoS(phys); + const auto machInt = fabs(velIntNorm) / SoSInt; + + if (machInt >= 1.0 && velIntNorm < 0.0) { // supersonic inflow + // ----------------------------------------------------- + // characteristics all go into the domain, so use freestream values for + // both riemann invariants + ghost = freeState; + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + + } else if (machInt >= 1.0 && velIntNorm >= 0.0) { // supersonic outflow + // ---------------------------------------------- + // characteristics all leave the domain, so use interior values for both + // riemann invariants (do nothing) + } else if (machInt < 1.0 && velIntNorm < 0.0) { // subsonic inflow + // ---------------------------------------------- + // characteristics go in both directions, use interior values for plus + // characteristic and freestream values for minus characteristic + const auto rhoSoSInt = interior.Rho() * SoSInt; + const auto velDiff = freeState.Velocity() - interior.Velocity(); + + // plus characteristic + ghost[ie] = 0.5 * (freeState.P() + interior.P() - + rhoSoSInt * normArea.DotProd(velDiff)); + const auto deltaPressure = freeState.P() - ghost.P(); + + // minus characteristic + const auto rho = freeState.Rho() - deltaPressure / (SoSInt * SoSInt); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * freeState.MassFractionN(ii); + } + ghost[imx] = freeState.U() - normArea.X() * deltaPressure / rhoSoSInt; + ghost[imy] = freeState.V() - normArea.Y() * deltaPressure / rhoSoSInt; + ghost[imz] = freeState.W() - normArea.Z() * deltaPressure / rhoSoSInt; + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + + } else if (machInt < 1.0 && velIntNorm >= 0.0) { // subsonic outflow + // ---------------------------------------------------------- + // characteristics go in both directions, use interior values for plus + // characteristic and freestream values for minus characteristic + const auto rhoSoSInt = interior.Rho() * SoSInt; + const auto deltaPressure = interior.P() - freeState.P(); + + // plus characteristic + const auto rho = interior.Rho() - deltaPressure / (SoSInt * SoSInt); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + ghost[imx] = interior.U() + normArea.X() * deltaPressure / rhoSoSInt; + ghost[imy] = interior.V() + normArea.Y() * deltaPressure / rhoSoSInt; + ghost[imz] = interior.W() + normArea.Z() * deltaPressure / rhoSoSInt; + ghost[ie] = freeState.P(); // minus characteristic + + // numerical bcs for turbulence variables + + } else { + cerr << "ERROR: flow condition for characteristic BC is not recognized!" + << endl; + cerr << "Interior state: " << interior << endl; + cerr << "Ghost state: " << ghost << endl; + exit(EXIT_FAILURE); + } + + ghost = ExtrapolateHoldMixture(ghost, 2.0, interior); + + if (layer > 1) { // extrapolate to get ghost state at deeper layers + ghost = ExtrapolateHoldMixture(ghost, layer, interior); + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + } + + // inlet boundary condition + // ------------------------------------------------------------------------- + } else if (bcType == "inlet") { + const auto &bcData = inputVars.BCData(tag); + // freestream variables + primitive freeState(inputVars.NumEquations(), inputVars.NumSpecies()); + const auto freeVel = bcData->Velocity(); + const auto freeRho = bcData->Density(); + const auto freeMf = bcData->MassFractions(); + for (auto &mf : freeMf) { + auto ind = inputVars.SpeciesIndex(mf.first); + freeState[ind] = freeRho * mf.second; + } + freeState[imx] = freeVel.X(); + freeState[imy] = freeVel.Y(); + freeState[imz] = freeVel.Z(); + freeState[ie] = bcData->Pressure(); + + // internal variables + const auto velIntNorm = interior.Velocity().DotProd(normArea); + const auto SoSInt = interior.SoS(phys); + const auto machInt = fabs(velIntNorm) / SoSInt; + + if (machInt >= 1.0) { // supersonic inflow + // ----------------------------------------------------- + // characteristics all go into the domain, so use freestream values for + // both riemann invariants + ghost = freeState; + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + } else { // subsonic inflow + // ---------------------------------------------- + // characteristics go in both directions, use interior values for plus + // characteristic and freestream values for minus characteristic + const auto rhoSoSInt = interior.Rho() * SoSInt; + const auto velDiff = freeState.Velocity() - interior.Velocity(); + + // plus characteristic + ghost[ie] = 0.5 * (freeState.P() + interior.P() - + rhoSoSInt * normArea.DotProd(velDiff)); + + if (bcData->IsNonreflecting()) { + // minus characteristic + // calculate LODI terms + constexpr auto sigma = 0.25; + const auto rhoN = stateN.Rho(); + const auto sosN = stateN.SoS(phys); + const auto rhoSoSN = rhoN * sosN; + const auto deltaPressure = ghost.P() - stateN.P(); + const auto length = bcData->LengthScale(); + const auto alphaR = sigma / (sosN * length); + + const auto rhoNp1 = (rhoN + dt * alphaR * freeState.Rho() + + deltaPressure / (sosN * sosN)) / + (1.0 + dt * alphaR); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rhoNp1 * freeState.MassFractionN(ii); + } + + const auto alpha = sigma * sosN / length; + const auto k = alpha * (1.0 - maxMach * maxMach); + auto vel = (stateN.Velocity() + dt * k * freeState.Velocity() - + normArea * deltaPressure / rhoSoSN) / + (1.0 + dt * k); + + ghost[imx] = vel.X(); + ghost[imy] = vel.Y(); + ghost[imz] = vel.Z(); + + } else { + const auto deltaPressure = freeState.P() - ghost.P(); + + // minus characteristic + const auto rho = freeState.Rho() - deltaPressure / (SoSInt * SoSInt); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * freeState.MassFractionN(ii); + } + ghost[imx] = freeState.U() - normArea.X() * deltaPressure / rhoSoSInt; + ghost[imy] = freeState.V() - normArea.Y() * deltaPressure / rhoSoSInt; + ghost[imz] = freeState.W() - normArea.Z() * deltaPressure / rhoSoSInt; + } + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + + // only extrapolating for subsonic condition + // extrapolate from boundary to ghost cell + ghost = ExtrapolateHoldMixture(ghost, 2.0, interior); + + if (layer > 1) { // extrapolate to get ghost state at deeper layers + ghost = ExtrapolateHoldMixture(ghost, layer, interior); + } + } + + // supersonic inflow boundary condition + // ------------------------------------------------------------------------- + // this boundary condition enforces the entire state as the specified + // freestream state + } else if (bcType == "supersonicInflow") { + const auto &bcData = inputVars.BCData(tag); + // physical boundary conditions - fix everything + const auto vel = bcData->Velocity(); + // zero densities + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = 0.0; + } + // assign density from BCs + const auto ghostRho = bcData->Density(); + const auto ghostMf = bcData->MassFractions(); + for (auto &mf : ghostMf) { + auto ind = inputVars.SpeciesIndex(mf.first); + ghost[ind] = ghostRho * mf.second; + } + ghost[imx] = vel.X(); + ghost[imy] = vel.Y(); + ghost[imz] = vel.Z(); + ghost[ie] = bcData->Pressure(); + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(vel, bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + + // supersonic outflow boundary condition + // -------------------------------------------------------------------------- + // this boundary condition enforces the entire state as extrapolated from + // the + // interior (zeroth order extrapolation) + } else if (bcType == "supersonicOutflow") { + // do nothing and return boundary state -- numerical BCs for all + if (layer > 1) { // extrapolate to get ghost state at deeper layers + ghost = layer * ghost - interior; + } + + // stagnation inlet boundary condition + // -------------------------------------------------------------------------- + // this boundary condition is appropriate for subsonic flow. It is + // particularly well suited for internal flows. Implementation from Blazek + } else if (bcType == "stagnationInlet") { + const auto &bcData = inputVars.BCData(tag); + + const auto t = interior.Temperature(phys.EoS()); + const auto mf = interior.MassFractions(); + const auto g = phys.Thermodynamic()->Gamma(t, mf) - 1.0; + // calculate outgoing riemann invarient + const auto rNeg = + interior.Velocity().DotProd(normArea) - 2.0 * interior.SoS(phys) / g; + + // calculate SoS on boundary + const auto cosTheta = -1.0 * interior.Velocity().DotProd(normArea) / + interior.Velocity().Mag(); + const auto stagSoSsq = + pow(interior.SoS(phys), 2.0) + 0.5 * g * interior.Velocity().MagSq(); + + const auto sosB = -1.0 * rNeg * g / (g * cosTheta * cosTheta + 2.0) * + (1.0 + cosTheta * sqrt((g * cosTheta * cosTheta + 2.0) * + stagSoSsq / (g * rNeg * rNeg) - + 0.5 * g)); + const auto tb = bcData->StagnationTemperature() * (sosB * sosB / stagSoSsq); + const auto pb = + bcData->StagnationPressure() * + pow(sosB * sosB / stagSoSsq, phys.Thermodynamic()->Gamma(t, mf) / g); + const auto vbMag = sqrt(2.0 / g * (bcData->StagnationTemperature() - tb)); + + // zero densities + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = 0.0; + } + // assign densities from BC + const auto mfGhostMap = bcData->MassFractions(); + vector mfGhost(interior.NumSpecies(), 0); + for (auto &mfg : mfGhostMap) { + auto ind = inputVars.SpeciesIndex(mfg.first); + mfGhost[ind] = mfg.second; + } + const auto rhoGhost = phys.EoS()->DensityTP(tb, pb, mfGhost); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rhoGhost * mfGhost[ii]; + } + ghost[imx] = vbMag * bcData->Direction().X(); + ghost[imy] = vbMag * bcData->Direction().Y(); + ghost[imz] = vbMag * bcData->Direction().Z(); + ghost[ie] = pb; + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(ghost.Velocity(), bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + + // extrapolate from boundary to ghost cell + ghost = ExtrapolateHoldMixture(ghost, 2.0, interior); + + if (layer > 1) { // extrapolate to get ghost state at deeper layers + ghost = ExtrapolateHoldMixture(ghost, layer, interior); + + // assign farfield conditions to turbulence variables + if (inputVars.IsRANS()) { + ghost.ApplyFarfieldTurbBC(ghost.Velocity(), + bcData->TurbulenceIntensity(), + bcData->EddyViscosityRatio(), phys); + } + } + + // pressure outlet boundary condition + // ----------------------------------------------------------------------- + // this boundary condition is appropriate for subsonic flow. Implementation + // from Blazek + } else if (bcType == "pressureOutlet") { + const auto &bcData = inputVars.BCData(tag); + + // nondimensional pressure from input file + const auto pb = bcData->Pressure(); + + const auto SoSInt = interior.SoS(phys); + const auto rhoSoSInt = interior.Rho() * SoSInt; + + if (bcData->IsNonreflecting()) { + // calculate LODI terms + const auto deltaVel = + (interior.Velocity() - stateN.Velocity()).DotProd(normArea); + constexpr auto sigma = 0.25; + const auto rhoN = stateN.Rho(); + const auto sosN = stateN.SoS(phys); + const auto rhoSoSN = rhoN * sosN; + const auto length = bcData->LengthScale(); + const auto k = sigma * sosN * (1.0 - maxMach * maxMach) / length; + + // calculate transverse terms + const auto beta = avgMach; + const auto pGradT = pressGrad - pressGrad.DotProd(normArea) * normArea; + const auto velT = + stateN.Velocity() - stateN.Velocity().DotProd(normArea) * normArea; + const auto velGradT = velGrad.RemoveComponent(normArea); + const auto dVelN_dTrans = velGradT.LinearCombination(normArea); + const auto dVelT_dTrans = velGradT.Sum() - dVelN_dTrans.SumElem(); + const auto gamma = phys.Thermodynamic()->Gamma( + stateN.Temperature(phys.EoS()), stateN.MassFractions()); + + const auto trans = -0.5 * (velT.DotProd(pGradT - rhoSoSN * dVelN_dTrans) + + gamma * stateN.P() * dVelT_dTrans); + + ghost[ie] = + (stateN.P() + rhoSoSN * deltaVel + dt * k * pb - dt * beta * trans) / + (1.0 + dt * k); + } else { + ghost[ie] = pb; + } + + const auto deltaPressure = interior.P() - ghost.P(); + const auto rho = interior.Rho() - deltaPressure / (SoSInt * SoSInt); + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = rho * interior.MassFractionN(ii); + } + ghost[imx] = interior.U() + normArea.X() * deltaPressure / rhoSoSInt; + ghost[imy] = interior.V() + normArea.Y() * deltaPressure / rhoSoSInt; + ghost[imz] = interior.W() + normArea.Z() * deltaPressure / rhoSoSInt; + + // numerical bcs for turbulence variables + + // check for supersonic flow + if (ghost.Velocity().DotProd(normArea) / ghost.SoS(phys) >= 1.0) { + ghost = interior.CopyData(); + } + + // extrapolate from boundary to ghost cell + ghost = 2.0 * ghost - interior; + + if (layer > 1) { // extrapolate to get ghost state at deeper layers + ghost = layer * ghost - interior; + } + + // connection boundary condition + // -------------------------------------------------------------------------- + // this boundary condition is appropriate for point matched interfaces + // between physical blocks or processor blocks + } else if (bcType == "interblock" || bcType == "periodic") { + // do nothing -- assign interior state to ghost state (already done) + // for second layer of ghost cells interior state should be 2nd interior + // cell + + } else { + cerr << "ERROR: Error in primitive::GetGhostState ghost state for BC type " + << bcType << " is not supported!" << endl; + cerr << "surface is " << surf << " and layer is " << layer << endl; + exit(EXIT_FAILURE); + } + + MSG_ASSERT(ghost.Rho() > 0, "nonphysical density"); + MSG_ASSERT(ghost.P() > 0, "nonphysical pressure"); + + return ghost; +} + +primitive ExtrapolateHoldMixture(const primitive &boundary, + const double &factor, + const primitiveView &interior) { + auto bndRho = boundary.Rho(); + auto bndMf = boundary.MassFractions(); + auto intRho = interior.Rho(); + + auto ghostRho = factor * bndRho - intRho; + if (ghostRho <= 0.0) { // big density change at boundary, don't extrapolate + return boundary; + } + + // keep boundary mass fractions, but use extrapolated density + auto ghost = factor * boundary - interior; + for (auto ii = 0; ii < ghost.NumSpecies(); ++ii) { + ghost[ii] = std::max(ghostRho * bndMf[ii], 0.0); + } + return ghost; +} \ No newline at end of file diff --git a/src/input.cpp b/src/input.cpp index 3e470ba..73f9f48 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,9 +28,7 @@ #include "input.hpp" #include "turbulence.hpp" #include "inputStates.hpp" -#include "eos.hpp" -#include "transport.hpp" -#include "thermodynamic.hpp" +#include "physicsModels.hpp" #include "fluid.hpp" #include "macros.hpp" @@ -57,6 +55,7 @@ input::input(const string &name, const string &resName) : simName_(name), tRef_ = -1.0; lRef_ = 1.0; aRef_ = 0.0; + mixtureRef_ = vector(1, 1.0); fluids_ = vector(1); bc_ = vector(1); timeIntegration_ = "explicitEuler"; @@ -88,10 +87,12 @@ input::input(const string &name, const string &resName) : simName_(name), thermodynamicModel_ = "caloricallyPerfect"; // default to cpg equationOfState_ = "idealGas"; // default to ideal gas transportModel_ = "sutherland"; // default to sutherland + diffusionModel_ = "none"; // default to no diffusion restartFrequency_ = 0; // default to not write restarts iterationStart_ = 0; // default to start from iteration zero + schmidtNumber_ = 0.9; - // default to primative variables + // default to primitive variables outputVariables_ = {"density", "vel_x", "vel_y", "vel_z", "pressure"}; wallOutputVariables_ = {}; @@ -124,11 +125,13 @@ input::input(const string &name, const string &resName) : simName_(name), "decompositionMethod", "turbulenceModel", "thermodynamicModel", + "diffusionModel", "equationOfState", "transportModel", "outputVariables", "wallOutputVariables", "initialConditions", + "schmidtNumber", "boundaryStates", "boundaryConditions"}; } @@ -228,7 +231,7 @@ void input::ReadInput(const int &rank) { if (ii == fluids_.size() - 1) { cout << ">" << endl; } else { - cout << "," << endl << " "; + cout << "," << endl << " "; } } } @@ -388,6 +391,16 @@ void input::ReadInput(const int &rank) { if (rank == ROOTP) { cout << key << ": " << this->TransportModel() << endl; } + } else if (key == "diffusionModel") { + diffusionModel_ = tokens[1]; + if (rank == ROOTP) { + cout << key << ": " << this->DiffusionModel() << endl; + } + } else if (key == "schmidtNumber") { + schmidtNumber_ = stod(tokens[1]); // double variable (stod) + if (rank == ROOTP) { + cout << key << ": " << this->SchmidtNumber() << endl; + } } else if (key == "outputVariables") { // clear default variables from set outputVariables_.clear(); @@ -497,7 +510,6 @@ void input::ReadInput(const int &rank) { // boundary conditions are space delimited tokens = Tokenize(line, " "); tempBC[blk].AssignFromInput(surfCounter, tokens); - surfCounter++; if (surfCounter == numSurf) { // at end of block data, increment // block index, reset surface @@ -512,6 +524,9 @@ void input::ReadInput(const int &rank) { // if block counter reaches number of blocks, BCs are finished (b/c // counter starts at 0), so assign BCs and write them out if (blk == numBCBlks) { + for (auto &bc : tempBC) { + bc.Sort(); + } bc_ = tempBC; if (rank == ROOTP) { cout << "boundaryConditions: " << this->NumBC() << endl; @@ -526,6 +541,26 @@ void input::ReadInput(const int &rank) { } } + // get mixture reference mass fractions + if (this->NumSpecies() > 1) { + mixtureRef_.resize(this->NumSpecies()); + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + mixtureRef_[ii] = fluids_[ii].MassFractionRef(); + } + // normalize mass fractions so that sum is 1 + auto mfSum = std::accumulate(mixtureRef_.begin(), mixtureRef_.end(), 0.0); + std::for_each(mixtureRef_.begin(), mixtureRef_.end(), + [&mfSum](auto &val) { val /= mfSum; }); + } else { + mixtureRef_[0] = 1.0; + } + + // assign reference speed of sound (assume cpg for gamma) + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + auto gamma = (fluids_[ii].N() + 1) / fluids_[ii].N(); + aRef_ += mixtureRef_[ii] * gamma * fluids_[ii].GasConstant() * tRef_; + } + aRef_ = sqrt(aRef_); // input file sanity checks this->CheckNonlinearIterations(); @@ -533,6 +568,7 @@ void input::ReadInput(const int &rank) { this->CheckWallOutputVariables(); this->CheckTurbulenceModel(); this->CheckSpecies(); + this->CheckNonreflecting(); if (rank == ROOTP) { cout << endl; @@ -541,6 +577,7 @@ void input::ReadInput(const int &rank) { "#########################################################" << endl << endl; } + inFile.close(); } // member function to calculate the cfl value for the step from the starting, @@ -660,24 +697,17 @@ unique_ptr input::AssignTurbulenceModel() const { } // member function to get equation of state -unique_ptr input::AssignEquationOfState( - const unique_ptr &thermo) { - // get fluid - auto fl = this->Fluid(); +unique_ptr input::AssignEquationOfState() const { // define equation of state unique_ptr eqnState(nullptr); if (equationOfState_ == "idealGas") { - // nondimensional temperature is 1.0 (tRef_ / tRef_) - eqnState = unique_ptr{ - std::make_unique(thermo, fl.GasConstant(), 1.0)}; + eqnState = + unique_ptr{std::make_unique(fluids_, tRef_, aRef_)}; } else { cerr << "ERROR: Error in input::AssignEquationOfState(). Equation of state " << equationOfState_ << " is not recognized!" << endl; exit(EXIT_FAILURE); } - // use equation of state to assign additional reference values - const auto pRef = eqnState->PressureDim(rRef_, tRef_); - aRef_ = eqnState->SoS(pRef, rRef_); return eqnState; } @@ -687,7 +717,7 @@ unique_ptr input::AssignTransportModel() const { unique_ptr trans(nullptr); if (transportModel_ == "sutherland") { trans = unique_ptr{std::make_unique( - tRef_, rRef_, lRef_, aRef_)}; + fluids_, tRef_, rRef_, lRef_, aRef_, mixtureRef_)}; } else { cerr << "ERROR: Error in input::AssignTransportModel(). Transport model " << transportModel_ << " is not recognized!" << endl; @@ -698,16 +728,14 @@ unique_ptr input::AssignTransportModel() const { // member function to get thermodynamic model unique_ptr input::AssignThermodynamicModel() const { - // get fluid - auto fl = this->Fluid(); - // define equation of state + // define thermodynamic model unique_ptr thermo(nullptr); if (thermodynamicModel_ == "caloricallyPerfect") { - thermo = - unique_ptr{std::make_unique(fl.N())}; + thermo = unique_ptr{ + std::make_unique(fluids_, tRef_, aRef_)}; } else if (thermodynamicModel_ == "thermallyPerfect") { - thermo = unique_ptr{std::make_unique( - fl.N(), fl.VibrationalTemperature())}; + thermo = unique_ptr{ + std::make_unique(fluids_, tRef_, aRef_)}; } else { cerr << "ERROR: Error in input::AssignThermodynamicModel(). Thermodynamic " << "model " << thermodynamicModel_ << " is not recognized!" << endl; @@ -716,6 +744,31 @@ unique_ptr input::AssignThermodynamicModel() const { return thermo; } +// member function to get diffusion model +unique_ptr input::AssignDiffusionModel(const double &sct) const { + // define diffusion model + unique_ptr diff(nullptr); + if (diffusionModel_ == "none") { + diff = unique_ptr{std::make_unique()}; + } else if (diffusionModel_ == "schmidt") { + diff = unique_ptr{ + std::make_unique(schmidtNumber_, sct)}; + } else { + cerr << "ERROR: Error in input::AssignDiffusionModel(). Diffusion " + << "model " << diffusionModel_ << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } + return diff; +} + +physics input::AssignPhysicsModels() const { + auto eqnState = this->AssignEquationOfState(); + auto trans = this->AssignTransportModel(); + auto thermo = this->AssignThermodynamicModel(); + auto turb = this->AssignTurbulenceModel(); + auto diff = this->AssignDiffusionModel(turb->TurbSchmidtNumber()); + return {eqnState, trans, thermo, diff, turb}; +} // member function to return the name of the simulation without the file // extension i.e. "myInput.inp" would return "myInput" @@ -732,7 +785,7 @@ void input::CheckNonlinearIterations() { nonlinearIterations_ = 4; } - if (timeIntegration_ == "euler" && nonlinearIterations_ != 1) { + if (timeIntegration_ == "explicitEuler" && nonlinearIterations_ != 1) { cerr << "WARNING: For euler method, nonlinear iterations should be set to " << 1 << " changing value from " << nonlinearIterations_ << " to " << 1 << endl; @@ -763,13 +816,20 @@ void input::CheckOutputVariables() { } if (!this->IsViscous()) { // can't have viscous variables output - if (var.find("velGrad_") != string::npos - || var.find("tempGrad_") != string::npos || var == "viscosity") { + if (var == "viscosity") { cerr << "WARNING: Variable " << var << " is not available for inviscid simulations." << endl; outputVariables_.erase(var); } } + + // check species + if (var.substr(0, 3) == "mf_" && + !this->HaveSpecies(var.substr(3, string::npos))) { + cerr << "WARNING: Species " << var.substr(3, string::npos) + << " is not present. Removing mass fraction output request" << endl; + outputVariables_.erase(var); + } } } @@ -829,15 +889,17 @@ void input::CheckTurbulenceModel() const { void input::CheckSpecies() const { // check all species in ICs are defined for (auto &ic : ics_) { - auto fracs = ic.MassFractions(); // get mass fractions for ICs - // loop over all species and find if that species has been defined - for (auto &species : fracs) { - auto name = species.first; - if (find_if(std::begin(fluids_), std::end(fluids_), - [&name](const fluid &fl) { return fl.Name() == name; }) == - std::end(fluids_)) { - cerr << "ERROR: Species " << name << " is not defined!" << endl; - exit(EXIT_FAILURE); + if (!ic.IsFromFile()) { + auto fracs = ic.MassFractions(); // get mass fractions for ICs + // loop over all species and find if that species has been defined + for (auto &species : fracs) { + auto name = species.first; + if (find_if(std::begin(fluids_), std::end(fluids_), + [&name](const fluid &fl) { return fl.Name() == name; }) == + std::end(fluids_)) { + cerr << "ERROR: Species " << name << " is not defined!" << endl; + exit(EXIT_FAILURE); + } } } } @@ -861,9 +923,66 @@ void input::CheckSpecies() const { // check that there is at least one species defined if (fluids_.size() < 1) { cerr << "ERROR: At least one fluid species must be defined!" << endl; + exit(EXIT_FAILURE); } } +// check that nonreflecting BCs aren't used with explicit euler because +// solution at time N is not stored +void input::CheckNonreflecting() const { + if (timeIntegration_ == "explicitEuler") { + for (auto &bc : bcStates_) { + if (bc->IsNonreflecting()) { + cerr << "ERROR: Nonreflecting BCs cannot be used with explicitEuler " + "time integration!" + << endl; + exit(EXIT_FAILURE); + } + } + } +} + +// member function to check that all species specified are defined +// vector of species comes from prescribed ic file +void input::CheckSpecies(const vector &species) const { + for (auto &name : species) { + if (find_if(std::begin(fluids_), std::end(fluids_), + [&name](const fluid &fl) { return fl.Name() == name; }) == + std::end(fluids_)) { + cerr << "ERROR: Species " << name << " is not defined!" << endl; + exit(EXIT_FAILURE); + } + } + + // check that there is at least one species from ic file + if (species.size() < 1) { + cerr << "ERROR: At least one fluid species must be defined in ic file!" + << endl; + exit(EXIT_FAILURE); + } +} + +// member function to check that species specified is defined +bool input::HaveSpecies(const string &species) const { + return !(find_if(std::begin(fluids_), std::end(fluids_), + [&species](const fluid &fl) { + return fl.Name() == species; + }) == std::end(fluids_)); +} + +// member function to get index of species +int input::SpeciesIndex(const string &species) const { + auto ind = -1; + find_if(std::begin(fluids_), std::end(fluids_), + [&species, &ind](const fluid &fl) { + ind++; + return fl.Name() == species; + }); + MSG_ASSERT(ind < this->NumSpecies() && ind >= 0, + "species index out of range"); + return ind; +} + // member function to calculate the coefficient used to scale the viscous // spectral radius in the time step calculation double input::ViscousCFLCoefficient() const { @@ -915,6 +1034,7 @@ icState input::ICStateForBlock(const int &block) const { } else if (ic.Tag() == block) { blockIC = ic; foundExactMatch = true; + break; } } @@ -956,6 +1076,3 @@ void input::NondimensionalizeFluid() { fl.Nondimensionalize(tRef_); } } - -// default value is 0; code currently only supports single fluid flows -fluid input::Fluid(const int ind) const { return fluids_[ind]; } \ No newline at end of file diff --git a/src/inputStates.cpp b/src/inputStates.cpp index d80ec6c..8105256 100644 --- a/src/inputStates.cpp +++ b/src/inputStates.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -90,10 +90,10 @@ ostream &operator<<(ostream &os, const characteristic &bc) { return os; } -void stagnationInlet::Print(ostream &os) const { - os << "stagnationInlet(tag=" << this->Tag() << "; p0=" - << this->StagnationPressure() << "; t0=" << this->StagnationTemperature() - << "; direction=[" << this->Direction() << "]"; +void inlet::Print(ostream &os) const { + os << "inlet(tag=" << this->Tag() << "; pressure=" << this->Pressure() + << "; density=" << this->Density() << "; velocity=[" << this->Velocity() + << "]"; if (this->SpecifiedTurbulence()) { os << "; turbulenceIntensity=" << this->TurbulenceIntensity() << "; eddyViscosityRatio=" << this->EddyViscosityRatio(); @@ -113,26 +113,15 @@ void stagnationInlet::Print(ostream &os) const { } os << ")"; } - -ostream &operator<<(ostream &os, const stagnationInlet &bc) { +ostream &operator<<(ostream &os, const inlet &bc) { bc.Print(os); return os; } -void pressureOutlet::Print(ostream &os) const { - os << "pressureOutlet(tag=" << this->Tag() << "; pressure=" - << this->Pressure() << ")"; -} - -ostream &operator<<(ostream &os, const pressureOutlet &bc) { - bc.Print(os); - return os; -} - -void supersonicInflow::Print(ostream &os) const { - os << "supersonicInflow(tag=" << this->Tag() << "; pressure=" - << this->Pressure() << "; density=" << this->Density() << "; velocity=[" - << this->Velocity() << "]"; +void stagnationInlet::Print(ostream &os) const { + os << "stagnationInlet(tag=" << this->Tag() << "; p0=" + << this->StagnationPressure() << "; t0=" << this->StagnationTemperature() + << "; direction=[" << this->Direction() << "]"; if (this->SpecifiedTurbulence()) { os << "; turbulenceIntensity=" << this->TurbulenceIntensity() << "; eddyViscosityRatio=" << this->EddyViscosityRatio(); @@ -153,24 +142,30 @@ void supersonicInflow::Print(ostream &os) const { os << ")"; } -ostream &operator<<(ostream &os, const supersonicInflow &bc) { +ostream &operator<<(ostream &os, const stagnationInlet &bc) { bc.Print(os); return os; } -void subsonicOutflow::Print(ostream &os) const { - os << "subsonicOutflow(tag=" << this->Tag() << "; pressure=" - << this->Pressure() << ")"; +void pressureOutlet::Print(ostream &os) const { + os << "pressureOutlet(tag=" << this->Tag() + << "; pressure=" << this->Pressure(); + if (this->SpecifiedReflecting()) { + os << "; nonreflecting=" << std::boolalpha << this->IsNonreflecting(); + os << "; lengthScale=" << this->LengthScale(); + } + os << ")"; } -ostream &operator<<(ostream &os, const subsonicOutflow &bc) { +ostream &operator<<(ostream &os, const pressureOutlet &bc) { bc.Print(os); return os; } -void subsonicInflow::Print(ostream &os) const { - os << "subsonicInflow(tag=" << this->Tag() << "; density=" << this->Density() - << "; velocity=[" << this->Velocity() << "]"; +void supersonicInflow::Print(ostream &os) const { + os << "supersonicInflow(tag=" << this->Tag() << "; pressure=" + << this->Pressure() << "; density=" << this->Density() << "; velocity=[" + << this->Velocity() << "]"; if (this->SpecifiedTurbulence()) { os << "; turbulenceIntensity=" << this->TurbulenceIntensity() << "; eddyViscosityRatio=" << this->EddyViscosityRatio(); @@ -179,7 +174,7 @@ void subsonicInflow::Print(ostream &os) const { os << "; massFractions=["; auto numSpecies = this->NumberSpecies(); auto count = 0; - for (auto &fracs : massFractions_) { + for (auto &fracs : this->MassFractions()) { os << fracs.first << "=" << fracs.second; if (count < numSpecies - 1) { os << ", "; @@ -191,7 +186,7 @@ void subsonicInflow::Print(ostream &os) const { os << ")"; } -ostream &operator<<(ostream &os, const subsonicInflow &bc) { +ostream &operator<<(ostream &os, const supersonicInflow &bc) { bc.Print(os); return os; } @@ -307,6 +302,20 @@ vector3d ReadVector(const string &str) { return {stod(tokens[0]), stod(tokens[1]), stod(tokens[2])}; } +// function to read vector data from string +vector ReadVectorXd(const string &str) { + const auto start = str.find("[") + 1; + const auto end = str.find("]") - 1; + const auto range = end - start + 1; // +/-1 to ignore [] + auto vec = str.substr(start, range); + auto tokens = Tokenize(vec, ","); + vector vals(tokens.size()); + for (auto ii = 0U; ii < vals.size(); ++ii) { + vals[ii] = stod(tokens[ii]); + } + return vals; +} + // function to read mass fraction data from string map ReadMassFractions(const string &str) { const auto start = str.find("[") + 1; @@ -347,13 +356,13 @@ map ReadMassFractions(const string &str) { } // construct initial condition from string -icState::icState(string &str, const string name) { +void icState::Read(string &str) { const auto start = str.find("(") + 1; const auto end = str.find(")") - 1; const auto range = end - start + 1; // +/-1 to ignore () auto state = str.substr(start, range); const auto id = str.substr(0, start - 1); - if (id != name) { + if (id != name_) { cerr << "ERROR. State condition specifier " << id << " is not recognized!" << endl; exit(EXIT_FAILURE); @@ -376,7 +385,7 @@ icState::icState(string &str, const string name) { for (auto &token : tokens) { auto param = Tokenize(token, "=", 1); if (param.size() != 2) { - cerr << "ERROR. Problem with " << name << " parameter " << token << endl; + cerr << "ERROR. Problem with " << name_ << " parameter " << token << endl; exit(EXIT_FAILURE); } @@ -407,8 +416,10 @@ icState::icState(string &str, const string name) { } else if (param[0] == "tag") { this->SetTag(stoi(RemoveTrailing(param[1], ","))); tagCount++; + } else if (this->MatchesExtraData(param[0])) { + this->AssignExtraData(param[0], param[1]); } else { - cerr << "ERROR. " << name << " specifier " << param[0] + cerr << "ERROR. " << name_ << " specifier " << param[0] << " is not recognized!" << endl; exit(EXIT_FAILURE); } @@ -418,14 +429,14 @@ icState::icState(string &str, const string name) { // required variables if (!((pressureCount == 1 && densityCount == 1 && velocityCount == 1) || fileCount == 1)) { - cerr << "ERROR. For " << name << " pressure, density, and " + cerr << "ERROR. For " << name_ << " pressure, density, and " << "velocity must be specified, OR file must be specified." << endl; exit(EXIT_FAILURE); } if (fileCount == 1 && (pressureCount == 1 || densityCount == 1 || velocityCount == 1 || mfCount == 1 || tiCount == 1 || evrCount == 1)) { - cerr << "ERROR. For " << name + cerr << "ERROR. For " << name_ << ", if file is specified, tag is the only other field allowed" << endl; exit(EXIT_FAILURE); @@ -434,7 +445,7 @@ icState::icState(string &str, const string name) { if (tagCount > 1 || tiCount > 1 || mfCount > 1 || evrCount > 1 || tiCount != evrCount || fileCount > 1 || pressureCount > 1 || densityCount > 1 || velocityCount > 1) { - cerr << "ERROR. For " << name << ", tag, pressure, density, velocity, " + cerr << "ERROR. For " << name_ << ", tag, pressure, density, velocity, " "massFractions, turbulenceIntensity, " << "eddyViscosityRatio, and file can only be specified once." << endl; cerr << "If either turbulenceIntensity or eddyViscosityRatio is specified " @@ -442,10 +453,12 @@ icState::icState(string &str, const string name) { exit(EXIT_FAILURE); } - if (name != "icState" && tagCount != 1) { - cerr << "ERROR. For " << name << ", tag must be specified." << endl; + if (name_ != "icState" && tagCount != 1) { + cerr << "ERROR. For " << name_ << ", tag must be specified." << endl; exit(EXIT_FAILURE); } + + this->ExtraDataChecks(); } void icState::Nondimensionalize(const double &rRef, const double &tRef, @@ -454,12 +467,48 @@ void icState::Nondimensionalize(const double &rRef, const double &tRef, velocity_ /= aRef; density_ /= rRef; pressure_ /= rRef * aRef * aRef; + this->NondimensionalizeExtra(rRef, tRef, lRef, aRef); this->SetNondimensional(true); } } +void inlet::AssignExtraData(const string &s1, const string &s2) { + if (s1 == "nonreflecting") { + auto reflect = RemoveTrailing(s2, ","); + nonreflecting_ = (reflect == "true"); + specifiedReflecting_ = true; + nonreflectingCount_++; + } else if (s1 == "lengthScale") { + lengthScale_ = stod(RemoveTrailing(s2, ",")); + lengthCount_++; + } else { + cerr << "ERROR: parameter " << s1 << " with value " << s2 + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } +} + +void inlet::NondimensionalizeExtra(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) { + lengthScale_ /= lRef; +} + +void inlet::ExtraDataChecks() const { + // can only specify nonreflecting and length scale once + if (nonreflectingCount_ > 1 || lengthCount_ > 1) { + cerr << "ERROR. For inlet nonreflecting and/or lengthScale can " + << "only be specified once" << endl; + exit(EXIT_FAILURE); + } + if (nonreflecting_ && lengthCount_ != 1) { + cerr << "ERROR. For inlet lengthScale must be specified with " + << "nonreflecting" << endl; + exit(EXIT_FAILURE); + } +} + // construct stagnation inlet from string -stagnationInlet::stagnationInlet(string &str) { +void stagnationInlet::Read(string &str) { const auto start = str.find("(") + 1; const auto end = str.find(")") - 1; const auto range = end - start + 1; // +/-1 to ignore () @@ -550,13 +599,13 @@ void stagnationInlet::Nondimensionalize(const double &rRef, const double &tRef, } // construct pressureOutlet from string -pressureOutlet::pressureOutlet(string &str, const string name) { +void pressureOutlet::Read(string &str) { const auto start = str.find("(") + 1; const auto end = str.find(")") - 1; const auto range = end - start + 1; // +/-1 to ignore () auto state = str.substr(start, range); const auto id = str.substr(0, start - 1); - if (id != name) { + if (id != name_) { cerr << "ERROR. State condition specifier " << id << " is not recognized!" << endl; exit(EXIT_FAILURE); @@ -569,22 +618,34 @@ pressureOutlet::pressureOutlet(string &str, const string name) { // parameter counters auto tagCount = 0; auto pressureCount = 0; + auto nonreflectingCount = 0; + auto lengthCount = 0; + nonreflecting_ = false; + specifiedReflecting_ = false; for (auto &token : tokens) { auto param = Tokenize(token, "="); if (param.size() != 2) { - cerr << "ERROR. Problem with " << name << " parameter " << token << endl; + cerr << "ERROR. Problem with " << name_ << " parameter " << token << endl; exit(EXIT_FAILURE); } if (param[0] == "pressure") { pressure_ = stod(RemoveTrailing(param[1], ",")); pressureCount++; + } else if (param[0] == "nonreflecting") { + auto reflect = RemoveTrailing(param[1], ","); + nonreflecting_ = (reflect == "true"); + specifiedReflecting_ = true; + nonreflectingCount++; } else if (param[0] == "tag") { this->SetTag(stoi(RemoveTrailing(param[1], ","))); tagCount++; + } else if (param[0] == "lengthScale") { + lengthScale_ = stod(RemoveTrailing(param[1], ",")); + lengthCount++; } else { - cerr << "ERROR. " << name << " specifier " << param[0] + cerr << "ERROR. " << name_ << " specifier " << param[0] << " is not recognized!" << endl; exit(EXIT_FAILURE); } @@ -593,107 +654,35 @@ pressureOutlet::pressureOutlet(string &str, const string name) { // sanity checks // required variables if (pressureCount != 1 || tagCount != 1) { - cerr << "ERROR. For " << name << " pressure and tag must be specified, and " + cerr << "ERROR. For " << name_ << " pressure and tag must be specified, and " << "only specified once." << endl; exit(EXIT_FAILURE); } -} - -void pressureOutlet::Nondimensionalize(const double &rRef, const double &tRef, - const double &lRef, const double &aRef) { - if (!this->IsNondimensional()) { - pressure_ /= rRef * aRef * aRef; - this->SetNondimensional(true); - } -} - -// construct subsonic inflow from string -subsonicInflow::subsonicInflow(string &str) { - const auto start = str.find("(") + 1; - const auto end = str.find(")") - 1; - const auto range = end - start + 1; // +/-1 to ignore () - auto state = str.substr(start, range); - const auto id = str.substr(0, start - 1); - if (id != "subsonicInflow") { - cerr << "ERROR. State condition specifier " << id << " is not recognized!" - << endl; - exit(EXIT_FAILURE); - } - auto tokens = Tokenize(state, ";"); - - // erase portion used so multiple states in same string can easily be found - str.erase(0, end); - - // parameter counters - auto tagCount = 0; - auto densityCount = 0; - auto velocityCount = 0; - auto tiCount = 0; - auto evrCount = 0; - auto mfCount = 0; - - for (auto &token : tokens) { - auto param = Tokenize(token, "=", 1); - if (param.size() != 2) { - cerr << "ERROR. Problem with state condition parameter " << token << endl; - exit(EXIT_FAILURE); - } - - if (param[0] == "density") { - density_ = stod(RemoveTrailing(param[1], ",")); - densityCount++; - } else if (param[0] == "velocity") { - velocity_ = ReadVector(RemoveTrailing(param[1], ",")); - velocityCount++; - } else if (param[0] == "massFractions") { - this->SetSpecifiedMassFractions(); - massFractions_ = ReadMassFractions(RemoveTrailing(param[1], ",")); - mfCount++; - } else if (param[0] == "turbulenceIntensity") { - this->SetSpecifiedTurbulence(); - turbIntensity_ = stod(RemoveTrailing(param[1], ",")); - tiCount++; - } else if (param[0] == "eddyViscosityRatio") { - eddyViscRatio_ = stod(RemoveTrailing(param[1], ",")); - evrCount++; - } else if (param[0] == "tag") { - this->SetTag(stoi(RemoveTrailing(param[1], ","))); - tagCount++; - } else { - cerr << "ERROR. subsonicInlet specifier " << param[0] - << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } - } - - // sanity checks - // required variables - if (densityCount != 1 || velocityCount != 1 || tagCount != 1) { - cerr << "ERROR. For subsonicInlet density, tag, and velocity " - << "must be specified, and only specified once." << endl; + // can only specify nonreflecting and length scale once + if (nonreflectingCount > 1 || lengthCount > 1) { + cerr << "ERROR. For " << name_ << " nonreflecting and/or lengthScale can " + << "only be specified once" << endl; exit(EXIT_FAILURE); } - // optional variables - if (mfCount > 1 || tiCount > 1 || evrCount > 1 || tiCount != evrCount) { - cerr << "ERROR. For subsonicInlet, massFractions, turbulenceIntensity, and " - << "eddyViscosityRatio can only be specified once." << endl; - cerr << "If either turbulenceIntensity or eddyViscosityRatio is specified " - << "the other must be as well." << endl; + if (nonreflecting_ && lengthCount != 1) { + cerr << "ERROR. For " << name_ << " lengthScale must be specified with " + << "nonreflecting" << endl; exit(EXIT_FAILURE); } } -void subsonicInflow::Nondimensionalize(const double &rRef, const double &tRef, +void pressureOutlet::Nondimensionalize(const double &rRef, const double &tRef, const double &lRef, const double &aRef) { if (!this->IsNondimensional()) { - velocity_ /= aRef; - density_ /= rRef; + pressure_ /= rRef * aRef * aRef; + lengthScale_ /= lRef; this->SetNondimensional(true); } } + // construct viscousWall from string -viscousWall::viscousWall(string &str) { +void viscousWall::Read(string &str) { const auto start = str.find("(") + 1; const auto end = str.find(")") - 1; const auto range = end - start + 1; // +/-1 to ignore () @@ -794,7 +783,7 @@ void viscousWall::Nondimensionalize(const double &rRef, const double &tRef, } // construct periodic from string -periodic::periodic(string &str) { +void periodic::Read(string &str) { const auto start = str.find("(") + 1; const auto end = str.find(")") - 1; const auto range = end - start + 1; // +/-1 to ignore () @@ -940,14 +929,16 @@ vector ReadICList(ifstream &inFile, string &str) { list = str.substr(start, range); } - icState ic(list); + icState ic; + ic.Read(list); CheckICTags(icList, ic.Tag()); icList.push_back(ic); auto nextState = list.find("icState"); while (nextState != string::npos) { // there are more states to read list.erase(0, nextState); // remove commas separating states - ic = icState(list); + ic = icState(); + ic.Read(list); CheckICTags(icList, ic.Tag()); icList.push_back(ic); nextState = list.find("icState"); @@ -981,26 +972,26 @@ void AddBCToList(const string &type, vector> &bcList, string &list) { shared_ptr bc(nullptr); if (type == "characteristic") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; + } else if (type == "inlet") { + bc = shared_ptr{std::make_shared()}; } else if (type == "stagnationInlet") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; } else if (type == "pressureOutlet") { - bc = shared_ptr{std::make_shared(list)}; - } else if (type == "subsonicInflow") { - bc = shared_ptr{std::make_shared(list)}; - } else if (type == "subsonicOutflow") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; } else if (type == "supersonicInflow") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; } else if (type == "viscousWall") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; } else if (type == "periodic") { - bc = shared_ptr{std::make_shared(list)}; + bc = shared_ptr{std::make_shared()}; } else { cerr << "ERROR. BC state " << type << " is not recognized!" << endl; exit(EXIT_FAILURE); } + bc->Read(list); + // sanity check -- see if tag already exits for (auto &bcData : bcList) { if (bc->Tag() == bcData->Tag()) { @@ -1015,9 +1006,9 @@ void AddBCToList(const string &type, vector> &bcList, // function to read boundary condition list from string vector> ReadBCList(ifstream &inFile, string &str) { vector> bcList; - vector bcNames {"characteristic", "stagnationInlet", "pressureOutlet", - "subsonicInflow", "subsonicOutflow", "supersonicInflow", "viscousWall", - "periodic"}; + vector bcNames{"characteristic", "inlet", "stagnationInlet", + "pressureOutlet", "supersonicInflow", + "viscousWall", "periodic"}; auto openList = false; do { auto start = openList ? 0 : str.find("<"); diff --git a/src/inviscidFlux.cpp b/src/inviscidFlux.cpp index 3ca170c..876bc68 100644 --- a/src/inviscidFlux.cpp +++ b/src/inviscidFlux.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,437 +14,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include // sqrt -#include -#include -#include // max +#include #include "inviscidFlux.hpp" -#include "eos.hpp" -#include "thermodynamic.hpp" -#include "primVars.hpp" -#include "genArray.hpp" -#include "matrix.hpp" -#include "turbulence.hpp" -#include "utility.hpp" -using std::cout; using std::endl; -using std::cerr; -using std::vector; -using std::string; -using std::max; -using std::copysign; -using std::unique_ptr; - -// flux is a 3D flux in the normal direction of the given face -/* - -F = [rho * vel (dot) area - rho * vel (dot) area * velx + P * areax - rho * vel (dot) area * vely + P * areay - rho * vel (dot) area * velz + P * areaz - rho * vel (dot) area * H - rho * vel (dot) area * k - rho * vel (dot) area * w] - -rho -- density -vel -- velocity vector (3D) -area -- area vector (3D) -P -- pressure -H -- enthalpy -velx, vely, velz -- velocity components -areax, areay, areaz -- area components -k -- turbulence kinetic energy -w -- specific turbulent dissipation - -Constructor is put in a private member function because identical code is -used for constructing from primative variables and conservative variables -once the conservative variables have been changed to primative variables. -The C++11 way of delegating constructors is not used because the primVars -class is not fully defined in the inviscidFlux.hpp header. This way both -constructors (primVars version and genArray version) can call this function -to avoid code duplication. -*/ -void inviscidFlux::ConstructFromPrim(const primVars &state, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &normArea) { - // state -- primative variables - // eqnState -- equation of state - // normArea -- unit area vector of face - - const auto vel = state.Velocity(); - const auto velNorm = vel.DotProd(normArea); - - data_[0] = state.Rho() * velNorm; - data_[1] = state.Rho() * velNorm * vel.X() + state.P() * normArea.X(); - data_[2] = state.Rho() * velNorm * vel.Y() + state.P() * normArea.Y(); - data_[3] = state.Rho() * velNorm * vel.Z() + state.P() * normArea.Z(); - data_[4] = state.Rho() * velNorm * state.Enthalpy(eqnState, thermo); - - data_[5] = state.Rho() * velNorm * state.Tke(); - data_[6] = state.Rho() * velNorm * state.Omega(); -} - -inviscidFlux::inviscidFlux(const primVars &state, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &normArea) { - // state -- primative variables - // eqnState -- equation of state - // normArea -- unit area vector of face - - this->ConstructFromPrim(state, eqnState, thermo, normArea); -} - -// constructor -- initialize flux from state vector using conservative variables -// flux is a 3D flux in the normal direction of the given face -inviscidFlux::inviscidFlux(const genArray &cons, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &turb, - const vector3d &normArea) { - // cons -- genArray of conserved variables - // eqnState -- equation of state - // turb -- turbulence model - // normArea -- unit area vector of face - - // convert conserved variables to primative variables - const primVars state(cons, false, eqnState, thermo, turb); - - this->ConstructFromPrim(state, eqnState, thermo, normArea); -} - -/* Function to calculate inviscid flux using Roe's approximate Riemann solver. -The function takes in the primative varibles constructed -from the left and right states, an equation of state, a face area vector, and -outputs the inviscid flux as well as the maximum wave speed. -The function uses Harten's entropy fix to correct wave speeds near 0 and near -sonic. -__________________________________________ -| | Ul|Ur | | -| | | | | -| Ui-1 | Ui Ua Ui+1 | Ui+2 | -| | | | | -| | | | | -|_________|_________|__________|_________| - -In the diagram above, Ul and Ur represent the reconstructed states, which for -the MUSCL scheme (1st and 2nd order) come from the stencil shown -above. Ua represents the average state at the face at which the flux will be -calculated. In this case it is a Roe average. Once the average -state has been calculated, the Roe flux can be calculated using the following -equation. - -F = 1/2 * (Fl + Fr - D) - -F represents the calculated Roe flux at the given face. Fl is the inviscid flux -calculated from the reconstructed state Ul. Fr is the inviscid -flux calculated from the reconstructed state Ur. D is the dissipation term which -is calculated using the Roe averaged state, as well as the -eigen values and eigen vectors resulting from the Roe linearization. - -D = A * (Ur - Ul) = T * L * T^-1 * (Ur - Ul) = T * L * (Cr - Cl) - -A is the linearized Roe matrix. It is equal to the convective flux jacobian -(dF/dU) calculated with the Roe averaged state. The linearization -essentially states that the flux jacobian (which is the change in flux over -change in state) mulitplied by the change in state is equal to the -change in flux. The change in flux is then added to the average of the physical -right and left fluxes (central difference). The Roe matrix, A, -can be diagonalized where T and T^-1 are the right and left eigenvectors -respectively and L is the eigenvalues. T^-1 multiplied by the change in -state results in the change in characteristic wave amplitude (Cr - Cl), or wave -strength. In its final form (right most) T represents the -characteristic waves, L represents the wave speeds, and (Cr - Cl) represents the -wave strength across the face. - -*/ -inviscidFlux RoeFlux(const primVars &left, const primVars &right, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &areaNorm) { - // left -- primative variables from left - // right -- primative variables from right - // eqnState -- equation of state - // areaNorm -- norm area vector of face - - // compute Rho averaged quantities - // Roe averaged state - const auto roe = RoeAveragedState(left, right); - - // Roe averaged total enthalpy - const auto hR = roe.Enthalpy(eqnState, thermo); - - // Roe averaged speed of sound - const auto aR = roe.SoS(thermo, eqnState); - - // Roe velocity dotted with normalized area vector - const auto velRSum = roe.Velocity().DotProd(areaNorm); - - // Delta between right and left states - const auto delta = right - left; - - // normal velocity difference between left and right states - const auto normVelDiff = delta.Velocity().DotProd(areaNorm); - - // calculate wave strengths (Cr - Cl) - const double waveStrength[NUMVARS - 1] = { - (delta.P() - roe.Rho() * aR * normVelDiff) / (2.0 * aR * aR), - delta.Rho() - delta.P() / (aR * aR), - (delta.P() + roe.Rho() * aR * normVelDiff) / (2.0 * aR * aR), - roe.Rho(), - roe.Rho() * delta.Tke() + roe.Tke() * delta.Rho() - delta.P() * roe.Tke() - / (aR * aR), - roe.Rho() * delta.Omega() + roe.Omega() * delta.Rho() - - delta.P() * roe.Omega() / (aR * aR)}; - - // calculate absolute value of wave speeds (L) - double waveSpeed[NUMVARS - 1] = { - fabs(velRSum - aR), // left moving acoustic wave speed - fabs(velRSum), // entropy wave speed - fabs(velRSum + aR), // right moving acoustic wave speed - fabs(velRSum), // shear wave speed - fabs(velRSum), // turbulent eqn 1 (k) wave speed - fabs(velRSum)}; // turbulent eqn 2 (omega) wave speed - - // calculate entropy fix (Harten) and adjust wave speeds if necessary - // default setting for entropy fix to kick in - constexpr auto entropyFix = 0.1; - - if (waveSpeed[0] < entropyFix) { - waveSpeed[0] = 0.5 * (waveSpeed[0] * waveSpeed[0] / - entropyFix + entropyFix); - } - if (waveSpeed[2] < entropyFix) { - waveSpeed[2] = 0.5 * (waveSpeed[2] * waveSpeed[2] / - entropyFix + entropyFix); - } - - // calculate right eigenvectors (T) - // calculate eigenvector due to left acoustic wave - const genArray lAcousticEigV(1.0, roe.U() - aR * areaNorm.X(), - roe.V() - aR * areaNorm.Y(), - roe.W() - aR * areaNorm.Z(), - hR - aR * velRSum, roe.Tke(), roe.Omega()); - - // calculate eigenvector due to entropy wave - const genArray entropyEigV(1.0, roe.U(), roe.V(), roe.W(), - 0.5 * roe.Velocity().MagSq(), - 0.0, 0.0); - - // calculate eigenvector due to right acoustic wave - const genArray rAcousticEigV(1.0, roe.U() + aR * areaNorm.X(), - roe.V() + aR * areaNorm.Y(), - roe.W() + aR * areaNorm.Z(), - hR + aR * velRSum, roe.Tke(), roe.Omega()); - - // calculate eigenvector due to shear wave - const genArray shearEigV(0.0, - delta.U() - normVelDiff * areaNorm.X(), - delta.V() - normVelDiff * areaNorm.Y(), - delta.W() - normVelDiff * areaNorm.Z(), - roe.Velocity().DotProd(delta.Velocity()) - - velRSum * normVelDiff, - 0.0, 0.0); - - // calculate eigenvector due to turbulent equation 1 - const genArray tkeEigV(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - - // calculate eigenvector due to turbulent equation 2 - const genArray omgEigV(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); - - // calculate dissipation term ( eigenvector * wave speed * wave strength) - genArray dissipation(0.0); - for (auto ii = 0; ii < NUMVARS; ii++) { - // contribution from left acoustic wave - // contribution from entropy wave - // contribution from right acoustic wave - // contribution from shear wave - // contribution from turbulent wave 1 - // contribution from turbulent wave 2 - dissipation[ii] = waveSpeed[0] * waveStrength[0] * lAcousticEigV[ii] + - waveSpeed[1] * waveStrength[1] * entropyEigV[ii] + - waveSpeed[2] * waveStrength[2] * rAcousticEigV[ii] + - waveSpeed[3] * waveStrength[3] * shearEigV[ii] + - waveSpeed[4] * waveStrength[4] * tkeEigV[ii] + - waveSpeed[5] * waveStrength[5] * omgEigV[ii]; - } - - // calculate left/right physical flux - inviscidFlux leftFlux(left, eqnState, thermo, areaNorm); - inviscidFlux rightFlux(right, eqnState, thermo, areaNorm); - - // calculate numerical Roe flux - leftFlux.RoeFlux(rightFlux, dissipation); - - return leftFlux; -} - -/* Function to calculate the AUSMPW+ flux as described in "Accurate Compuations - of Hypersonic Flows Using AUSMPW+ Scheme and Shock-Aligned Grid Technique". - by Kim, Kim, & Rho. AIAA 1998. Unlike the Roe scheme, this flux scheme is an - example of flux vector splitting instead of flux difference splitting. - Although more dissipative, it has shown good performance in the high speed - regime where the Roe scheme can suffer from carbuncle problems. The flux is - split into the convective and pressure terms, which are then split based on - the mach number and pressure. The flux discretization is shown below. - - F = M^+_l * c * F_cl + M^-_r * c * F_cr + P^+_l * P_l + P^-_r * P_r -*/ -inviscidFlux AUSMFlux(const primVars &left, const primVars &right, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &area) { - // left -- primative variables from left - // right -- primative variables from right - // eqnState -- equation of state - // thermo -- thermodynamic model - // area -- norm area vector of face - - // calculate average specific enthalpy on face - const auto tl = left.Temperature(eqnState); - const auto tr = right.Temperature(eqnState); - const auto hl = thermo->SpecEnthalpy(tl); - const auto hr = thermo->SpecEnthalpy(tr); - const auto h = 0.5 * (hl + hr); - - // calculate c* from Kim, Kim, Rho 1998 - const auto t = 0.5 * (tl + tr); - const auto sosStar = - sqrt(2.0 * h * (thermo->Gamma(t) - 1.0) / (thermo->Gamma(t) + 1.0)); - - // calculate left/right mach numbers - const auto vell = left.Velocity().DotProd(area); - const auto velr = right.Velocity().DotProd(area); - const auto ml = vell / sosStar; - const auto mr = velr / sosStar; - - // calculate speed of sound on face c_1/2 from Kim, Kim, Rho 1998 - const auto vel = 0.5 * (vell + velr); - auto sos = 0.0; - if (vel < 0.0) { - sos = sosStar * sosStar / std::max(vell, sosStar); - } else if (vel > 0.0) { - sos = sosStar * sosStar / std::max(velr, sosStar); - } - - // calculate split mach number and pressure terms - const auto mPlusL = - fabs(ml) <= 1.0 ? 0.25 * pow(ml + 1.0, 2.0) : 0.5 * (ml + fabs(ml)); - const auto mMinusR = - fabs(mr) <= 1.0 ? -0.25 * pow(mr - 1.0, 2.0) : 0.5 * (mr - fabs(mr)); - const auto pPlus = fabs(ml) <= 1.0 ? 0.25 * pow(ml + 1.0, 2.0) * (2.0 - ml) - : 0.5 * (1.0 + Sign(ml)); - const auto pMinus = fabs(mr) <= 1.0 ? 0.25 * pow(mr - 1.0, 2.0) * (2.0 + mr) - : 0.5 * (1.0 - Sign(mr)); - - // calculate pressure weighting terms - const auto ps = pPlus * left.P() + pMinus * right.P(); - const auto w = - 1.0 - pow(std::min(left.P() / right.P(), right.P() / left.P()), 3.0); - const auto fl = fabs(ml) < 1.0 ? left.P() / ps - 1.0 : 0.0; - const auto fr = fabs(mr) < 1.0 ? right.P() / ps - 1.0 : 0.0; - - // calculate final split properties - const auto mavg = mPlusL + mMinusR; - const auto mPlusLBar = mavg >= 0.0 - ? mPlusL + mMinusR * ((1.0 - w) * (1.0 + fr) - fl) - : mPlusL * w * (1.0 + fl); - const auto mMinusRBar = - mavg >= 0.0 ? mMinusR * w * (1.0 + fr) - : mMinusR + mPlusL * ((1.0 - w) * (1.0 + fl) - fr); - - inviscidFlux ausm; - ausm.AUSMFlux(left, right, eqnState, thermo, area, sos, mPlusLBar, mMinusRBar, - pPlus, pMinus); - return ausm; -} - -void inviscidFlux::AUSMFlux(const primVars &left, const primVars &right, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &area, - const double &sos, const double &mPlusLBar, - const double &mMinusRBar, const double &pPlus, - const double &pMinus) { - // calculate left flux - const auto vl = mPlusLBar * sos; - data_[0] = left.Rho() * vl; - data_[1] = left.Rho() * vl * left.U() + pPlus * left.P() * area.X(); - data_[2] = left.Rho() * vl * left.V() + pPlus * left.P() * area.Y(); - data_[3] = left.Rho() * vl * left.W() + pPlus * left.P() * area.Z(); - data_[4] = left.Rho() * vl * left.Enthalpy(eqnState, thermo); - data_[5] = left.Rho() * vl * left.Tke(); - data_[6] = left.Rho() * vl * left.Omega(); - - // calculate right flux (add contribution) - const auto vr = mMinusRBar * sos; - data_[0] += right.Rho() * vr; - data_[1] += right.Rho() * vr * right.U() + pMinus * right.P() * area.X(); - data_[2] += right.Rho() * vr * right.V() + pMinus * right.P() * area.Y(); - data_[3] += right.Rho() * vr * right.W() + pMinus * right.P() * area.Z(); - data_[4] += right.Rho() * vr * right.Enthalpy(eqnState, thermo); - data_[5] += right.Rho() * vr * right.Tke(); - data_[6] += right.Rho() * vr * right.Omega(); -} - -inviscidFlux InviscidFlux(const primVars &left, const primVars &right, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &area, const string &flux) { - inviscidFlux invFlux; - if (flux == "roe") { - invFlux = RoeFlux(left, right, eqnState, thermo, area); - } else if (flux == "ausm") { - invFlux = AUSMFlux(left, right, eqnState, thermo, area); - } else { - cerr << "ERROR: inviscid flux type " << flux << " is not recognized!" - << endl; - cerr << "Choose 'roe' or 'ausm'" << endl; - exit(EXIT_FAILURE); - } - return invFlux; -} - -inviscidFlux RusanovFlux(const primVars &left, const primVars &right, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &areaNorm, - const bool &positive) { - // left -- primative variables from left - // right -- primative variables from right - // eqnState -- equation of state - // thermo -- thermodynamic model - // areaNorm -- norm area vector of face - // positive -- flag that is positive to add spectral radius - - // calculate maximum spectral radius - const auto leftSpecRad = - fabs(left.Velocity().DotProd(areaNorm)) + left.SoS(thermo, eqnState); - const auto rightSpecRad = - fabs(right.Velocity().DotProd(areaNorm)) + right.SoS(thermo, eqnState); - const auto fac = positive ? -1.0 : 1.0; - const auto specRad = fac * std::max(leftSpecRad, rightSpecRad); - - // calculate left/right physical flux - inviscidFlux leftFlux(left, eqnState, thermo, areaNorm); - inviscidFlux rightFlux(right, eqnState, thermo, areaNorm); - - return 0.5 * (leftFlux + rightFlux - specRad); -} - +using std::ostream; /* Member function to calculate the Roe flux, given the left and right * convective fluxes as well as the dissipation term. */ -void inviscidFlux::RoeFlux(const inviscidFlux &right, const genArray &diss) { +void inviscidFlux::RoeFlux(const inviscidFlux &right, const varArray &diss) { // right -- right convective flux // diss -- dissipation term - for (auto ii = 0; ii < NUMVARS; ii++) { - data_[ii] = 0.5 * (data_[ii] + right.data_[ii] - diss[ii]); - } + (*this) += right - diss; + (*this) *= 0.5; } // non-member functions @@ -452,39 +36,9 @@ void inviscidFlux::RoeFlux(const inviscidFlux &right, const genArray &diss) { // operator overload for << - allows use of cout, cerr, etc. ostream &operator<<(ostream &os, const inviscidFlux &flux) { - os << flux.RhoVel() << endl; - os << flux.RhoVelU() << endl; - os << flux.RhoVelV() << endl; - os << flux.RhoVelW() << endl; - os << flux.RhoVelH() << endl; - os << flux.RhoVelK() << endl; - os << flux.RhoVelO() << endl; + for (auto rr = 0; rr < flux.Size(); rr++) { + os << flux[rr] << endl; + } return os; } -// convert the inviscid flux to a genArray -genArray inviscidFlux::ConvertToGenArray() const { - return genArray(this->RhoVel(), this->RhoVelU(), this->RhoVelV(), - this->RhoVelW(), this->RhoVelH(), this->RhoVelK(), - this->RhoVelO()); -} - -// function to take in the primative variables, equation of state, face area -// vector, and conservative variable update and calculate the change in the -// convective flux -genArray ConvectiveFluxUpdate(const primVars &state, - const primVars &stateUpdate, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const vector3d &normArea) { - // get inviscid flux of old state - const inviscidFlux oldFlux(state, eqnState, thermo, normArea); - - // get updated inviscid flux - const inviscidFlux newFlux(stateUpdate, eqnState, thermo, normArea); - - // calculate difference in flux - const auto dFlux = newFlux - oldFlux; - - return dFlux.ConvertToGenArray(); -} diff --git a/src/kdtree.cpp b/src/kdtree.cpp index f9a07bb..d41e0f8 100644 --- a/src/kdtree.cpp +++ b/src/kdtree.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ kdtree::kdtree(const vector> &points) { // points -- all points to search through, stored in kdtree nodes_.resize(points.size()); - for (auto ii = 0; ii < nodes_.size(); ++ii) { + for (auto ii = 0U; ii < nodes_.size(); ++ii) { nodes_[ii] = std::make_pair(points[ii], ii); } right_ = vector(points.size(), -1); diff --git a/src/limiter.cpp b/src/limiter.cpp new file mode 100644 index 0000000..fb9f58f --- /dev/null +++ b/src/limiter.cpp @@ -0,0 +1,54 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include "limiter.hpp" +#include "primitive.hpp" + + +// function to calculate minmod limiter +primitive LimiterMinmod(const primitive &r) { + // r -- ratio of divided differences + + primitive limiter(r.Size(), r.NumSpecies()); + // calculate minmod limiter + for (auto ii = 0; ii < limiter.Size(); ++ii) { + limiter[ii] = std::max(0.0, std::min(1.0, r[ii])); + } + return limiter; +} + +// function to calculate Van Albada limiter +primitive LimiterVanAlbada(const primitive &r) { + // r -- ratio of divided differences + + const auto r2 = r * r; + auto limiter = (r + r2) / (1.0 + r2); + // if value is negative, return zero + for (auto ii = 0; ii < limiter.Size(); ++ii) { + limiter[ii] = std::max(0.0, limiter[ii]); + } + return limiter; +} + +// function to return no limiter +primitive LimiterNone(const int &numEq, const int &numSpec) { + // for no limiter return all 1s + primitive limiter(numEq, numSpec, 1.0); + return limiter; +} + diff --git a/src/main.cpp b/src/main.cpp index 7b185b6..4cdcb37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,20 +30,19 @@ #include "vector3d.hpp" #include "input.hpp" #include "procBlock.hpp" -#include "primVars.hpp" -#include "eos.hpp" -#include "transport.hpp" +#include "primitive.hpp" +#include "physicsModels.hpp" #include "thermodynamic.hpp" #include "boundaryConditions.hpp" #include "output.hpp" -#include "genArray.hpp" +#include "varArray.hpp" #include "parallel.hpp" -#include "turbulence.hpp" #include "resid.hpp" #include "multiArray3d.hpp" #include "kdtree.hpp" #include "fluxJacobian.hpp" #include "utility.hpp" +#include "matMultiArray3d.hpp" using std::cout; using std::cerr; @@ -109,24 +108,18 @@ int main(int argc, char *argv[]) { // nondimensionalize fluid data inp.NondimensionalizeFluid(); - // Get thermodynamic model - const auto thermo = inp.AssignThermodynamicModel(); - // Get equation of state - const auto eqnState = inp.AssignEquationOfState(thermo); - // Get transport model - const auto trans = inp.AssignTransportModel(); + // Get physics models + const auto phys = inp.AssignPhysicsModels(); // Nondimensionalize BC & IC data - inp.NondimensionalizeStateData(eqnState); - - // Get turbulence model - const auto turb = inp.AssignTurbulenceModel(); + inp.NondimensionalizeStateData(phys.EoS()); vector mesh; vector connections; vector stateBlocks; vector> viscFaces; - genArray residL2First(0.0); // l2 norm residuals to normalize by + // l2 norm residuals to normalize by + residual residL2First(inp.NumEquations(), inp.NumSpecies()); if (rank == ROOTP) { cout << "Number of equations: " << inp.NumEquations() << endl << endl; @@ -162,13 +155,13 @@ int main(int argc, char *argv[]) { stateBlocks[ll] = procBlock(mesh[ll], decomp.ParentBlock(ll), bcs[ll], ll, decomp.Rank(ll), decomp.LocalPosition(ll), inp); - stateBlocks[ll].InitializeStates(inp, eqnState, trans, turb); + stateBlocks[ll].InitializeStates(inp, phys); stateBlocks[ll].AssignGhostCellsGeom(); } // if restart, get data from restart file if (inp.IsRestart()) { - ReadRestart(stateBlocks, restartFile, decomp, inp, eqnState, thermo, - trans, turb, residL2First, gridSizes); + ReadRestart(stateBlocks, restartFile, decomp, inp, phys, residL2First, + gridSizes); } // Swap geometry for connection BCs @@ -189,24 +182,22 @@ int main(int argc, char *argv[]) { } // Set MPI datatypes - MPI_Datatype MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, MPI_uncoupledScalar, - MPI_tensorDouble, MPI_wallData; - SetDataTypesMPI(MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, - MPI_uncoupledScalar, MPI_tensorDouble, MPI_wallData); + MPI_Datatype MPI_vec3d, MPI_procBlockInts, MPI_connection, MPI_DOUBLE_5INT, + MPI_vec3dMag, MPI_uncoupledScalar, MPI_tensorDouble; + SetDataTypesMPI(MPI_vec3d, MPI_procBlockInts, MPI_connection, MPI_DOUBLE_5INT, + MPI_vec3dMag, MPI_uncoupledScalar, MPI_tensorDouble); // Send number of procBlocks to all processors SendNumProcBlocks(decomp.NumBlocksOnAllProc(), numProcBlock); // Send procBlocks to appropriate processor - auto localStateBlocks = SendProcBlocks(stateBlocks, rank, numProcBlock, - MPI_cellData, MPI_vec3d, MPI_vec3dMag, - MPI_wallData, inp); + auto localStateBlocks = + SendProcBlocks(stateBlocks, rank, numProcBlock, MPI_vec3d, MPI_vec3dMag, + inp); // Update auxillary variables (temperature, viscosity, etc), cell widths for (auto &block : localStateBlocks) { - block.UpdateAuxillaryVariables(eqnState, trans, false); + block.UpdateAuxillaryVariables(phys, false); block.CalcCellWidths(); } @@ -256,15 +247,14 @@ int main(int argc, char *argv[]) { //----------------------------------------------------------------------- // Allocate array for flux jacobian - vector> mainDiagonal(numProcBlock); + vector mainDiagonal(numProcBlock); if (inp.IsImplicit()) { ResizeArrays(localStateBlocks, inp, mainDiagonal); } // Send/recv solutions - necessary to get wall distances - GetProcBlocks(stateBlocks, localStateBlocks, rank, MPI_cellData, - MPI_uncoupledScalar, MPI_vec3d, MPI_tensorDouble, MPI_wallData, - inp); + GetProcBlocks(stateBlocks, localStateBlocks, rank, MPI_uncoupledScalar, + MPI_vec3d, MPI_tensorDouble, inp); ofstream resFile; if (rank == ROOTP) { @@ -283,8 +273,7 @@ int main(int argc, char *argv[]) { WriteCellCenter(inp.GridName(), stateBlocks, decomp, inp); // Write out initial results - WriteFun(stateBlocks, eqnState, thermo, trans, inp.IterationStart(), decomp, - inp, turb); + WriteFun(stateBlocks, phys, inp.IterationStart(), decomp, inp); WriteMeta(inp, inp.IterationStart()); } @@ -300,7 +289,7 @@ int main(int argc, char *argv[]) { // Store time-n solution, for time integration methods that require it if (inp.NeedToStoreTimeN()) { - AssignSolToTimeN(localStateBlocks, eqnState, thermo); + AssignSolToTimeN(localStateBlocks, phys); if (!inp.IsRestart() && inp.IsMultilevelInTime() && nn == 0) { AssignSolToTimeNm1(localStateBlocks); } @@ -309,32 +298,30 @@ int main(int argc, char *argv[]) { // loop over nonlinear iterations for (auto mm = 0; mm < inp.NonlinearIterations(); mm++) { // Get boundary conditions for all blocks - GetBoundaryConditions(localStateBlocks, inp, eqnState, thermo, trans, - turb, connections, rank, MPI_cellData); + GetBoundaryConditions(localStateBlocks, inp, phys, connections, rank); // Calculate residual (RHS) - CalcResidual(localStateBlocks, mainDiagonal, trans, thermo, eqnState, inp, - turb, connections, rank, MPI_tensorDouble, MPI_vec3d); + CalcResidual(localStateBlocks, mainDiagonal, phys, inp, connections, rank, + MPI_tensorDouble, MPI_vec3d); // Calculate time step CalcTimeStep(localStateBlocks, inp); // Initialize residual variables - genArray residL2(0.0); // l2 norm residuals + // l2 norm residuals + residual residL2(inp.NumEquations(), inp.NumSpecies()); resid residLinf; // linf residuals auto matrixResid = 0.0; if (inp.IsImplicit()) { - matrixResid = ImplicitUpdate( - localStateBlocks, mainDiagonal, inp, eqnState, thermo, trans, turb, - mm, residL2, residLinf, connections, rank, MPI_cellData); + matrixResid = ImplicitUpdate(localStateBlocks, mainDiagonal, inp, phys, + mm, residL2, residLinf, connections, rank); } else { // explicit time integration - ExplicitUpdate(localStateBlocks, inp, eqnState, thermo, trans, turb, mm, - residL2, residLinf); + ExplicitUpdate(localStateBlocks, inp, phys, mm, residL2, residLinf); } // ---------------------------------------------------------------------- // Get residuals from all processors - residL2.GlobalReduceMPI(rank, inp.NumEquations()); + residL2.GlobalReduceMPI(rank); residLinf.GlobalReduceMPI(rank, MPI_DOUBLE_5INT, MPI_MAX_LINF); // Get matrix residuals from all processors @@ -362,25 +349,23 @@ int main(int argc, char *argv[]) { // write out function file if (inp.WriteOutput(nn) || inp.WriteRestart(nn)) { // Send/recv solutions - GetProcBlocks(stateBlocks, localStateBlocks, rank, MPI_cellData, - MPI_uncoupledScalar, MPI_vec3d, MPI_tensorDouble, - MPI_wallData, inp); + GetProcBlocks(stateBlocks, localStateBlocks, rank, MPI_uncoupledScalar, + MPI_vec3d, MPI_tensorDouble, inp); if (rank == ROOTP && inp.WriteOutput(nn)) { cout << "writing out function file at iteration " << nn + inp.IterationStart()<< endl; // Write out function file - WriteFun(stateBlocks, eqnState, thermo, trans, - (nn + inp.IterationStart() + 1), decomp, inp, turb); + WriteFun(stateBlocks, phys, (nn + inp.IterationStart() + 1), decomp, + inp); WriteMeta(inp, (nn + inp.IterationStart() + 1)); } if (rank == ROOTP && inp.WriteRestart(nn)) { cout << "writing out restart file at iteration " << nn + inp.IterationStart()<< endl; // Write out restart file - WriteRestart(stateBlocks, eqnState, trans, - (nn + inp.IterationStart() + 1), decomp, inp, - residL2First); + WriteRestart(stateBlocks, phys, (nn + inp.IterationStart() + 1), decomp, + inp, residL2First); } } } // loop for time step ----------------------------------------------------- @@ -398,9 +383,9 @@ int main(int argc, char *argv[]) { } // Free datatypes previously created - FreeDataTypesMPI(MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, - MPI_uncoupledScalar, MPI_tensorDouble, MPI_wallData); + FreeDataTypesMPI(MPI_vec3d, MPI_procBlockInts, MPI_connection, + MPI_DOUBLE_5INT, MPI_vec3dMag, MPI_uncoupledScalar, + MPI_tensorDouble); MPI_Finalize(); diff --git a/src/matMultiArray3d.cpp b/src/matMultiArray3d.cpp new file mode 100644 index 0000000..18003f5 --- /dev/null +++ b/src/matMultiArray3d.cpp @@ -0,0 +1,70 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include // cout +#include +#include "matMultiArray3d.hpp" + +using std::cout; +using std::endl; +using std::cerr; +using std::vector; + +// operation overload for << - allows use of cout, cerr, etc. +ostream &operator<<(ostream &os, const matMultiArray3d &arr) { + os << "Size: " << arr.NumI() << ", " << arr.NumJ() << ", " << arr.NumK() + << endl; + os << "Number of ghost layers: " << arr.GhostLayers() << endl; + + auto GetVal = [](const auto &mat, const int &r, const int &c, + const int &size) -> decltype(auto) { + return *(mat + r * size + c); + }; + + for (auto kk = arr.StartK(); kk < arr.EndK(); ++kk) { + for (auto jj = arr.StartJ(); jj < arr.EndJ(); ++jj) { + for (auto ii = arr.StartI(); ii < arr.EndI(); ++ii) { + os << ii << ", " << jj << ", " << kk << endl; + + // print flow jacobian + for (auto rf = 0; rf < arr.FlowSize(); ++rf) { + for (auto cf = 0; cf < arr.FlowSize(); ++cf) { + os << GetVal(arr.begin() + arr.GetLoc1D(ii, jj, kk), rf, cf, + arr.FlowSize()) + << " "; + if (cf == arr.FlowSize() - 1) { + os << endl; + } + } + } + + // print turbulence jacobian + for (auto rt = 0; rt < arr.TurbSize(); ++rt) { + for (auto ct = 0; ct < arr.TurbSize(); ++ct) { + os << GetVal(arr.begin() + arr.GetLoc1D(ii, jj, kk) + + arr.FlowSize() * arr.FlowSize(), + rt, ct, arr.FlowSize()) + << " "; + if (ct == arr.TurbSize() - 1) { + os << endl; + } + } + } + } + } + } + return os; +} diff --git a/src/matrix.cpp b/src/matrix.cpp index 323e82e..f0f4252 100644 --- a/src/matrix.cpp +++ b/src/matrix.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,183 +19,219 @@ #include // cout #include // swap #include "matrix.hpp" -#include "genArray.hpp" +#include "varArray.hpp" using std::cout; using std::endl; using std::cerr; -using std::copy; -using std::swap_ranges; -// member function to swap rows of matrix -void squareMatrix::SwapRows(const int &r1, const int &r2) { - if (r1 != r2) { - for (auto cc = 0; cc < size_; cc++) { - std::swap((*this)(r1, cc), (*this)(r2, cc)); +// operator overload for multiplication +// using cache efficient implimentation +squareMatrix squareMatrix::MatMult(const squareMatrix &s2) const { + MSG_ASSERT(this->Size() == s2.Size(), "matrix size mismatch"); + squareMatrix result(s2.Size()); + MatrixMultiply(this->begin(), s2.begin(), result.begin(), this->Size()); + return result; +} + +// operation overload for << - allows use of cout, cerr, etc. +ostream &operator<<(ostream &os, const squareMatrix &m) { + for (auto rr = 0; rr < m.Size(); rr++) { + for (auto cc = 0; cc < m.Size(); cc++) { + os << m(rr, cc); + if (cc != (m.Size() - 1)) { + os << ", "; + } else { + os << endl; + } } } + return os; } -// member function to invert matrix using Gauss-Jordan elimination -void squareMatrix::Inverse() { - squareMatrix I(size_); + +// --------------------------------------------------------------------------- +// generic matrix functions + +// function to invert matrix using Gauss-Jordan elimination +void MatrixInverse(const vector::iterator &mat, const int &size) { + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + + squareMatrix I(size); I.Identity(); - for (auto cPivot = 0, r = 0; r < size_; r++, cPivot++) { + for (auto cPivot = 0, r = 0; r < size; ++r, ++cPivot) { // find pivot row - auto rPivot = this->FindMaxInCol(r, cPivot, size_ - 1); + auto rPivot = FindMaxInColumn(mat, size, r, cPivot, size - 1); // swap rows - this->SwapRows(r, rPivot); + SwapMatRows(mat, size, r, rPivot); I.SwapRows(r, rPivot); - if (r != 0) { // if not on first row, need to get rid entries ahead of - // pivot - for (auto ii = 0; ii < cPivot; ii++) { - auto factor = (*this)(r, ii) / (*this)(ii, ii); - this->LinCombRow(ii, factor, r); + if (r != 0) { // if not first row, need to get rid entries ahead of pivot + for (auto ii = 0; ii < cPivot; ++ii) { + auto factor = GetVal(mat, r, ii) / GetVal(mat, ii, ii); + LinearCombRow(mat, size, ii, factor, r); I.LinCombRow(ii, factor, r); } } // normalize row by pivot - if ((*this)(r, cPivot) == 0.0) { - cerr << "ERROR: Singular matrix in Gauss-Jordan elimination! Matrix (mid " - "inversion) is" << endl << *this << endl; + if (GetVal(mat, r, cPivot) == 0.0) { + cerr << "ERROR: Singular matrix in Gauss-Jordan elimination!" << endl; exit(EXIT_FAILURE); } - auto normFactor = 1.0 / (*this)(r, cPivot); - this->RowMultiply(r, cPivot, normFactor); // only multiply entries from - // pivot and to the right + // only normalize entries from pivot and to the right + auto normFactor = 1.0 / GetVal(mat, r, cPivot); + RowMultiplyFactor(mat, size, r, cPivot, normFactor); I.RowMultiply(r, 0, normFactor); // multiply all entries } // matrix is now upper triangular, work way back up to identity matrix // start with second to last row - for (auto cPivot = size_ - 2, r = size_ - 2; r >= 0; r--, cPivot--) { - for (auto ii = size_ - 1; ii > cPivot; ii--) { - auto factor = (*this)(r, ii); - this->LinCombRow(ii, factor, r); + for (auto cPivot = size - 2, r = size - 2; r >= 0; --r, --cPivot) { + for (auto ii = size - 1; ii > cPivot; --ii) { + auto factor = GetVal(mat, r, ii); + LinearCombRow(mat, size, ii, factor, r); I.LinCombRow(ii, factor, r); } } - // set this matrix equal to its inverse - (*this) = I; + // set matrix equal to its inverse + std::copy(I.begin(), I.end(), mat); } -// member function to add a linear combination of one row to another -void squareMatrix::LinCombRow(const int &r1, const double &factor, - const int &r2) { - for (auto ii = 0; ii < size_; ii++) { - (*this)(r2, ii) = (*this)(r2, ii) - (*this)(r1, ii) * factor; +// member function to swap rows of matrix +void SwapMatRows(const vector::iterator &mat, const int &size, + const int &r1, const int &r2) { + MSG_ASSERT(r1 < size && r2 < size, "index outside of range"); + if (r1 != r2) { + auto GetLoc = [&size](const int &r, const int &c) -> decltype(auto) { + return r * size + c; + }; + std::swap_ranges(mat + GetLoc(r1, 0), + mat + GetLoc(r1, size), + mat + GetLoc(r2, 0)); } } -// member function to multiply a row by a given factor -void squareMatrix::RowMultiply(const int &r, const int &c, - const double &factor) { - for (auto ii = c; ii < size_; ii++) { - (*this)(r, ii) = (*this)(r, ii) * factor; - } +// function to add a linear combination of one row to another +void LinearCombRow(const vector::iterator &mat, const int &size, + const int &r1, const double &factor, const int &r2) { + MSG_ASSERT(r1 < size && r2 < size, "index outside of range"); + auto GetLoc = [&size](const int &r, const int &c) -> decltype(auto) { + return r * size + c; + }; + std::transform( + mat + GetLoc(r2, 0), mat + GetLoc(r2, size), mat + GetLoc(r1, 0), + mat + GetLoc(r2, 0), + [&factor](const auto &v1, const auto &v2) { return v1 - factor * v2; }); } -// member function to find maximum absolute value in a given column and range +// function to multiply a row by a given factor +void RowMultiplyFactor(const vector::iterator &mat, const int &size, + const int &r, const int &c, const double &factor) { + MSG_ASSERT(r < size && c < size, "index outside of range"); + auto GetLoc = [&size](const int &r, const int &c) -> decltype(auto) { + return r * size + c; + }; + for_each(mat + GetLoc(r, c), mat + GetLoc(r, size), + [&factor](auto &val) { val *= factor; }); +} + +// function to find maximum absolute value in a given column and range // within that column and return the corresponding row indice -int squareMatrix::FindMaxInCol(const int &c, const int &start, - const int &end) const { +int FindMaxInColumn(const vector::const_iterator &mat, const int &size, + const int &c, const int &start, const int &end) { + MSG_ASSERT(start < size && end < size && c < size, + "index outside of range"); + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + auto maxVal = 0.0; auto maxRow = 0; - for (auto ii = start; ii <= end; ii++) { - if (fabs((*this)(ii, c)) > maxVal) { - maxVal = fabs((*this)(ii, c)); + for (auto ii = start; ii <= end; ++ii) { + if (fabs(GetVal(mat, ii, c)) > maxVal) { + maxVal = fabs(GetVal(mat, ii, c)); maxRow = ii; } } return maxRow; } - -// operator overload for multiplication -// using cache efficient implimentation -squareMatrix squareMatrix::MatMult(const squareMatrix &s2) const { - squareMatrix s1(s2.Size()); - for (auto cc = 0; cc < s2.Size(); cc++) { - for (auto rr = 0; rr < s2.Size(); rr++) { - for (auto ii = 0; ii < s2.Size(); ii++) { - s1(rr, ii) += (*this)(rr, cc) * s2(cc, ii); - } +// member function to set matrix to Identity +void IdentityMatrix(const vector::iterator &mat, const int &size) { + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + for (auto rr = 0; rr < size; ++rr) { + for (auto cc = 0; cc < size; ++cc) { + GetVal(mat, rr, cc) = (rr == cc) ? 1.0 : 0.0; } } - return s1; } -// operation overload for << - allows use of cout, cerr, etc. -ostream &operator<<(ostream &os, const squareMatrix &m) { - for (auto rr = 0; rr < m.Size(); rr++) { - for (auto cc = 0; cc < m.Size(); cc++) { - os << m(rr, cc); - if (cc != (m.Size() - 1)) { - os << ", "; - } else { - os << endl; - } - } - } - return os; -} +// function to find maximum absolute value on diagonal +// this can be used to find the spectral radius of a diagoanl matrix +double MaximumAbsValOnDiagonal(const vector::const_iterator &mat, + const int &size) { + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; -// member function to zero the matrix -void squareMatrix::Zero() { - for (auto &val : data_) { - val = 0.0; + auto maxVal = 0.0; + for (auto ii = 0; ii < size; ++ii) { + maxVal = std::max(fabs(GetVal(mat, ii, ii)), maxVal); } + return maxVal; } -// member function to set matrix to Identity -void squareMatrix::Identity() { - for (auto rr = 0; rr < this->Size(); rr++) { - for (auto cc = 0; cc < this->Size(); cc++) { - if (rr == cc) { - (*this)(rr, cc) = 1.0; - } else { - (*this)(rr, cc) = 0.0; +// function to multiply two matrices +void MatrixMultiply(const vector::const_iterator &matL, + const vector::const_iterator &matR, + const vector::iterator &result, const int &size) { + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + + for (auto cc = 0; cc < size; ++cc) { + for (auto rr = 0; rr < size; ++rr) { + for (auto ii = 0; ii < size; ++ii) { + GetVal(result, rr, ii) += GetVal(matL, rr, cc) * GetVal(matR, cc, ii); } } } } -// member function to do matrix/vector multplication -genArray squareMatrix::ArrayMult(const genArray &vec, const int pos) const { - // vec -- vector to multiply with - - auto product = vec; - - // zero out portion of genArray that will be written over - if (pos == 0) { - for (auto ii = 0; ii < NUMFLOWVARS; ii++) { - product[ii] = 0.0; - } - } else { - for (auto ii = pos; ii < NUMVARS; ii++) { - product[ii] = 0.0; - } +void MultiplyFacOnDiagonal(const vector::iterator &mat, const int &size, + const double &val) { + // val -- value to multiply along diagonal + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + for (auto ii = 0; ii < size; ++ii) { + GetVal(mat, ii, ii) *= val; } - - for (auto rr = 0; rr < size_; rr++) { - for (auto cc = 0; cc < size_; cc++) { - product[pos + rr] += (*this)(rr, cc) * vec[pos + cc]; - } - } - return product; } -// member function to find maximum absolute value on diagonal -// this can be used to find the spectral radius of a diagoanl matrix -double squareMatrix::MaxAbsValOnDiagonal() const { - auto maxVal = 0.0; - for (auto ii = 0; ii < size_; ii++) { - maxVal = std::max(fabs((*this)(ii, ii)), maxVal); +void AddFacOnDiagonal(const vector::iterator &mat, const int &size, + const double &val) { + // val -- value to multiply along diagonal + auto GetVal = [&size](const auto &mat, const int &r, + const int &c) -> decltype(auto) { + return *(mat + r * size + c); + }; + for (auto ii = 0; ii < size; ++ii) { + GetVal(mat, ii, ii) += val; } - return maxVal; } + diff --git a/src/output.cpp b/src/output.cpp index 0f43731..bb2157f 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,21 +22,19 @@ #include // pair #include #include "output.hpp" -#include "turbulence.hpp" #include "vector3d.hpp" // vector3d #include "multiArray3d.hpp" // multiArray3d #include "tensor.hpp" // tensor #include "plot3d.hpp" // plot3d -#include "eos.hpp" -#include "transport.hpp" -#include "thermodynamic.hpp" -#include "primVars.hpp" // primVars +#include "physicsModels.hpp" +#include "primitive.hpp" // primitive #include "procBlock.hpp" // procBlock #include "inviscidFlux.hpp" // inviscidFlux #include "input.hpp" // inputVars #include "parallel.hpp" // decomposition #include "resid.hpp" // resid -#include "genArray.hpp" // genArray +#include "conserved.hpp" // conserved +#include "varArray.hpp" // residual #include "utility.hpp" using std::cout; @@ -51,7 +49,6 @@ using std::max; using std::pair; using std::setw; using std::setprecision; -using std::unique_ptr; //----------------------------------------------------------------------- // function declarations @@ -168,11 +165,9 @@ void WriteWallFaceCenter(const string &gridName, const vector &vars, //---------------------------------------------------------------------- // function to write out variables in function file format -void WriteFun(const vector &vars, const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, const int &solIter, - const decomposition &decomp, const input &inp, - const unique_ptr &turb) { +void WriteFun(const vector &vars, const physics &phys, + const int &solIter, const decomposition &decomp, + const input &inp) { // recombine blocks into original structure auto recombVars = Recombine(vars, decomp); @@ -219,9 +214,9 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, value *= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "mach") { auto vel = blk.State(ii, jj, kk).Velocity(); - value = vel.Mag() / blk.State(ii, jj, kk).SoS(thermo, eqnState); + value = vel.Mag() / blk.State(ii, jj, kk).SoS(phys); } else if (var == "sos") { - value = blk.State(ii, jj, kk).SoS(thermo, eqnState); + value = blk.State(ii, jj, kk).SoS(phys); value *= inp.ARef(); } else if (var == "dt") { value = blk.Dt(ii, jj, kk); @@ -242,16 +237,17 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, : 0.0; } else if (var == "turbulentViscosity") { value = blk.EddyViscosity(ii, jj, kk); - value *= trans->MuRef(); + value *= phys.Transport()->MuRef(); } else if (var == "viscosity") { value = blk.Viscosity(ii, jj, kk); - value *= trans->MuRef(); + value *= phys.Transport()->MuRef(); } else if (var == "tke") { value = blk.State(ii, jj, kk).Tke(); value *= inp.ARef() * inp.ARef(); } else if (var == "sdr") { value = blk.State(ii, jj, kk).Omega(); - value *= inp.ARef() * inp.ARef() * inp.RRef() / trans->MuRef(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / + phys.Transport()->MuRef(); } else if (var == "f1") { value = blk.F1(ii, jj, kk); } else if (var == "f2") { @@ -295,6 +291,24 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, } else if (var == "tempGrad_z") { value = blk.TempGrad(ii, jj, kk).Z(); value *= inp.TRef() / inp.LRef(); + } else if (var == "densityGrad_x") { + value = blk.DensityGrad(ii, jj, kk).X(); + value *= inp.RRef() / inp.LRef(); + } else if (var == "densityGrad_y") { + value = blk.DensityGrad(ii, jj, kk).Y(); + value *= inp.RRef() / inp.LRef(); + } else if (var == "denistyGrad_z") { + value = blk.DensityGrad(ii, jj, kk).Z(); + value *= inp.RRef() / inp.LRef(); + } else if (var == "pressGrad_x") { + value = blk.PressureGrad(ii, jj, kk).X(); + value *= inp.RRef() * inp.ARef() * inp.ARef() / inp.LRef(); + } else if (var == "pressGrad_y") { + value = blk.PressureGrad(ii, jj, kk).Y(); + value *= inp.RRef() * inp.ARef() * inp.ARef() / inp.LRef(); + } else if (var == "pressGrad_z") { + value = blk.PressureGrad(ii, jj, kk).Z(); + value *= inp.RRef() * inp.ARef() * inp.ARef() / inp.LRef(); } else if (var == "tkeGrad_x") { value = blk.TkeGrad(ii, jj, kk).X(); value *= inp.ARef() * inp.ARef() / inp.LRef(); @@ -307,15 +321,15 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, } else if (var == "omegaGrad_x") { value = blk.OmegaGrad(ii, jj, kk).X(); value *= inp.ARef() * inp.ARef() * inp.RRef() / - (trans->MuRef() * inp.LRef()); + (phys.Transport()->MuRef() * inp.LRef()); } else if (var == "omegaGrad_y") { value = blk.OmegaGrad(ii, jj, kk).Y(); value *= inp.ARef() * inp.ARef() * inp.RRef() / - (trans->MuRef() * inp.LRef()); + (phys.Transport()->MuRef() * inp.LRef()); } else if (var == "omegaGrad_z") { value = blk.OmegaGrad(ii, jj, kk).Z(); value *= inp.ARef() * inp.ARef() * inp.RRef() / - (trans->MuRef() * inp.LRef()); + (phys.Transport()->MuRef() * inp.LRef()); } else if (var == "resid_mass") { value = blk.Residual(ii, jj, kk, 0); value *= inp.RRef() * inp.ARef() * inp.LRef() * inp.LRef(); @@ -342,7 +356,16 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, } else if (var == "resid_sdr") { value = blk.Residual(ii, jj, kk, 6); value *= inp.RRef() * inp.RRef() * pow(inp.ARef(), 4.0) * - inp.LRef() * inp.LRef() / trans->MuRef(); + inp.LRef() * inp.LRef() / phys.Transport()->MuRef(); + } else if (var.substr(0, 3) == "mf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto ind = inp.SpeciesIndex(var.substr(3, string::npos)); + value = blk.State(ii, jj, kk).MassFractionN(ind); + } else if (var.substr(0, 3) == "vf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto ind = inp.SpeciesIndex(var.substr(3, string::npos)); + value = + blk.State(ii, jj, kk).VolumeFractions(phys.Transport())[ind]; } else { cerr << "ERROR: Variable " << var << " to write to function file is not defined!" << endl; @@ -361,15 +384,13 @@ void WriteFun(const vector &vars, const unique_ptr &eqnState, outFile.close(); if (inp.NumWallVarsOutput() > 0) { - WriteWallFun(recombVars, eqnState, trans, solIter, inp, turb); + WriteWallFun(recombVars, phys, solIter, inp); } } // function to write out variables in function file format -void WriteWallFun(const vector &vars, - const unique_ptr &eqnState, - const unique_ptr &trans, const int &solIter, - const input &inp, const unique_ptr &turb) { +void WriteWallFun(const vector &vars, const physics &phys, + const int &solIter, const input &inp) { // open binary plot3d function file const string fEnd = "_wall_center"; const string fPostfix = ".fun"; @@ -419,14 +440,14 @@ void WriteWallFun(const vector &vars, value = blk.WallYplus(ll, ii, jj, kk); } else if (var == "shearStress") { value = blk.WallShearStress(ll, ii, jj, kk).Mag(); - value *= trans->InvNondimScaling() * trans->MuRef() * inp.ARef() / - inp.LRef(); + value *= phys.Transport()->InvNondimScaling() * + phys.Transport()->MuRef() * inp.ARef() / inp.LRef(); } else if (var == "viscosityRatio") { value = blk.WallEddyVisc(ll, ii, jj, kk) / (blk.WallViscosity(ll, ii, jj, kk) + EPS); } else if (var == "heatFlux") { value = blk.WallHeatFlux(ll, ii, jj, kk); - value *= trans->MuRef() * inp.TRef() / inp.LRef(); + value *= phys.Transport()->MuRef() * inp.TRef() / inp.LRef(); } else if (var == "frictionVelocity") { value = blk.WallFrictionVelocity(ll, ii, jj, kk); value *= inp.ARef(); @@ -434,20 +455,22 @@ void WriteWallFun(const vector &vars, value = blk.WallDensity(ll, ii, jj, kk); value *= inp.RRef(); } else if (var == "pressure") { - value = blk.WallPressure(ll, ii, jj, kk, eqnState); + value = blk.WallPressure(ll, ii, jj, kk, phys.EoS()); value *= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "temperature") { value = blk.WallTemperature(ll, ii, jj, kk); value *= inp.TRef(); } else if (var == "viscosity") { value = blk.WallViscosity(ll, ii, jj, kk); - value *= trans->MuRef() * trans->InvNondimScaling(); + value *= phys.Transport()->MuRef() * + phys.Transport()->InvNondimScaling(); } else if (var == "tke") { value = blk.WallTke(ll, ii, jj, kk); value *= inp.ARef() * inp.ARef(); } else if (var == "sdr") { value = blk.WallSdr(ll, ii, jj, kk); - value *= inp.ARef() * inp.ARef() * inp.RRef() / trans->MuRef(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / + phys.Transport()->MuRef(); } else { cerr << "ERROR: Variable " << var << " to write to wall function file is not defined!" @@ -468,17 +491,16 @@ void WriteWallFun(const vector &vars, } // function to write out restart variables -void WriteRestart(const vector &splitVars, - const unique_ptr &eqnState, - const unique_ptr &trans, const int &solIter, - const decomposition &decomp, const input &inp, - const genArray &residL2First) { +void WriteRestart(const vector &splitVars, const physics &phys, + const int &solIter, const decomposition &decomp, + const input &inp, const residual &residL2First) { // recombine blocks into original structure auto vars = Recombine(splitVars, decomp); // open binary restart file const string fPostfix = ".rst"; - const auto writeName = inp.SimNameRoot() + "_" + to_string(solIter) + fPostfix; + const auto writeName = + inp.SimNameRoot() + "_" + to_string(solIter) + fPostfix; ofstream outFile(writeName, ios::out | ios::binary); // check to see if file opened correctly @@ -500,16 +522,34 @@ void WriteRestart(const vector &splitVars, auto numEqns = inp.NumEquations(); outFile.write(reinterpret_cast(&numEqns), sizeof(numEqns)); + // write number of species + auto numSpecies = inp.NumSpecies(); + outFile.write(reinterpret_cast(&numSpecies), sizeof(numSpecies)); + + // write species names (including sizes) + for (auto ii = 0; ii < numSpecies; ++ii) { + auto specName = inp.Fluid(ii).Name(); + auto specSize = specName.size(); + outFile.write(reinterpret_cast(&specSize), sizeof(specSize)); + outFile.write(specName.c_str(), specSize * sizeof(char)); + } + // write residual values - outFile.write(const_cast(reinterpret_cast(&residL2First)), - sizeof(residL2First)); + outFile.write( + const_cast(reinterpret_cast(&residL2First[0])), + residL2First.Size() * sizeof(residL2First[0])); // variables to write to restart file - vector restartVars = {"density", "vel_x", "vel_y", "vel_z", "pressure"}; + vector restartVars = {"density", "vel_x", "vel_y", "vel_z", + "pressure"}; if (inp.IsRANS()) { restartVars.push_back("tke"); restartVars.push_back("sdr"); } + for (auto ii = 0; ii < numSpecies; ++ii) { + auto var = "mf_" + inp.Fluid(ii).Name(); + restartVars.push_back(var); + } WriteBlockDims(outFile, vars, restartVars.size()); @@ -542,7 +582,12 @@ void WriteRestart(const vector &splitVars, value *= inp.ARef() * inp.ARef(); } else if (var == "sdr") { value = blk.State(ii, jj, kk).Omega(); - value *= inp.ARef() * inp.ARef() * inp.RRef() / trans->MuRef(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / + phys.Transport()->MuRef(); + } else if (var.substr(0, 3) == "mf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto ind = inp.SpeciesIndex(var.substr(3, string::npos)); + value = blk.State(ii, jj, kk).MassFractionN(ind); } else { cerr << "ERROR: Variable " << var << " to write to restart file is not defined!" << endl; @@ -587,7 +632,12 @@ void WriteRestart(const vector &splitVars, value *= inp.ARef() * inp.ARef() * inp.RRef(); } else if (var == "sdr") { // conserved var is rho-sdr value = blk.ConsVarsNm1(ii, jj, kk)[6]; - value *= inp.ARef() * inp.ARef() * inp.RRef() * inp.RRef() / trans->MuRef(); + value *= inp.ARef() * inp.ARef() * inp.RRef() * inp.RRef() / + phys.Transport()->MuRef(); + } else if (var.substr(0, 3) == "mf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto ind = inp.SpeciesIndex(var.substr(3, string::npos)); + value = blk.ConsVarsNm1(ii, jj, kk).MassFractionN(ind); } else { cerr << "ERROR: Variable " << var << " to write to restart file is not defined!" << endl; @@ -607,11 +657,8 @@ void WriteRestart(const vector &splitVars, } void ReadRestart(vector &vars, const string &restartName, - const decomposition &decomp, input &inp, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, genArray &residL2First, + const decomposition &decomp, input &inp, const physics &phys, + residual &residL2First, const vector> &gridSizes) { // open binary restart file ifstream fName(restartName, ios::in | ios::binary); @@ -645,8 +692,28 @@ void ReadRestart(vector &vars, const string &restartName, fName.read(reinterpret_cast(&numEqns), sizeof(numEqns)); cout << "Number of equations: " << numEqns << endl; + // read the number of species + auto numSpecies = 0; + fName.read(reinterpret_cast(&numSpecies), sizeof(numSpecies)); + cout << "Number of species: " << numSpecies << endl; + + // read species names (including sizes) + vector speciesNames(numSpecies); + for (auto ii = 0; ii < numSpecies; ++ii) { + size_t nameSize = 0; + fName.read(reinterpret_cast(&nameSize), sizeof(nameSize)); + + auto buffer = unique_ptr(new char[nameSize]); + fName.read(buffer.get(), nameSize * sizeof(char)); + string sname(buffer.get(), nameSize); + speciesNames[ii] = sname; + } + // check that species are defined + inp.CheckSpecies(speciesNames); + // read the residuals to normalize by - fName.read(reinterpret_cast(&residL2First), sizeof(residL2First)); + fName.read(reinterpret_cast(&residL2First[0]), + residL2First.Size() * sizeof(residL2First[0])); // read the number of blocks auto numBlks = 0; @@ -667,7 +734,7 @@ void ReadRestart(vector &vars, const string &restartName, fName.read(reinterpret_cast(&numK), sizeof(numK)); fName.read(reinterpret_cast(&numVars), sizeof(numVars)); if (numI != gridSizes[ii].X() || numJ != gridSizes[ii].Y() || - numK != gridSizes[ii].Z() || numVars != numEqns) { + numK != gridSizes[ii].Z() || numVars - 1 != numEqns) { cerr << "ERROR: Problem with restart file. Block size does not match " << "grid, or number of variables in block does not match number of " << "equations!" << endl; @@ -676,19 +743,24 @@ void ReadRestart(vector &vars, const string &restartName, } // variables to read from restart file - vector restartVars = {"density", "vel_x", "vel_y", "vel_z", "pressure"}; - if (numEqns == 7) { + vector restartVars = {"density", "vel_x", "vel_y", "vel_z", + "pressure"}; + if (numEqns == numSpecies + 6) { // have turbulence variables restartVars.push_back("tke"); restartVars.push_back("sdr"); } + for (auto &spec : speciesNames) { + auto var = "mf_" + spec; + restartVars.push_back(var); + } // loop over blocks and initialize cout << "Reading solution from time n..." << endl; - vector> solN(numBlks); + vector> solN(numBlks); for (auto ii = 0U; ii < solN.size(); ++ii) { - solN[ii] = ReadSolFromRestart(fName, inp, eqnState, thermo, trans, turb, - restartVars, gridSizes[ii].X(), - gridSizes[ii].Y(), gridSizes[ii].Z()); + solN[ii] = + ReadSolFromRestart(fName, inp, phys, restartVars, gridSizes[ii].X(), + gridSizes[ii].Y(), gridSizes[ii].Z(), numSpecies); } // decompose solution decomp.DecompArray(solN); @@ -701,11 +773,11 @@ void ReadRestart(vector &vars, const string &restartName, if (inp.IsMultilevelInTime()) { if (numSols == 2) { cout << "Reading solution from time n-1..." << endl; - vector> solNm1(numBlks); + vector> solNm1(numBlks); for (auto ii = 0U; ii < solNm1.size(); ++ii) { - solNm1[ii] = ReadSolNm1FromRestart(fName, inp, eqnState, trans, turb, - restartVars, gridSizes[ii].X(), - gridSizes[ii].Y(), gridSizes[ii].Z()); + solNm1[ii] = ReadSolNm1FromRestart(fName, inp, phys, restartVars, + gridSizes[ii].X(), gridSizes[ii].Y(), + gridSizes[ii].Z(), numSpecies); } // decompose solution decomp.DecompArray(solNm1); @@ -719,7 +791,7 @@ void ReadRestart(vector &vars, const string &restartName, cerr << "WARNING: Using multilevel time integration scheme, but only one " << "time level found in restart file" << endl; // assign solution at time n to n-1 - AssignSolToTimeN(vars, eqnState, thermo); + AssignSolToTimeN(vars, phys); AssignSolToTimeNm1(vars); } } @@ -729,28 +801,6 @@ void ReadRestart(vector &vars, const string &restartName, cout << "Done with restart file" << endl << endl; } -template -void WriteBlockDims(ofstream &outFile, const vector &vars, - int numVars) { - // write number of blocks to file - auto numBlks = static_cast(vars.size()); - outFile.write(reinterpret_cast(&numBlks), sizeof(numBlks)); - - // loop over all blocks and write out imax, jmax, kmax, numVars - for (auto &blk : vars) { - auto dumInt = blk.NumI(); - outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - dumInt = blk.NumJ(); - outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - dumInt = blk.NumK(); - outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - - if (numVars > 0) { - outFile.write(reinterpret_cast(&numVars), sizeof(numVars)); - } - } -} - // function to write out plot3d meta data for Paraview void WriteMeta(const input &inp, const int &iter) { @@ -777,8 +827,23 @@ void WriteMeta(const input &inp, const int &iter) { metaFile << "\"auto-detect-format\" : true," << endl; metaFile << "\"format\" : \"binary\"," << endl; metaFile << "\"language\" : \"C\"," << endl; - metaFile << "\"filenames\" : [{ \"time\" : " << iter << ", \"xyz\" : \"" - << gridName << "\", \"function\" : \"" << funName << "\" }]," << endl; + if (inp.IsTimeAccurate()) { + metaFile << "\"filenames\" : ["; + for (auto nn = 0; nn <= iter; nn += inp.OutputFrequency()) { + const auto currFunName = + inp.SimNameRoot() + "_" + to_string(nn) + fEnd + ".fun"; + metaFile << "{ \"time\" : " << nn * inp.Dt() << ", \"xyz\" : \"" + << gridName << "\", \"function\" : \"" << currFunName << "\" }"; + if (nn != iter) { + metaFile << ", " << endl; + } + } + metaFile << "]," << endl; + } else { + metaFile << "\"filenames\" : [{ \"time\" : " << iter << ", \"xyz\" : \"" + << gridName << "\", \"function\" : \"" << funName << "\" }]," + << endl; + } // Write out scalar variables auto numVar = 0U; @@ -848,8 +913,8 @@ void WriteWallMeta(const input &inp, const int &iter) { // function to write out residual information -void WriteResiduals(const input &inp, genArray &residL2First, - const genArray &residL2, const resid &residLinf, +void WriteResiduals(const input &inp, residual &residL2First, + const residual &residL2, const resid &residLinf, const double &matrixResid, const int &nn, const int &mm, ostream &resFile) { // if first iteration write headers to residual file @@ -891,26 +956,26 @@ void PrintHeaders(const input &inp, ostream &os) { } // function to write out residual information -void PrintResiduals(const input &inp, genArray &residL2First, - const genArray &residL2, const resid &residLinf, +void PrintResiduals(const input &inp, residual &residL2First, + const residual &residL2, const resid &residLinf, const double &matrixResid, const int &nn, const int &mm, ostream &os) { // determine normalization // if at first iteration and not restart, normalize by itself if (nn == 0 && mm == 0 && !inp.IsRestart()) { residL2First = residL2; - // if within first 5 iterations reset normalization + // if within first 5 iterations reset normalization if resid at new max } else if ((nn < 5) && mm == 0 && !inp.IsRestart()) { - for (auto cc = 0; cc < NUMVARS; cc++) { - if (residL2[cc] > residL2First[cc]) { + if (residL2.SpeciesSum() > residL2First.SpeciesSum()) { + for (auto cc = 0; cc < residL2.NumSpecies(); ++cc) { residL2First[cc] = residL2[cc]; } } + for (auto cc = residL2.NumSpecies(); cc < residL2.Size(); ++cc) { + residL2First[cc] = std::max(residL2First[cc], residL2[cc]); + } } - // normalize residuals - const auto resNormL2 = (residL2 + EPS) / (residL2First + EPS); - os << std::left << setw(7) << nn << setw(8) << mm; if (inp.Dt() > 0.0) { os << std::left << setw(12) << setprecision(4) << std::scientific @@ -919,11 +984,26 @@ void PrintResiduals(const input &inp, genArray &residL2First, os << std::left << setw(12) << setprecision(4) << std::scientific << inp.CFL(); } - os << std::left << setw(12) << resNormL2[0] << setw(12) << resNormL2[1] - << setw(12) << resNormL2[2] << setw(12) << resNormL2[3] << setw(12) - << resNormL2[4]; + + // normalize residuals + // mass residual is sum of species residuals + const auto resMass = + (residL2.SpeciesSum() + EPS) / (residL2First.SpeciesSum() + EPS); + const auto resNormL2 = (residL2 + EPS) / (residL2First + EPS); + + // get indices + const auto imx = resNormL2.MomentumXIndex(); + const auto imy = resNormL2.MomentumYIndex(); + const auto imz = resNormL2.MomentumZIndex(); + const auto ie = resNormL2.EnergyIndex(); + + os << std::left << setw(12) << resMass << setw(12) + << resNormL2[imx] << setw(12) << resNormL2[imy] << setw(12) + << resNormL2[imz] << setw(12) << resNormL2[ie]; if (inp.IsRANS()) { - os << std::left << setw(12) << resNormL2[5] << setw(12) << resNormL2[6]; + const auto it = resNormL2.TurbulenceIndex(); + os << std::left << setw(12) << resNormL2[it] << setw(12) + << resNormL2[it + 1]; } os.unsetf(std::ios::fixed | std::ios::scientific); os << std::left << setw(8) << residLinf.Eqn() << setw(8) @@ -1025,101 +1105,130 @@ int SplitBlockNumber(const vector &vars, const decomposition &decomp, return ind; // cell was in uppermost split for given parent block } -multiArray3d ReadSolFromRestart( - ifstream &resFile, const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb, const vector &restartVars, - const int &numI, const int &numJ, const int &numK) { +blkMultiArray3d ReadSolFromRestart( + ifstream &resFile, const input &inp, const physics &phys, + const vector &restartVars, const int &numI, const int &numJ, + const int &numK, const int &numSpecies) { // intialize multiArray3d - multiArray3d sol(numI, numJ, numK, 0); + // -1 b/c mf and density written to file + auto numEqns = restartVars.size() - 1; + blkMultiArray3d sol(numI, numJ, numK, 0, numEqns, numSpecies); - // read the primative variables + // read the primitive variables // read dimensional variables -- loop over physical cells for (auto kk = sol.StartK(); kk < sol.EndK(); kk++) { for (auto jj = sol.StartJ(); jj < sol.EndJ(); jj++) { for (auto ii = sol.StartI(); ii < sol.EndI(); ii++) { - genArray value; + primitive value(numEqns, numSpecies); + auto rho = 0.0; // loop over the number of variables to read for (auto &var : restartVars) { if (var == "density") { - resFile.read(reinterpret_cast(&value[0]), sizeof(value[0])); - value[0] /= inp.RRef(); + resFile.read(reinterpret_cast(&rho), sizeof(rho)); + rho /= inp.RRef(); } else if (var == "vel_x") { - resFile.read(reinterpret_cast(&value[1]), sizeof(value[1])); - value[1] /= inp.ARef(); + auto n = value.MomentumXIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef(); } else if (var == "vel_y") { - resFile.read(reinterpret_cast(&value[2]), sizeof(value[2])); - value[2] /= inp.ARef(); + auto n = value.MomentumYIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef(); } else if (var == "vel_z") { - resFile.read(reinterpret_cast(&value[3]), sizeof(value[3])); - value[3] /= inp.ARef(); + auto n = value.MomentumZIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef(); } else if (var == "pressure") { - resFile.read(reinterpret_cast(&value[4]), sizeof(value[4])); - value[4] /= inp.RRef() * inp.ARef() * inp.ARef(); + auto n = value.EnergyIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "tke") { - resFile.read(reinterpret_cast(&value[5]), sizeof(value[5])); - value[5] /= inp.ARef() * inp.ARef(); + auto n = value.TurbulenceIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.ARef(); } else if (var == "sdr") { - resFile.read(reinterpret_cast(&value[6]), sizeof(value[6])); - value[6] /= inp.ARef() * inp.ARef() * inp.RRef() / trans->MuRef(); + auto n = value.TurbulenceIndex() + 1; + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.ARef() * inp.RRef() / + phys.Transport()->MuRef(); + } else if (var.substr(0, 3) == "mf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto n = inp.SpeciesIndex(var.substr(3, string::npos)); + auto mf = 0.0; + resFile.read(reinterpret_cast(&mf), sizeof(mf)); + value[n] = rho * mf; } else { cerr << "ERROR: Variable " << var << " to read from restart file is not defined!" << endl; exit(EXIT_FAILURE); } } - sol(ii, jj, kk) = primVars(value, true, eqnState, thermo, turb); + sol.InsertBlock(ii, jj, kk, value); } } } return sol; } -multiArray3d ReadSolNm1FromRestart( - ifstream &resFile, const input &inp, const unique_ptr &eqnState, - const unique_ptr &trans, const unique_ptr &turb, +blkMultiArray3d ReadSolNm1FromRestart( + ifstream &resFile, const input &inp, const physics &phys, const vector &restartVars, const int &numI, const int &numJ, - const int &numK) { + const int &numK, const int &numSpecies) { // intialize multiArray3d - multiArray3d sol(numI, numJ, numK, 0); + // -1 b/c mf and density written to file + auto numEqns = restartVars.size() - 1; + blkMultiArray3d sol(numI, numJ, numK, 0, numEqns, numSpecies); // data is conserved variables // read dimensional variables -- loop over physical cells for (auto kk = sol.StartK(); kk < sol.EndK(); kk++) { for (auto jj = sol.StartJ(); jj < sol.EndJ(); jj++) { for (auto ii = sol.StartI(); ii < sol.EndI(); ii++) { - genArray value; + conserved value(numEqns, numSpecies); + auto rho = 0.0; // loop over the number of variables to read for (auto &var : restartVars) { if (var == "density") { - resFile.read(reinterpret_cast(&value[0]), sizeof(value[0])); - value[0] /= inp.RRef(); + resFile.read(reinterpret_cast(&rho), sizeof(rho)); + rho /= inp.RRef(); } else if (var == "vel_x") { // conserved var is rho-u - resFile.read(reinterpret_cast(&value[1]), sizeof(value[1])); - value[1] /= inp.ARef() * inp.RRef(); + auto n = value.MomentumXIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.RRef(); } else if (var == "vel_y") { // conserved var is rho-v - resFile.read(reinterpret_cast(&value[2]), sizeof(value[2])); - value[2] /= inp.ARef() * inp.RRef(); + auto n = value.MomentumYIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.RRef(); } else if (var == "vel_z") { // conserved var is rho-w - resFile.read(reinterpret_cast(&value[3]), sizeof(value[3])); - value[3] /= inp.ARef() * inp.RRef(); + auto n = value.MomentumZIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.RRef(); } else if (var == "pressure") { // conserved var is rho-E - resFile.read(reinterpret_cast(&value[4]), sizeof(value[4])); - value[4] /= inp.RRef() * inp.ARef() * inp.ARef(); + auto n = value.EnergyIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "tke") { // conserved var is rho-tke - resFile.read(reinterpret_cast(&value[5]), sizeof(value[5])); - value[5] /= inp.ARef() * inp.ARef() * inp.RRef(); + auto n = value.TurbulenceIndex(); + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.ARef() * inp.RRef(); } else if (var == "sdr") { // conserved var is rho-sdr - resFile.read(reinterpret_cast(&value[6]), sizeof(value[6])); - value[6] /= inp.ARef() * inp.ARef() * inp.RRef() * inp.RRef() / - trans->MuRef(); + auto n = value.TurbulenceIndex() + 1; + resFile.read(reinterpret_cast(&value[n]), sizeof(value[n])); + value[n] /= inp.ARef() * inp.ARef() * inp.RRef() * inp.RRef() / + phys.Transport()->MuRef(); + } else if (var.substr(0, 3) == "mf_" && + inp.HaveSpecies(var.substr(3, string::npos))) { + auto n = inp.SpeciesIndex(var.substr(3, string::npos)); + auto mf = 0.0; + resFile.read(reinterpret_cast(&mf), sizeof(mf)); + value[n] = rho * mf; } else { cerr << "ERROR: Variable " << var << " to read from restart file is not defined!" << endl; exit(EXIT_FAILURE); } } - sol(ii, jj, kk) = value; + sol.InsertBlock(ii, jj, kk, value); } } } diff --git a/src/parallel.cpp b/src/parallel.cpp index 5f145f8..66e3182 100644 --- a/src/parallel.cpp +++ b/src/parallel.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,12 +24,11 @@ #include "output.hpp" #include "vector3d.hpp" // vector3d #include "plot3d.hpp" // plot3d -#include "primVars.hpp" // primVars +#include "primitive.hpp" // primitive #include "procBlock.hpp" // procBlock #include "boundaryConditions.hpp" // connection #include "resid.hpp" // resid #include "macros.hpp" -#include "genArray.hpp" using std::max_element; using std::min_element; @@ -123,18 +122,25 @@ decomposition CubicDecomposition(vector &grid, decomp.SendToProc(blk, ol, ul); } else { // split/send auto newBlk = static_cast(grid.size()); + // find all interblocks that could be altered by this split along with + // their partners and orientation + auto affectedConnections = GetBlockInterConnBCs(bcs, grid, blk); + // split grid plot3dBlock lBlk, uBlk; grid[blk].Split(dir, ind, lBlk, uBlk); grid.push_back(uBlk); + // split bcs vector altSurf; auto newBcs = bcs[blk].Split(dir, ind, blk, newBlk, altSurf); bcs.push_back(newBcs); - for (auto ii = 0U; ii < altSurf.size(); ii++) { - bcs[altSurf[ii].PartnerBlock()].DependentSplit( - altSurf[ii], grid[blk], grid[altSurf[ii].PartnerBlock()], - altSurf[ii].PartnerBlock(), dir, ind, blk, newBlk); + // update interblock partners affected by split + for (auto &alt : altSurf) { + bcs[alt.PartnerBlock()].DependentSplit( + alt, affectedConnections.at(alt).first, + affectedConnections.at(alt).second, alt.PartnerBlock(), dir, ind, + blk, newBlk); } // reassign split grid @@ -196,16 +202,14 @@ void SendConnections(vector &connections, } /* Function to set custom MPI datatypes to allow for easier data transmission */ -void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, +void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_procBlockInts, MPI_Datatype &MPI_connection, MPI_Datatype &MPI_DOUBLE_5INT, MPI_Datatype &MPI_vec3dMag, MPI_Datatype &MPI_uncoupledScalar, - MPI_Datatype &MPI_tensorDouble, - MPI_Datatype &MPI_wallData) { + MPI_Datatype &MPI_tensorDouble) { // MPI_vec3d -- output MPI_Datatype for a vector3d - // MPI_cellData -- output MPI_Datatype for primVars or genArray // MPI_procBlockInts -- output MPI_Datatype for 14 INTs (14 INTs in procBlock // class) // MPI_connection -- output MPI_Datatype to send connection class @@ -213,7 +217,6 @@ void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, // MPI_vec3dMag -- output MPI_Datatype for a unitVect3dMag // MPI_uncoupledScalar -- output MPI_Datatype for a uncoupledScalar // MPI_tensorDouble -- output MPI_Datatype for a tensor - // MPI_wallData -- output MPI_Datatype for wallData class // create vector3d MPI datatype MPI_Type_contiguous(3, MPI_DOUBLE, &MPI_vec3d); @@ -231,30 +234,6 @@ void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, MPI_Type_contiguous(9, MPI_DOUBLE, &MPI_tensorDouble); MPI_Type_commit(&MPI_tensorDouble); - // create wallData MPI datatype - MPI_Type_contiguous(12, MPI_DOUBLE, &MPI_wallData); - MPI_Type_commit(&MPI_wallData); - - // create MPI datatype for states (primVars), residuals (genArray), etc - MPI_Type_contiguous(NUMVARS, MPI_DOUBLE, &MPI_cellData); - - // faster to just send the whole array - // if ( numEqn != NUMVARS ){ //adjust extent if not using all equations - // MPI_Aint lb, ext, lbdoub, extdoub; - // MPI_Type_get_extent(MPI_cellData, &lb, &ext); //get lower bound and - // extent of current cellData datatype - // MPI_Type_get_extent(MPI_DOUBLE, &lbdoub, &extdoub); //get lower bound and - // extent of double - // //increase extent of cellData by the number of doubles that are unused - // equations - // //this allows this datatype to behave properly in vectors and arrays - // because the extent/stride is now correct - // MPI_Type_create_resized(MPI_cellData, lb, ext + (extdoub - lbdoub) * - // (NUMVARS - numEqn), &MPI_cellData); - // } - - MPI_Type_commit(&MPI_cellData); - // create MPI datatype for all the integers in the procBlock class MPI_Type_contiguous(15, MPI_INT, &MPI_procBlockInts); MPI_Type_commit(&MPI_procBlockInts); @@ -315,23 +294,20 @@ void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, } /* Function to free custom MPI datatypesn */ -void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, +void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_procBlockInts, MPI_Datatype &MPI_connection, MPI_Datatype &MPI_DOUBLE_5INT, MPI_Datatype &MPI_vec3dMag, MPI_Datatype &MPI_uncoupledScalar, - MPI_Datatype &MPI_tensorDouble, - MPI_Datatype &MPI_wallData) { + MPI_Datatype &MPI_tensorDouble) { // MPI_vec3d -- MPI_Datatype for a vector3d - // MPI_cellData -- MPI_Datatype for primVars or genArray // MPI_procBlockInts -- MPI_Datatype for 14 INTs (14 INTs in procBlock class) // MPI_connection -- MPI_Datatype to send connection class // MPI_DOUBLE_5INT -- MPI_Datatype for a double followed by 5 ints // MPI_vec3dMag -- MPI_Datatype for a unitVect3dMag // MPI_uncoupledScalar -- MPI_Datatype for a uncoupledScalar // MPI_tensorDouble -- MPI_Datatype for a tensor - // MPI_wallData -- MPI_Datatype for a wallData // free vector3d MPI datatype MPI_Type_free(&MPI_vec3d); @@ -339,9 +315,6 @@ void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, // free unitVect3dMag MPI datatype MPI_Type_free(&MPI_vec3dMag); - // free MPI datatype for states (primVars), residuals (genArray), etc - MPI_Type_free(&MPI_cellData); - // free MPI datatype for uncoupledScalar MPI_Type_free(&MPI_uncoupledScalar); @@ -356,9 +329,6 @@ void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, // free MPI datatype for tensor class MPI_Type_free(&MPI_tensorDouble); - - // free MPI datatype for wallData class - MPI_Type_free(&MPI_wallData); } /* Function to send procBlocks to their appropriate processor. This function is @@ -371,10 +341,8 @@ simulation. */ vector SendProcBlocks(const vector &blocks, const int &rank, const int &numProcBlock, - const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_vec3d, const MPI_Datatype &MPI_vec3dMag, - const MPI_Datatype &MPI_wallData, const input &inp) { // blocks -- full vector of all procBlocks. This is only used on ROOT // processor, all other processors just need a dummy variable to @@ -383,10 +351,8 @@ vector SendProcBlocks(const vector &blocks, // receive // numProcBlock -- number of procBlocks that the processor should have. (All // processors may give different values). - // MPI_cellData -- MPI_Datatype used for primVars and genArray transmission // MPI_vec3d -- MPI_Datatype used for vector3d transmission // MPI_vec3dMag -- MPI_Datatype used for unitVec3dMag transmission - // MPI_wallData -- MPI_Datatype used for wallData transmission // input -- input variables // vector of procBlocks for each processor @@ -397,25 +363,23 @@ vector SendProcBlocks(const vector &blocks, //------------------------------------------------------------------------ if (rank == ROOTP) { // may have to pack and send data // loop over ALL blocks - for (auto ii = 0U; ii < blocks.size(); ii++) { + for (auto &blk : blocks) { // no need to send data because it is already on root processor - if (blocks[ii].Rank() == ROOTP) { - localBlocks[blocks[ii].LocalPosition()] = blocks[ii]; + if (blk.Rank() == ROOTP) { + localBlocks[blk.LocalPosition()] = blk; } else { // send data to receiving processors // pack and send procBlock - blocks[ii].PackSendGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag, - MPI_wallData); + blk.PackSendGeomMPI(MPI_vec3d, MPI_vec3dMag); } } //-------------------------------------------------------------------------- // NON - ROOT //-------------------------------------------------------------------------- } else { // receive and unpack data (non-root) - for (auto ii = 0; ii < numProcBlock; ii++) { + for (auto ii = 0; ii < numProcBlock; ++ii) { // recv and unpack procBlock procBlock tempBlock; - tempBlock.RecvUnpackGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag, - MPI_wallData, inp); + tempBlock.RecvUnpackGeomMPI(MPI_vec3d, MPI_vec3dMag, inp); // add procBlock to output vector localBlocks[tempBlock.LocalPosition()] = tempBlock; @@ -432,67 +396,56 @@ This is used to get all the data on the ROOT processor to write out results. */ void GetProcBlocks(vector &blocks, const vector &localBlocks, const int &rank, - const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_tensorDouble, - const MPI_Datatype &MPI_wallData, const input &inp) { + const MPI_Datatype &MPI_tensorDouble, const input &inp) { // blocks -- full vector of all procBlocks. This is only used on ROOT // processor, all other processors just need a dummy variable to // call the function // localBlocks -- procBlocks local to each processor. These are sent to ROOT // rank -- processor rank. Used to determine if process should send or // receive - // MPI_cellData -- MPI_Datatype used for primVars and genArray transmission // MPI_uncoupledScalar -- MPI_Datatype used for uncoupledScalar transmission // MPI_vec3d -- MPI_Datatype used for vector3d transmission // MPI_tensorDouble -- MPI_Datatype used for tensor transmission - // MPI_wallData -- MPI_Datatype used for wallData transmission // input -- input variables //-------------------------------------------------------------------------- // ROOT //-------------------------------------------------------------------------- if (rank == ROOTP) { // may have to recv and unpack data - for (auto ii = 0U; ii < blocks.size(); ii++) { // loop over ALL blocks - if (blocks[ii].Rank() == ROOTP) { // no need to recv data because it is - // already on ROOT processor - // assign local state block to global state block in order of local - // state vector - blocks[ii] = localBlocks[blocks[ii].LocalPosition()]; + // loop over ALL blocks + auto count = 0; + for (auto &blk : blocks) { + if (blk.Rank() == ROOTP) { // data already on ROOT processor + // assign local block to global block in order of local vector + blk = localBlocks[blk.LocalPosition()]; } else { // recv data from sending processors - blocks[ii].RecvUnpackSolMPI(MPI_cellData, MPI_uncoupledScalar, - MPI_vec3d, MPI_tensorDouble, MPI_wallData, - inp); + blk.RecvUnpackSolMPI(MPI_uncoupledScalar, MPI_vec3d, MPI_tensorDouble, + inp); } + count++; } //------------------------------------------------------------------------- // NON - ROOT //------------------------------------------------------------------------- } else { // pack and send data (non-root) // get vector of local positions - vector localPos(localBlocks.size()); - for (auto ii = 0U; ii < localPos.size(); ii++) { - localPos[ii] = localBlocks[ii].LocalPosition(); + vector> localPos; + localPos.reserve(localBlocks.size()); + for (auto &lb : localBlocks) { + localPos.push_back(std::make_pair(lb.LocalPosition(), lb.GlobalPos())); } - - for (auto ii = 0U; ii < localBlocks.size(); ii++) { - // need to send data in order of global position, not local position to - // prevent deadlock - auto minGlobal = 0; - for (auto jj = 0U; jj < localPos.size(); jj++) { - if (localBlocks[localPos[jj]].GlobalPos() < - localBlocks[minGlobal].GlobalPos()) { - minGlobal = jj; - } - } - - localBlocks[localPos[minGlobal]].PackSendSolMPI(MPI_cellData, - MPI_uncoupledScalar, - MPI_vec3d, - MPI_tensorDouble, - MPI_wallData); - localPos.erase(localPos.begin() + minGlobal); + // sort by global position + // need to send data in order of global position, not local position to + // prevent deadlock + std::sort( + std::begin(localPos), std::end(localPos), + [](const auto &d1, const auto &d2) { return d1.second < d2.second; }); + + for (auto &lp : localPos) { + localBlocks[lp.first].PackSendSolMPI(MPI_uncoupledScalar, MPI_vec3d, + MPI_tensorDouble); } } } diff --git a/src/plot3d.cpp b/src/plot3d.cpp index e999a5b..78f095f 100644 --- a/src/plot3d.cpp +++ b/src/plot3d.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/primVars.cpp b/src/primVars.cpp deleted file mode 100644 index c9b7afe..0000000 --- a/src/primVars.cpp +++ /dev/null @@ -1,1097 +0,0 @@ -/* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) - - Aither is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Aither is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include -#include -#include -#include -#include -#include -#include // max -#include "primVars.hpp" -#include "input.hpp" // input -#include "turbulence.hpp" // turbModel -#include "utility.hpp" -#include "wallLaw.hpp" -#include "wallData.hpp" - -using std::cout; -using std::endl; -using std::cerr; -using std::vector; -using std::string; -using std::max; -using std::min; -using std::unique_ptr; - -primVars::primVars(const genArray &a, const bool &prim, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &turb) { - // a -- array of conservative or primative variables - // prim -- flag that is true if variable a is primative variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // turb -- turbulence model - - if (prim) { // genArray is primative variables - for (auto ii = 0; ii < NUMVARS; ii++) { - data_[ii] = a[ii]; - } - } else { // genArray is conserved variables - data_[0] = a[0]; - data_[1] = a[1] / a[0]; - data_[2] = a[2] / a[0]; - data_[3] = a[3] / a[0]; - const auto energy = a[4] / a[0]; - data_[4] = eqnState->PressFromEnergy(thermo, data_[0], energy, - this->Velocity().Mag()); - data_[5] = a[5] / a[0]; - data_[6] = a[6] / a[0]; - } - - // Adjust turbulence variables to be above minimum if necessary - this->LimitTurb(turb); -} - -// member function to initialize a state with nondimensional values -void primVars::NondimensionalInitialize(const unique_ptr &eqnState, - const input &inp, - const unique_ptr &trans, - const int &parBlock, - const unique_ptr &turb) { - // get initial condition state for parent block - auto ic = inp.ICStateForBlock(parBlock); - - data_[0] = ic.Density(); - data_[1] = ic.Velocity().X(); - data_[2] = ic.Velocity().Y(); - data_[3] = ic.Velocity().Z(); - data_[4] = ic.Pressure(); - - if (inp.IsRANS()) { - // Initialize turbulence quantities based off of specified turublence - // intensity and eddy viscosity ratio. This is the default for - // STAR-CCM+ - this->ApplyFarfieldTurbBC(this->Velocity(), ic.TurbulenceIntensity(), - ic.EddyViscosityRatio(), trans, eqnState, turb); - } else { - data_[5] = 0.0; - data_[6] = 0.0; - } -} - -// operator overload for << - allows use of cout, cerr, etc. -ostream &operator<<(ostream &os, const primVars &prim) { - os << prim.Rho() << endl; - os << prim.U() << endl; - os << prim.V() << endl; - os << prim.W() << endl; - os << prim.P() << endl; - os << prim.Tke() << endl; - os << prim.Omega() << endl; - return os; -} - -// member function to calculate reconstruction of primative variables from cell -// center to cell face this function uses MUSCL extrapolation resulting in -// higher order accuracy -/* - -____________________|_____________________ -| | Ul|Ur | | -| | | | | -| Ui-1 | Ui | Ui+1 | Ui+2 | -| | | | | -| | | | | -|_________|_________|__________|_________| - | - face to reconstruct state at -<--UW2---><--UW1---><---DW----> - -The diagram above shows the stencil used to reconstruct the left and right -states for a given face. For each reconstruction (right and left) only 3 points -are needed, two upwind points and one downwind point. For the left -reconstruction, Ui is the first upwind point, Ui-1 is the second upwind point, -and Ui+1 is the downwind point. For the right reconstruction Ui+1 is the first -upwind point, Ui+2 is the second upwind point, and Ui is the downwind point. - -For left reconstruction the MUSCL scheme goes as follows: -Ui+1/2 = Ui + 0.25 * ( (1-K) * (Ui - Ui-1) + (1+K) * (Ui+1 - Ui) ) - -The above equation assumes there is no limiter, and that the grid spacing is -uniform. In the above equation K refers to the parameter kappa which can be -varied to produce different reconstructions. Acceptable values of K are [-1,1] -(inclusive) - -K = -1 -- fully upwind reconstruction - linear - results in 2nd order accuracy -K = 0 -- fromm scheme - linear - results in 2nd order accuracy -K = 0.5 -- QUICK scheme - parabolic - results in 2nd order accuracy -K = 1 -- central scheme - linear - results in 2nd order accuracy but is unstable -without dissipation added -K = 1/3 -- third order - parabolic - results 2nd order accuracy with lowest -error -(all order of accuracy estimates assume constant fluxes on cell faces which -limits order of accuracy to 2) - -With limiters the equation looks as follows: -Ui+1/2 = Ui + 0.25 * (Ui - Ui-1) * ( (1-K) * L + (1+K) * R * Linv ) - -L represents the limiter function which ranges between 0 and 1. A value of 1 -implies there is no limiter and the full accuracy of the scheme is achieved. A -value of 0 implies that the solution has been limited to first order accuracy. -An in between value results in an order of accuracy between first and second. -Linv is the inverse of the limiter. - -R represents the divided difference that the limiter is a function of. -R = (Ui - Ui-1) / (Ui+1 - Ui) - -The MUSCL scheme can be extended to nonuniform grids by adding in terms -representing the difference in size between the cells. In the above diagram the -values UW2, UW1, and DW represent the length of the second upwind, first upwind, -and downwind cells respectively. dP and dM represent the factors due to the -change in cell size between the first upwind to downwind and first upwind to -second upwind cells. - -dP = (UW1 + DW) / (2.0 * UW) -dM = (UW + UW2) / (2.0 * UW) -R = ((Ui - Ui-1) / dP) / ((Ui+1 - Ui) / dM) - -Ui+1/2 = Ui + 0.25 * ((Ui - Ui-1) / dM) * ( (1-K) * L + (1+K) * R * Linv ) - -*/ -primVars primVars::FaceReconMUSCL(const primVars &primUW2, - const primVars &primDW1, const double &kappa, - const string &lim, const double &uw, - const double &uw2, const double &dw) const { - // primUW2 -- upwind cell furthest from the face at which the primative is - // being reconstructed. - // primUW1 -- upwind cell nearest to the face at which the primative is - // being reconstructed. - // primDW1 -- downwind cell. - // kappa -- parameter that determines which scheme is implemented - // uw -- length of upwind cell - // uw2 -- length of furthest upwind cell - // dw -- length of downwind cell - - const auto primUW1 = *this; - - const auto dPlus = (uw + uw) / (uw + dw); - const auto dMinus = (uw + uw) / (uw + uw2); - - // divided differences to base limiter on; eps must be listed to left of - // primVars - const auto r = (EPS + (primDW1 - primUW1) * dPlus) / - (EPS + (primUW1 - primUW2) * dMinus); - - primVars limiter; - primVars invLimiter; - if (lim == "none") { - limiter = LimiterNone(); - invLimiter = limiter; - } else if (lim == "vanAlbada") { - limiter = LimiterVanAlbada(r); - invLimiter = LimiterVanAlbada(1.0 / r); - } else if (lim == "minmod") { - limiter = LimiterMinmod(primUW1 - primUW2, primDW1 - primUW1, kappa); - invLimiter = limiter / r; - } else { - cerr << "ERROR: Limiter " << lim << " is not recognized!" << endl; - exit(EXIT_FAILURE); - } - - // calculate reconstructed state at face using MUSCL method with limiter - return primUW1 + 0.25 * ((primUW1 - primUW2) * dMinus) * - ((1.0 - kappa) * limiter + (1.0 + kappa) * r * invLimiter); -} - -// member function for higher order reconstruction via weno -primVars primVars::FaceReconWENO(const primVars &upwind2, - const primVars &upwind3, - const primVars &downwind1, - const primVars &downwind2, const double &uw1, - const double &uw2, const double &uw3, - const double &dw1, const double &dw2, - const bool &isWenoZ) const { - // get candidate smaller stencils - const vector cellWidth = {uw3, uw2, uw1, dw1, dw2}; - - constexpr auto degree = 2; - constexpr auto up1Loc = 2; - const auto coeffs0 = LagrangeCoeff(cellWidth, degree, 2, up1Loc); - const auto stencil0 = coeffs0[0] * upwind3 + coeffs0[1] * upwind2 + - coeffs0[2] * (*this); - - const auto coeffs1 = LagrangeCoeff(cellWidth, degree, 1, up1Loc); - const auto stencil1 = coeffs1[0] * upwind2 + coeffs1[1] * (*this) + - coeffs1[2] * downwind1; - - const auto coeffs2 = LagrangeCoeff(cellWidth, degree, 0, up1Loc); - const auto stencil2 = coeffs2[0] * (*this) + coeffs2[1] * downwind1 + - coeffs2[2] * downwind2; - - // get coefficients for large stencil - const auto fullCoeffs = LagrangeCoeff(cellWidth, 4, 2, up1Loc); - - // linear weights - const auto lw0 = fullCoeffs[0] / coeffs0[0]; - const auto lw1 = fullCoeffs[4] / coeffs2[2]; - const auto lw2 = 1.0 - lw0 - lw1; - - const auto beta0 = Beta0(uw3, uw2, uw1, upwind3, upwind2, (*this)); - const auto beta1 = Beta1(uw2, uw1, dw1, upwind2, (*this), downwind1); - const auto beta2 = Beta2(uw1, dw1, dw2, (*this), downwind1, downwind2); - - // calculate nonlinear weights - primVars nlw0, nlw1, nlw2; - if (isWenoZ) { - // using weno-z weights with q = 2 - const auto tau5 = (beta0 - beta2).Abs(); - constexpr auto eps = 1.0e-40; - nlw0 = lw0 * (1.0 + (tau5 / (eps + beta0)).Squared()); - nlw1 = lw1 * (1.0 + (tau5 / (eps + beta1)).Squared()); - nlw2 = lw2 * (1.0 + (tau5 / (eps + beta2)).Squared()); - } else { // standard WENO - // calculate nonlinear weights - constexpr auto eps = 1.0e-6; - nlw0 = lw0 / (eps + beta0).Squared(); - nlw1 = lw1 / (eps + beta1).Squared(); - nlw2 = lw2 / (eps + beta2).Squared(); - } - - // normalize weights - const auto sum_nlw = nlw0 + nlw1 + nlw2; - nlw0 /= sum_nlw; - nlw1 /= sum_nlw; - nlw2 /= sum_nlw; - - // return weighted contribution of each stencil - return nlw0 * stencil0 + nlw1 * stencil1 + nlw2 * stencil2; -} - - -// member function to calculate minmod limiter -primVars primVars::LimiterMinmod(const primVars &upwind, - const primVars &downwind, - const double &kap) const { - // upwind -- upwind state (primative) - // downwind -- downwind state (primative) - // kap -- MUSCL parameter kappa - - primVars limiter; - - // calculate minmod parameter beta - const auto beta = (3.0 - kap) / (1.0 - kap); - - // calculate minmod limiter - for (auto ii = 0; ii < NUMVARS; ii++) { - auto sign = 0.0; - if (upwind.data_[ii] > 0.0) { - sign = 1.0; - } else if (upwind.data_[ii] < 0.0) { - sign = -1.0; - } - limiter.data_[ii] = sign * - max(0.0, min(fabs(upwind.data_[ii]), - sign * downwind.data_[ii] * beta)); - } - - return limiter; -} - -// member function to calculate Van Albada limiter -primVars primVars::LimiterVanAlbada(const primVars &r) const { - // r -- ratio of divided differences - - auto limiter = (r + r * r) / (1 + r * r); - // if value is negative, return zero - for (auto ii = 0; ii < NUMVARS; ii++) { - limiter.data_[ii] = max(0.0, limiter.data_[ii]); - } - return limiter; -} - -// member function to return no limiter -primVars primVars::LimiterNone() const { - // for no limiter return all 1s - primVars limiter(1.0); - return limiter; -} - -// member function to return the state of the appropriate ghost cell -/* - -In the diagram below Ui represents the interior state. This should be represnted -by (*this). Ug1 and Ug2 are the first and second layers of ghost cells -respectively. They are the output of the function. The input "layer" determines -whether Ug1 or Ug2 is output for BCs that use extrapolation. Reflected boundaries -(slipWall, viscousWall) do not use the layer input. Instead Ui+1 must be -specified as (*this) to output Ug2. - -____________________|___________ -| | | | -| | | | -| Ug2 | Ug1 | Ui | -| | | | -| | | | -|_________|_________|__________| - | - boundary face - -Currently the following boundary conditions are supported: slipWall, -viscousWall, characteristic, stagnationInlet, pressureOutlet, subsonicInflow, -subsonicOutflow, supersonicInflow, supersonicOutflow -*/ -primVars primVars::GetGhostState(const string &bcType, - const vector3d &areaVec, - const double &wallDist, const int &surf, - const input &inputVars, const int &tag, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - wallVars &wVars, const int layer) const { - // bcType -- type of boundary condition to supply ghost cell for - // areaVec -- unit area vector of boundary face - // surf -- surface type [1-6] - // wallDist -- distance from cell center to nearest wall boundary - // inputVar -- all input variables - // tag -- boundary condition tag - // eqnState -- equation of state - // trans -- unique_ptr model for viscosity - // turb -- turbulence model - // layer -- layer of ghost cell to return (first (closest) or second - // (farthest)) - - // the instance of primVars being acted upon should be the interior cell - // bordering the boundary - - // set ghost state equal to boundary state to start - auto ghostState = (*this); - - // face area vector (should always point out of domain) - // at lower surface normal should point out of domain for ghost cell calc - const auto isLower = surf % 2 == 1; - const auto normArea = isLower? -1.0 * areaVec : areaVec; - - // slip wall boundary condition - // ---------------------------------------------------------------------- - // slipWall is implemented as a reflection of the interior states so that - // there is no mass flow across the boundary. - if (bcType == "slipWall") { // for slip wall state should be reflected across - // boundary face, density and pressure stay equal - // to the boundary cell - const auto stateVel = this->Velocity(); - const auto normVelCellCenter = stateVel.DotProd(normArea); - - // for a slip wall the velocity of the boundary cell center is reflected - // across the boundary face to get the velocity at the ghost cell center - const auto ghostVel = stateVel - 2.0 * normArea * normVelCellCenter; - - ghostState.data_[1] = ghostVel.X(); - ghostState.data_[2] = ghostVel.Y(); - ghostState.data_[3] = ghostVel.Z(); - - // numerical BCs for rho and pressure, same as boundary state - // numerical BCs for turbulence variables - - // viscous wall boundary condition - // ------------------------------------------------------------------------- - // viscous wall uses the interior density and pressure, but flips the sign on - // the velocity so that the velocity at the boundary is 0. - } else if (bcType == "viscousWall") { // for viscous wall velocity at face - // should be 0.0, density and pressure - // stay equal to the boundary cell - const auto & bcData = inputVars.BCData(tag); - - // ghost cell velocity at cell center is set to opposite of velocity at - // boundary cell center so that velocity at face will be zero - // only true for low-Re wall treatment - const auto velWall = bcData->Velocity(); - const auto ghostVel = 2.0 * velWall - this->Velocity(); - ghostState.data_[1] = ghostVel.X(); - ghostState.data_[2] = ghostVel.Y(); - ghostState.data_[3] = ghostVel.Z(); - - if (bcData->IsIsothermal()) { //----------------------------------------- - const auto tWall = bcData->Temperature(); - // for wall law ghost velocity and turbulence variables calculated - // simultaneously - if (bcData->IsWallLaw()) { - wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), *this, wallDist, - inputVars.IsRANS()); - wVars = wl.IsothermalBCs(normArea, velWall, eqnState, thermo, trans, - turb, tWall, isLower); - - if (wVars.SwitchToLowRe()) { - const auto tGhost = 2.0 * tWall - this->Temperature(eqnState); - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - } else { - // use wall law heat flux to get ghost cell density - // need turbulent contribution because eddy viscosity is not 0 at wall - const auto kappa = trans->Conductivity(wVars.viscosity_, - wVars.temperature_, thermo) + - trans->TurbConductivity( - wVars.turbEddyVisc_, turb->TurbPrandtlNumber(), - wVars.temperature_, thermo); - // 2x wall distance as gradient length - const auto tGhost = tWall - wVars.heatFlux_ / kappa * 2.0 * wallDist; - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - } - - if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { - ghostState.data_[5] = 2.0 * wVars.tke_ - this->Tke(); - ghostState.data_[6] = 2.0 * wVars.sdr_ - this->Omega(); - if (layer > 1) { - ghostState.data_[5] = layer * ghostState.data_[5] - wVars.tke_; - ghostState.data_[6] = layer * ghostState.data_[6] - wVars.sdr_; - } - } - } else { // low-Re wall treatment - const auto tGhost = 2.0 * tWall - this->Temperature(eqnState); - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - } - } else if (bcData->IsConstantHeatFlux()) { //----------------------------- - // must nondimensionalize heat flux - const auto qWall = bcData->HeatFlux(); - if (bcData->IsWallLaw()) { - wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), *this, wallDist, - inputVars.IsRANS()); - wVars = wl.HeatFluxBCs(normArea, velWall, eqnState, thermo, trans, turb, - qWall, isLower); - - if (wVars.SwitchToLowRe()) { - // don't need turbulent contribution b/c eddy viscosity is 0 at wall - const auto t = this->Temperature(eqnState); - const auto mu = trans->EffectiveViscosity(t); - const auto kappa = trans->Conductivity(mu, t, thermo); - // 2x wall distance as gradient length - const auto tGhost = - this->Temperature(eqnState) - qWall / kappa * 2.0 * wallDist; - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - - } else { - // use wall law wall temperature to get ghost cell density - const auto tGhost = - 2.0 * wVars.temperature_ - this->Temperature(eqnState); - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - } - - if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { - ghostState.data_[5] = 2.0 * wVars.tke_ - this->Tke(); - ghostState.data_[6] = 2.0 * wVars.sdr_ - this->Omega(); - if (layer > 1) { - ghostState.data_[5] = layer * ghostState.data_[5] - wVars.tke_; - ghostState.data_[6] = layer * ghostState.data_[6] - wVars.sdr_; - } - } - } else { // low-Re wall treatment - // don't need turbulent contribution b/c eddy viscosity is 0 at wall - const auto t = this->Temperature(eqnState); - const auto mu = trans->EffectiveViscosity(t); - const auto kappa = trans->Conductivity(mu, t, thermo); - // 2x wall distance as gradient length - const auto tGhost = - this->Temperature(eqnState) - qWall / kappa * 2.0 * wallDist; - ghostState.data_[0] = eqnState->DensityTP(tGhost, ghostState.P()); - // numerical BCs for pressure, same as boundary state - } - } else { // default is adiabatic ----------------------------------------- - if (bcData->IsWallLaw()) { - wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), *this, wallDist, - inputVars.IsRANS()); - wVars = wl.AdiabaticBCs(normArea, velWall, eqnState, thermo, trans, - turb, isLower); - - if (inputVars.IsRANS() && !wVars.SwitchToLowRe()) { - ghostState.data_[5] = 2.0 * wVars.tke_ - this->Tke(); - ghostState.data_[6] = 2.0 * wVars.sdr_ - this->Omega(); - if (layer > 1) { - ghostState.data_[5] = layer * ghostState.data_[5] - wVars.tke_; - ghostState.data_[6] = layer * ghostState.data_[6] - wVars.sdr_; - } - } - } - // numerical BCs for pressure, density - same as boundary state - } - - // turbulence bcs - // for wall law, turbulence bcs are already calculated, unless low Re model - // should be used - if (inputVars.IsRANS() && (!bcData->IsWallLaw() || wVars.SwitchToLowRe())) { - // tke at cell center is set to opposite of tke at boundary cell center - // so that tke at face will be zero - ghostState.data_[5] = -1.0 * this->Tke(); - - const auto nuW = - trans->Viscosity(this->Temperature(eqnState)) / this->Rho(); - const auto wWall = trans->NondimScaling() * trans->NondimScaling() * - 60.0 * nuW / (wallDist * wallDist * turb->WallBeta()); - ghostState.data_[6] = 2.0 * wWall - this->Omega(); - - if (layer > 1) { - ghostState.data_[6] = layer * ghostState.data_[6] - wWall; - } - } - - // subsonic inflow boundary condition - // ------------------------------------------------------------------------- - // this boundary condition enforces density and velocity as freestream - // inputs - // (constant) and extrapolates from the interior state to get pressure - // this is a primative implementation, stagnationInlet or characteristic are - // better options - // set velocity and density to freestream values - } else if (bcType == "subsonicInflow") { - const auto & bcData = inputVars.BCData(tag); - - const auto ghostVel = bcData->Velocity(); - - ghostState.data_[0] = bcData->Density(); - ghostState.data_[1] = ghostVel.X(); - ghostState.data_[2] = ghostVel.Y(); - ghostState.data_[3] = ghostVel.Z(); - - // numerical bc for pressure, same as boundary state - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(ghostVel, - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(ghostVel, - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - } - - // subsonic outflow boundary condition - // ------------------------------------------------------------------------- - // this boundary condition enforces pressure as a freestream input (constant) - // and extrapolates density and velocity from the interior state - // this is a primative implementation, pressureOutlet or characteristic are - // better options - } else if (bcType == "subsonicOutflow") { // set pressure to freestream value - const auto & bcData = inputVars.BCData(tag); - ghostState.data_[4] = bcData->Pressure(); - - // numerical bcs for density, velocity -- equal to boundary cell - // numerical bcs for turbulence variables - - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - } - - // characteristic boundary condition - // ------------------------------------------------------------------------- - // this is a characteristic based boundary condition which is appropriate for - // subsonic and supersonic flow. It automatically switches between inflow - // and outflow as needed. It also automatically determines the number of - // characteristics that need to be specified at the boundary (subsonic vs - // supersonic) - } else if (bcType == "characteristic") { - const auto & bcData = inputVars.BCData(tag); - // freestream variables - const auto freeVel = bcData->Velocity(); - const primVars freeState(bcData->Density(), freeVel, bcData->Pressure()); - - // internal variables - const auto velIntNorm = this->Velocity().DotProd(normArea); - const auto SoSInt = eqnState->SoS(this->P(), this->Rho()); - const auto machInt = fabs(velIntNorm) / SoSInt; - - if (machInt >= 1.0 && velIntNorm < 0.0) { // supersonic inflow - // ----------------------------------------------------- - // characteristics all go into the domain, so use freestream values for - // both riemann invariants - ghostState = freeState; - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(freeVel, - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - - } else if (machInt >= 1.0 && velIntNorm >= 0.0) { // supersonic outflow - // ---------------------------------------------- - // characteristics all leave the domain, so use interior values for both - // riemann invariants - ghostState = (*this); - } else if (machInt < 1.0 && velIntNorm < 0.0) { // subsonic inflow - // ---------------------------------------------- - // characteristics go in both directions, use interior values for plus - // characteristic and freestream values for minus characteristic - const auto rhoSoSInt = this->Rho() * SoSInt; - const auto velDiff = freeState.Velocity() - this->Velocity(); - - // plus characteristic - ghostState.data_[4] = 0.5 * (freeState.P() + this->P() - - rhoSoSInt * normArea.DotProd(velDiff)); - // minus characteristic - ghostState.data_[0] = freeState.Rho() + (ghostState.P() - freeState.P()) / - (SoSInt * SoSInt); - ghostState.data_[1] = freeState.U() - - normArea.X() * (freeState.P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[2] = freeState.V() - - normArea.Y() * (freeState.P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[3] = freeState.W() - - normArea.Z() * (freeState.P() - ghostState.P()) / rhoSoSInt; - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(freeVel, - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - - } else if (machInt < 1.0 && velIntNorm >= 0.0) { // subsonic outflow - // ---------------------------------------------------------- - // characteristics go in both directions, use interior values for plus - // characteristic and freestream values for minus characteristic - const auto rhoSoSInt = this->Rho() * SoSInt; - ghostState.data_[4] = freeState.P(); // minus characteristic - // plus characteristic - ghostState.data_[0] = - this->Rho() + (ghostState.P() - this->P()) / (SoSInt * SoSInt); - ghostState.data_[1] = this->U() + normArea.X() * - (this->P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[2] = this->V() + normArea.Y() * - (this->P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[3] = this->W() + normArea.Z() * - (this->P() - ghostState.P()) / rhoSoSInt; - - // numerical bcs for turbulence variables - - } else { - cerr << "ERROR: flow condition for characteristic BC is not recognized!" - << endl; - cerr << "Interior state: " << (*this) << endl; - cerr << "Ghost state: " << ghostState << endl; - exit(EXIT_FAILURE); - } - - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(freeVel, - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - } - - // supersonic inflow boundary condition - // ------------------------------------------------------------------------- - // this boundary condition enforces the entire state as the specified - // freestream state - } else if (bcType == "supersonicInflow") { - const auto & bcData = inputVars.BCData(tag); - // physical boundary conditions - fix everything - const auto vel = bcData->Velocity(); - - ghostState.data_[0] = bcData->Density(); - ghostState.data_[1] = vel.X(); - ghostState.data_[2] = vel.Y(); - ghostState.data_[3] = vel.Z(); - ghostState.data_[4] = bcData->Pressure(); - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(vel, bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - - // supersonic outflow boundary condition - // -------------------------------------------------------------------------- - // this boundary condition enforces the entire state as extrapolated from - // the - // interior (zeroth order extrapolation) - } else if (bcType == "supersonicOutflow") { - // do nothing and return boundary state -- numerical BCs for all - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - } - - // stagnation inlet boundary condition - // -------------------------------------------------------------------------- - // this boundary condition is appropriate for subsonic flow. It is - // particularly well suited for internal flows. Implementation from Blazek - } else if (bcType == "stagnationInlet") { - const auto & bcData = inputVars.BCData(tag); - - const auto t = this->Temperature(eqnState); - const auto g = thermo->Gamma(t) - 1.0; - // calculate outgoing riemann invarient - const auto rNeg = this->Velocity().DotProd(normArea) - - 2.0 * this->SoS(thermo, eqnState) / g; - - // calculate SoS on boundary - const auto cosTheta = -1.0 * this->Velocity().DotProd(normArea) / - this->Velocity().Mag(); - const auto stagSoSsq = pow(this->SoS(thermo, eqnState), 2.0) + - 0.5 * g * this->Velocity().MagSq(); - - const auto sosB = -1.0 * rNeg * g / (g * cosTheta * cosTheta + 2.0) * - (1.0 + cosTheta * sqrt((g * cosTheta * cosTheta + 2.0) * - stagSoSsq / (g * rNeg * rNeg) - 0.5 * g)); - const auto tb = bcData->StagnationTemperature() * (sosB * sosB / stagSoSsq); - const auto pb = bcData->StagnationPressure() * - pow(sosB * sosB / stagSoSsq, thermo->Gamma(t) / g); - const auto vbMag = sqrt(2.0 / g * (bcData->StagnationTemperature() - tb)); - - ghostState.data_[0] = eqnState->DensityTP(tb, pb); - ghostState.data_[1] = vbMag * bcData->Direction().X(); - ghostState.data_[2] = vbMag * bcData->Direction().Y(); - ghostState.data_[3] = vbMag * bcData->Direction().Z(); - ghostState.data_[4] = pb; - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(ghostState.Velocity(), - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - - // assign farfield conditions to turbulence variables - if (inputVars.IsRANS()) { - ghostState.ApplyFarfieldTurbBC(ghostState.Velocity(), - bcData->TurbulenceIntensity(), - bcData->EddyViscosityRatio(), trans, - eqnState, turb); - } - } - - // pressure outlet boundary condition - // ----------------------------------------------------------------------- - // this boundary condition is appropriate for subsonic flow. Implementation - // from Blazek - } else if (bcType == "pressureOutlet") { - const auto & bcData = inputVars.BCData(tag); - - // nondimensional pressure from input file - const auto pb = bcData->Pressure(); - - const auto SoSInt = this->SoS(thermo, eqnState); - const auto rhoSoSInt = this->Rho() * SoSInt; - - ghostState.data_[4] = pb; - ghostState.data_[0] = this->Rho() + (ghostState.P() - this->P()) / - (SoSInt * SoSInt); - ghostState.data_[1] = this->U() + normArea.X() * - (this->P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[2] = this->V() + normArea.Y() * - (this->P() - ghostState.P()) / rhoSoSInt; - ghostState.data_[3] = this->W() + normArea.Z() * - (this->P() - ghostState.P()) / rhoSoSInt; - - // numerical bcs for turbulence variables - - if (layer > 1) { // extrapolate to get ghost state at deeper layers - ghostState = layer * ghostState - (*this); - } - - // connection boundary condition - // -------------------------------------------------------------------------- - // this boundary condition is appropriate for point matched interfaces between - // physical blocks or processor blocks - } else if (bcType == "interblock" || "periodic") { - // do nothing -- assign interior state to ghost state (already done) - // for second layer of ghost cells interior state should be 2nd interior - // cell - - } else { - cerr << "ERROR: Error in primVars::GetGhostState ghost state for BC type " - << bcType << " is not supported!" << endl; - cerr << "surface is " << surf << " and layer is " << layer << endl; - exit(EXIT_FAILURE); - } - - return ghostState; -} - -// member function to take in a genArray of updates to the conservative -// variables, and update the primative variables with it. -// this is used in the implicit solver -primVars primVars::UpdateWithConsVars(const unique_ptr &eqnState, - const unique_ptr &thermo, - const genArray &du, - const unique_ptr &turb) const { - // eqnState -- equation of state - // du -- updates to conservative variables - // turb -- turbulence model - - // convert primative to conservative and update - const auto consUpdate = this->ConsVars(eqnState, thermo) + du; - - return primVars(consUpdate, false, eqnState, thermo, turb); -} - -bool primVars::IsZero() const { - auto nonzero = false; - for (auto &var : data_) { - if (var != 0.0) { - nonzero = true; - break; - } - } - return !nonzero; -} - -// member function to apply farfield turbulence boundary conditions -// using the method in STAR-CCM+ involving turbulence intensity and -// eddy viscosity ratio -void primVars::ApplyFarfieldTurbBC(const vector3d &vel, - const double &turbInten, - const double &viscRatio, - const unique_ptr &trans, - const unique_ptr &eqnState, - const unique_ptr &turb) { - // vel -- reference velocity (nondimensionalized) - // turbInten -- turbulence intensity at farfield - // viscRatio -- eddy viscosity ratio at farfield - // trans -- viscous transport model - // eqnState -- equation of state - // turb -- turbulence model - - data_[5] = 1.5 * pow(turbInten * vel.Mag(), 2.0); - data_[6] = data_[0] * data_[5] / - (viscRatio * trans->Viscosity(this->Temperature(eqnState))); - this->LimitTurb(turb); -} - -void primVars::LimitTurb(const unique_ptr &turb) { - // Adjust turbulence variables to be above minimum if necessary - data_[5] = max(data_[5], turb->TkeMin()); - data_[6] = max(data_[6], turb->OmegaMin()); -} - -/*Function to return the inviscid spectral radius for one direction (i, j, or k) -given a cell state, equation of state, and 2 face area vectors - -L = 0.5 * (A1 + A2) * (|Vn| + SoS) - -In the above equation L is the spectral radius in either the i, j, or k -direction. A1 and A2 are the two face areas in that direction. Vn is the -cell velocity normal to that direction. SoS is the speed of sound at the cell - */ -double primVars::InvCellSpectralRadius(const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR, - const unique_ptr &thermo, - const unique_ptr &eqnState) const { - // fAreaL -- face area of lower face in either i, j, or k direction - // fAreaR -- face area of upper face in either i, j, or k direction - // thermo -- thermodynamic model - // eqnState -- equation of state - - // normalize face areas - const auto normAvg = (0.5 * (fAreaL.UnitVector() + - fAreaR.UnitVector())).Normalize(); - // average area magnitude - const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); - - // return spectral radius - return (fabs(this->Velocity().DotProd(normAvg)) + - this->SoS(thermo, eqnState)) * - fMag; -} - -double primVars::InvFaceSpectralRadius(const unitVec3dMag &fArea, - const unique_ptr &thermo, - const unique_ptr &eqnState) const { - // fArea -- face area - // thermo -- thermodynamic model - // eqnState -- equation of state - - // return spectral radius - return 0.5 * fArea.Mag() * (fabs(this->Velocity().DotProd(fArea.UnitVector())) - + this->SoS(thermo, eqnState)); -} - -/*Function to calculate the viscous spectral radius for one direction (i, j, or -k). - -L = max(4/(3*rho), g/rho) * mu/Pr * A^2 / V - -In the above equation L is the viscous spectral radius for a given direction (i, -j, or k). Rho is the density at the cell center. G is gamma, mu is viscosity, -and Pr is the Prandtl number (all at the cell center). A is the average face area -of the given direction (i, j, k), and V is the cell volume. This implementation -comes from Blazek. - */ -double primVars::ViscCellSpectralRadius( - const unitVec3dMag &fAreaL, const unitVec3dMag &fAreaR, - const unique_ptr &thermo, const unique_ptr &eqnState, - const unique_ptr &trans, const double &vol, const double &mu, - const double &mut, const unique_ptr &turb) const { - // fAreaL -- face area of lower face in either i, j, or k direction - // fAreaR -- face area of upper face in either i, j, or k direction - // thermo -- thermodynamic model - // eqnState -- equation of state - // trans -- viscous transport model - // vol -- cell volume - // mu -- laminar viscosity - // mut -- turbulent viscosity - // turb -- turbulence model - - // average area magnitude - const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); - const auto t = this->Temperature(eqnState); - const auto maxTerm = - max(4.0 / (3.0 * this->Rho()), thermo->Gamma(t) / this->Rho()); - // viscous term - const auto viscTerm = trans->NondimScaling() * - (mu / thermo->Prandtl(t) + mut / turb->TurbPrandtlNumber()); - - // return viscous spectral radius - return maxTerm * viscTerm * fMag * fMag / vol; -} - -double primVars::ViscFaceSpectralRadius( - const unitVec3dMag &fArea, const unique_ptr &thermo, - const unique_ptr &eqnState, const unique_ptr &trans, - const double &dist, const double &mu, const double &mut, - const unique_ptr &turb) const { - // fArea -- face area - // thermo -- thermodynamic model - // eqnState -- equation of state - // trans -- viscous transport model - // dist -- distacne from cell center to cell center - // mu -- laminar viscosity - // mut -- turbulent viscosity - // turb -- turbulence model - - const auto t = this->Temperature(eqnState); - const auto maxTerm = - max(4.0 / (3.0 * this->Rho()), thermo->Gamma(t) / this->Rho()); - // viscous term - const auto viscTerm = trans->NondimScaling() * - (mu / thermo->Prandtl(t) + mut / turb->TurbPrandtlNumber()); - - // return viscous spectral radius - return fArea.Mag() / dist * maxTerm * viscTerm; -} - -double primVars::CellSpectralRadius( - const unitVec3dMag &fAreaL, const unitVec3dMag &fAreaR, - const unique_ptr &thermo, const unique_ptr &eqnState, - const unique_ptr &trans, const double &vol, const double &mu, - const double &mut, const unique_ptr &turb, - const bool &isViscous) const { - // fAreaL -- face area of lower face in either i, j, or k direction - // fAreaR -- face area of upper face in either i, j, or k direction - // thermo -- thermodynamic model - // eqnState -- equation of state - // trans -- viscous transport model - // vol -- cell volume - // mu -- laminar viscosity - // mut -- turbulent viscosity - // turb -- turbulence model - // isViscous -- flag that is true if simulation is viscous - - auto specRad = this->InvCellSpectralRadius(fAreaL, fAreaR, thermo, eqnState); - - if (isViscous) { - // factor 2 2 because viscous spectral radius is not halved (Blazek 6.53) - specRad += 2.0 * - this->ViscCellSpectralRadius(fAreaL, fAreaR, thermo, eqnState, - trans, vol, mu, mut, turb); - } - return specRad; -} - -double primVars::FaceSpectralRadius(const unitVec3dMag &fArea, - const unique_ptr &thermo, - const unique_ptr &eqnState, - const unique_ptr &trans, - const double &dist, const double &mu, - const double &mut, - const unique_ptr &turb, - const bool &isViscous) const { - // fAreaL -- face area - // thermo -- thermodynamic model - // eqnState -- equation of state - // trans -- viscous transport model - // dist -- distance from cell center to cell center - // mu -- laminar viscosity - // mut -- turbulent viscosity - // turb -- turbulence model - // isViscous -- flag that is true if simulation is viscous - - auto specRad = this->InvFaceSpectralRadius(fArea, thermo, eqnState); - - if (isViscous) { - specRad += this->ViscFaceSpectralRadius(fArea, thermo, eqnState, trans, - dist, mu, mut, turb); - } - return specRad; -} - - -// function to calculate the Roe averaged state -primVars RoeAveragedState(const primVars &left, const primVars &right) { - // compute Rho averaged quantities - // density ratio - const auto denRatio = sqrt(right.Rho() / left.Rho()); - // Roe averaged density - const auto rhoR = left.Rho() * denRatio; - // Roe averaged velocities - u, v, w - const auto uR = (left.U() + denRatio * right.U()) / (1.0 + denRatio); - const auto vR = (left.V() + denRatio * right.V()) / (1.0 + denRatio); - const auto wR = (left.W() + denRatio * right.W()) / (1.0 + denRatio); - - // Roe averaged pressure - const auto pR = (left.P() + denRatio * right.P()) / (1.0 + denRatio); - - // Roe averaged tke - const auto kR = (left.Tke() + denRatio * right.Tke()) / (1.0 + denRatio); - // Roe averaged specific dissipation (omega) - const auto omR = (left.Omega() + denRatio * right.Omega()) / (1.0 + denRatio); - - return primVars(rhoR, uR, vR, wR, pR, kR, omR); -} - -// return element by element squared values -primVars primVars::Squared() const { - return (*this) * (*this); -} - -// return element by element absolute value -primVars primVars::Abs() const { - auto abs = *this; - for (auto &val : abs.data_) { - val = fabs(val); - } - return abs; -} diff --git a/src/primitive.cpp b/src/primitive.cpp new file mode 100644 index 0000000..fe3158b --- /dev/null +++ b/src/primitive.cpp @@ -0,0 +1,114 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include // max +#include "primitive.hpp" +#include "input.hpp" // input +#include "physicsModels.hpp" +#include "utility.hpp" +#include "wallLaw.hpp" +#include "wallData.hpp" + +using std::cout; +using std::endl; +using std::cerr; +using std::vector; +using std::string; +using std::max; +using std::min; +using std::unique_ptr; + +// member function to initialize a state with nondimensional values +void primitive::NondimensionalInitialize(const physics &phys, const input &inp, + const int &parBlock) { + // get initial condition state for parent block + auto ic = inp.ICStateForBlock(parBlock); + auto massFracs = ic.MassFractions(); + + for (auto &mf : massFracs) { + auto ind = inp.SpeciesIndex(mf.first); + (*this)[ind] = mf.second * ic.Density(); + } + + (*this)[this->MomentumXIndex()] = ic.Velocity().X(); + (*this)[this->MomentumYIndex()] = ic.Velocity().Y(); + (*this)[this->MomentumZIndex()] = ic.Velocity().Z(); + + (*this)[this->EnergyIndex()] = ic.Pressure(); + + if (this->HasTurbulenceData()) { + // Initialize turbulence quantities based off of specified turublence + // intensity and eddy viscosity ratio. This is the default for + // STAR-CCM+ + this->ApplyFarfieldTurbBC(this->Velocity(), ic.TurbulenceIntensity(), + ic.EddyViscosityRatio(), phys); + } +} + +// operator overload for << - allows use of cout, cerr, etc. +ostream &operator<<(ostream &os, const primitive &prim) { + for (auto rr = 0; rr < prim.Size(); rr++) { + os << prim[rr] << endl; + } + return os; +} + +primitive primitive::UpdateWithConsVars(const physics &phys, + const varArrayView &du) const { + return UpdatePrimWithCons((*this), phys, du); +} + +// member function to apply farfield turbulence boundary conditions +// using the method in STAR-CCM+ involving turbulence intensity and +// eddy viscosity ratio +void primitive::ApplyFarfieldTurbBC(const vector3d &vel, + const double &turbInten, + const double &viscRatio, + const physics &phys) { + // vel -- reference velocity (nondimensionalized) + // turbInten -- turbulence intensity at farfield + // viscRatio -- eddy viscosity ratio at farfield + // phys -- physics models + + (*this)[this->TurbulenceIndex()] = 1.5 * pow(turbInten * vel.Mag(), 2.0); + (*this)[this->TurbulenceIndex() + 1] = + this->Rho() * this->Tke() / + (viscRatio * phys.Transport()->Viscosity(this->Temperature(phys.EoS()), + this->MassFractions())); + this->LimitTurb(phys.Turbulence()); +} + +void primitive::LimitTurb(const unique_ptr &turb) { + // Adjust turbulence variables to be above minimum if necessary + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[this->TurbulenceIndex() + ii] = + max((*this)[TurbulenceIndex() + ii], turb->TurbMinN(ii)); + } +} + +// return element by element absolute value +primitive primitive::Abs() const { + auto abs = *this; + std::transform(std::begin(*this), std::end(*this), std::begin(abs), + [](const double &val) { return fabs(val); }); + return abs; +} diff --git a/src/procBlock.cpp b/src/procBlock.cpp index 4b74697..f78eed1 100644 --- a/src/procBlock.cpp +++ b/src/procBlock.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,6 +36,11 @@ #include "kdtree.hpp" #include "utility.hpp" #include "wallData.hpp" +#include "reconstruction.hpp" +#include "spectralRadius.hpp" +#include "ghostStates.hpp" +#include "matMultiArray3d.hpp" +#include "physicsModels.hpp" using std::cout; using std::endl; @@ -71,7 +76,7 @@ procBlock::procBlock(const plot3dBlock &blk, const int &numBlk, if (bound.GetBCTypes(ii) == "viscousWall") { const auto surf = bound.GetSurface(ii); const auto &bcData = inp.BCData(surf.Tag()); - wallData_.push_back(wallData(surf, bcData)); + wallData_.push_back(wallData(surf, bcData, inp.NumSpecies())); } } @@ -80,6 +85,7 @@ procBlock::procBlock(const plot3dBlock &blk, const int &numBlk, isRANS_ = inp.IsRANS(); storeTimeN_ = inp.NeedToStoreTimeN(); isMultiLevelTime_ = inp.IsMultilevelInTime(); + isMultiSpecies_ = inp.IsMultiSpecies(); // dimensions for multiArray3d located at cell centers const auto numI = blk.NumI() - 1; @@ -87,17 +93,21 @@ procBlock::procBlock(const plot3dBlock &blk, const int &numBlk, const auto numK = blk.NumK() - 1; // pad stored variable vectors with ghost cells - state_ = PadWithGhosts(multiArray3d(numI, numJ, numK, 0, - primVars(0.0)), numGhosts_); + state_ = PadWithGhosts( + blkMultiArray3d(numI, numJ, numK, 0, inp.NumEquations(), + inp.NumSpecies(), 0.0), + numGhosts_); if (storeTimeN_) { - consVarsN_ = {numI, numJ, numK, 0, genArray(0.0)}; + consVarsN_ = {numI, numJ, numK, 0, inp.NumEquations(), inp.NumSpecies(), + 0.0}; } else { - consVarsN_ = {0, 0, 0, 0}; + consVarsN_ = {}; } if (isMultiLevelTime_) { - consVarsNm1_ = {numI, numJ, numK, 0, genArray(0.0)}; + consVarsNm1_ = {numI, numJ, numK, 0, inp.NumEquations(), inp.NumSpecies(), + 0.0}; } else { - consVarsNm1_ = {0, 0, 0, 0}; + consVarsNm1_ = {}; } vol_ = PadWithGhosts(blk.Volume(), numGhosts_); @@ -113,48 +123,59 @@ procBlock::procBlock(const plot3dBlock &blk, const int &numBlk, cellWidthJ_ = {numI, numJ, numK, numGhosts_}; cellWidthK_ = {numI, numJ, numK, numGhosts_}; - wallDist_ = {numI, numJ, numK, numGhosts_, DEFAULTWALLDIST}; + wallDist_ = {numI, numJ, numK, numGhosts_, 1, DEFAULT_WALL_DIST}; specRadius_ = {numI, numJ, numK, 0}; dt_ = {numI, numJ, numK, 0}; - residual_ = {numI, numJ, numK, 0}; + residual_ = {numI, numJ, numK, 0, inp.NumEquations(), inp.NumSpecies(), 0.0}; - temperature_ = {numI, numJ, numK, numGhosts_, 0.0}; + temperature_ = {numI, numJ, numK, numGhosts_, 1, 0.0}; + + // gradients + // vel grad ghosts for off diag term along interblock bc in implicit solver + velocityGrad_ = {numI, numJ, numK, numGhosts_}; + temperatureGrad_ = {numI, numJ, numK, 0}; + densityGrad_ = {numI, numJ, numK, 0}; + pressureGrad_ = {numI, numJ, numK, 0}; if (isViscous_) { - velocityGrad_ = {numI, numJ, numK, numGhosts_}; - temperatureGrad_ = {numI, numJ, numK, numGhosts_}; - viscosity_ = {numI, numJ, numK, numGhosts_, 0.0}; + viscosity_ = {numI, numJ, numK, numGhosts_, 1, 0.0}; } else { - velocityGrad_ = {0, 0, 0, 0}; - temperatureGrad_ = {0, 0, 0, 0}; - viscosity_ = {0, 0, 0, 0}; + viscosity_ = {}; } if (isTurbulent_) { - eddyViscosity_ = {numI, numJ, numK, numGhosts_, 0.0}; + eddyViscosity_ = {numI, numJ, numK, numGhosts_, 1, 0.0}; } else { - eddyViscosity_ = {0, 0, 0, 0, 0.0}; + eddyViscosity_ = {}; } if (isRANS_) { - tkeGrad_ = {numI, numJ, numK, numGhosts_}; - omegaGrad_ = {numI, numJ, numK, numGhosts_}; - f1_ = {numI, numJ, numK, numGhosts_, 1.0}; - f2_ = {numI, numJ, numK, numGhosts_, 0.0}; + tkeGrad_ = {numI, numJ, numK, 0}; + omegaGrad_ = {numI, numJ, numK, 0}; + f1_ = {numI, numJ, numK, numGhosts_, 1, 1.0}; + f2_ = {numI, numJ, numK, numGhosts_, 1, 0.0}; + } else { + tkeGrad_ = {}; + omegaGrad_ = {}; + f1_ = {}; + f2_ = {}; + } + + if (isMultiSpecies_) { + mixtureGrad_ = {numI, numJ, numK, 0, inp.NumSpecies()}; } else { - tkeGrad_ = {0, 0, 0, 0}; - omegaGrad_ = {0, 0, 0, 0}; - f1_ = {0, 0, 0, 0, 0.0}; - f2_ = {0, 0, 0, 0, 0.0}; + mixtureGrad_ = {}; } } // constructor -- allocate space for procBlock procBlock::procBlock(const int &ni, const int &nj, const int &nk, - const int &numG, const bool &isViscous, - const bool &isTurbulent, const bool &isRANS, - const bool &storeTimeN, const bool &isMultiLevelInTime) { + const int &numG, const int &numEqns, const int &numSpecies, + const bool &isViscous, const bool &isTurbulent, + const bool &isRANS, const bool &storeTimeN, + const bool &isMultiLevelInTime, + const bool &isMultiSpecies) { // ni -- i-dimension (cell) // nj -- j-dimension (cell) // nk -- k-dimension (cell) @@ -177,18 +198,19 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, isRANS_ = isRANS; storeTimeN_ = storeTimeN; isMultiLevelTime_ = isMultiLevelInTime; + isMultiSpecies_ = isMultiSpecies; // pad stored variable vectors with ghost cells - state_ = {ni, nj, nk, numGhosts_}; + state_ = {ni, nj, nk, numGhosts_, numEqns, numSpecies}; if (storeTimeN) { - consVarsN_ = {ni, nj, nk, 0}; + consVarsN_ = {ni, nj, nk, 0, numEqns, numSpecies}; } else { - consVarsN_ = {0, 0, 0, 0}; + consVarsN_ = {}; } if (isMultiLevelTime_) { - consVarsNm1_ = {ni, nj, nk, 0}; + consVarsNm1_ = {ni, nj, nk, 0, numEqns, numSpecies}; } else { - consVarsNm1_ = {0, 0, 0, 0}; + consVarsNm1_ = {}; } center_ = {ni, nj, nk, numGhosts_}; fAreaI_ = {ni + 1, nj, nk, numGhosts_}; @@ -197,9 +219,9 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, fCenterI_ = {ni + 1, nj, nk, numGhosts_}; fCenterJ_ = {ni, nj + 1, nk, numGhosts_}; fCenterK_ = {ni, nj, nk + 1, numGhosts_}; - residual_ = {ni, nj, nk, 0}; + residual_ = {ni, nj, nk, 0, numEqns, numSpecies}; vol_ = {ni, nj, nk, numGhosts_}; - wallDist_ = {ni, nj, nk, numGhosts_, DEFAULTWALLDIST}; + wallDist_ = {ni, nj, nk, numGhosts_, 1, DEFAULT_WALL_DIST}; cellWidthI_ = {ni, nj, nk, numGhosts_}; cellWidthJ_ = {ni, nj, nk, numGhosts_}; @@ -210,141 +232,59 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, temperature_ = {ni, nj, nk, numGhosts_}; + // gradients + // vel grad ghosts for off diag term along interblock bc in implicit solver + velocityGrad_ = {ni, nj, nk, numGhosts_}; + temperatureGrad_ = {ni, nj, nk, 0}; + densityGrad_ = {ni, nj, nk, 0}; + pressureGrad_ = {ni, nj, nk, 0}; + if (isViscous_) { - velocityGrad_ = {ni, nj, nk, numGhosts_}; - temperatureGrad_ = {ni, nj, nk, numGhosts_}; viscosity_ = {ni, nj, nk, numGhosts_}; } else { - velocityGrad_ = {0, 0, 0, 0}; - temperatureGrad_ = {0, 0, 0, 0}; - viscosity_ = {0, 0, 0, 0}; + viscosity_ = {}; } if (isTurbulent_) { eddyViscosity_ = {ni, nj, nk, numGhosts_}; } else { - eddyViscosity_ = {0, 0, 0, 0}; + eddyViscosity_ = {}; } if (isRANS_) { - tkeGrad_ = {ni, nj, nk, numGhosts_}; - omegaGrad_ = {ni, nj, nk, numGhosts_}; + tkeGrad_ = {ni, nj, nk, 0}; + omegaGrad_ = {ni, nj, nk, 0}; f1_ = {ni, nj, nk, numGhosts_}; f2_ = {ni, nj, nk, numGhosts_}; } else { - tkeGrad_ = {0, 0, 0, 0}; - omegaGrad_ = {0, 0, 0, 0}; - f1_ = {0, 0, 0, 0}; - f2_ = {0, 0, 0, 0}; + tkeGrad_ = {}; + omegaGrad_ = {}; + f1_ = {}; + f2_ = {}; } -} - -// member function to add a member of the inviscid flux class to the residual -void procBlock::AddToResidual(const inviscidFlux &flux, const int &ii, - const int &jj, const int &kk) { - // flux -- inviscid flux to add to residual - // ii -- i-location of residual to add to - // jj -- j-location of residual to add to - // kk -- k-location of residual to add to - - residual_(ii, jj, kk)[0] += flux.RhoVel(); - residual_(ii, jj, kk)[1] += flux.RhoVelU(); - residual_(ii, jj, kk)[2] += flux.RhoVelV(); - residual_(ii, jj, kk)[3] += flux.RhoVelW(); - residual_(ii, jj, kk)[4] += flux.RhoVelH(); - residual_(ii, jj, kk)[5] += flux.RhoVelK(); - residual_(ii, jj, kk)[6] += flux.RhoVelO(); -} - -// member function to subtract a member of the inviscid flux class from the -// residual -void procBlock::SubtractFromResidual(const inviscidFlux &flux, const int &ii, - const int &jj, const int &kk) { - // flux -- inviscid flux to add to residual - // ii -- i-location of residual to add to - // jj -- j-location of residual to add to - // kk -- k-location of residual to add to - - residual_(ii, jj, kk)[0] -= flux.RhoVel(); - residual_(ii, jj, kk)[1] -= flux.RhoVelU(); - residual_(ii, jj, kk)[2] -= flux.RhoVelV(); - residual_(ii, jj, kk)[3] -= flux.RhoVelW(); - residual_(ii, jj, kk)[4] -= flux.RhoVelH(); - residual_(ii, jj, kk)[5] -= flux.RhoVelK(); - residual_(ii, jj, kk)[6] -= flux.RhoVelO(); -} - -// member function to add a member of the viscous flux class to the residual_ -void procBlock::AddToResidual(const viscousFlux &flux, const int &ii, - const int &jj, const int &kk) { - // flux -- inviscid flux to add to residual - // ii -- location of residual_ to add to - // jj -- j-location of residual to add to - // kk -- k-location of residual to add to - - residual_(ii, jj, kk)[1] += flux.MomX(); - residual_(ii, jj, kk)[2] += flux.MomY(); - residual_(ii, jj, kk)[3] += flux.MomZ(); - residual_(ii, jj, kk)[4] += flux.Engy(); - residual_(ii, jj, kk)[5] += flux.MomK(); - residual_(ii, jj, kk)[6] += flux.MomO(); -} -// member function to subtract a member of the viscous flux class from the -// residual -void procBlock::SubtractFromResidual(const viscousFlux &flux, const int &ii, - const int &jj, const int &kk) { - // flux -- inviscid flux to add to residual_ - // ii -- location of residual_ to add to - // jj -- j-location of residual to add to - // kk -- k-location of residual to add to - - residual_(ii, jj, kk)[1] -= flux.MomX(); - residual_(ii, jj, kk)[2] -= flux.MomY(); - residual_(ii, jj, kk)[3] -= flux.MomZ(); - residual_(ii, jj, kk)[4] -= flux.Engy(); - residual_(ii, jj, kk)[5] -= flux.MomK(); - residual_(ii, jj, kk)[6] -= flux.MomO(); -} - - -// member function to subtract a member of the inviscid source class from the -// residual -void procBlock::SubtractFromResidual(const source &src, const int &ii, - const int &jj, const int &kk) { - // src -- source to add to residual - // ii -- location of residual to add to - // jj -- j-location of residual to add to - // kk -- k-location of residual to add to - - residual_(ii, jj, kk)[0] -= src.SrcMass(); - residual_(ii, jj, kk)[1] -= src.SrcMomX(); - residual_(ii, jj, kk)[2] -= src.SrcMomY(); - residual_(ii, jj, kk)[3] -= src.SrcMomZ(); - residual_(ii, jj, kk)[4] -= src.SrcEngy(); - residual_(ii, jj, kk)[5] -= src.SrcTke(); - residual_(ii, jj, kk)[6] -= src.SrcOmg(); + if (isMultiSpecies) { + mixtureGrad_ = {ni, nj, nk, 0, numSpecies}; + } else { + mixtureGrad_ = {}; + } } //--------------------------------------------------------------------- // function declarations - -void procBlock::InitializeStates(const input &inp, - const unique_ptr &eqnState, - const unique_ptr &trans, - const unique_ptr &turb) { +void procBlock::InitializeStates(const input &inp, const physics &phys) { // inp -- input variables - // eqnState -- equation of state - // trans -- transport model - // turb -- turbulence model + // phys -- physics models // get initial condition state for parent block auto ic = inp.ICStateForBlock(parBlock_); if (ic.IsFromFile()) { // create k-d tree from cloud of points - vector cloudStates; - const auto tree = CalcTreeFromCloud(ic.File(), inp, trans, cloudStates); + vector cloudStates; + vector species; + const auto tree = CalcTreeFromCloud(ic.File(), inp, phys.Transport(), + cloudStates, species); auto maxDist = std::numeric_limits::min(); vector3d neighbor; @@ -355,13 +295,17 @@ void procBlock::InitializeStates(const input &inp, for (auto ii = this->StartI(); ii < this->EndI(); ii++) { auto dist = tree.NearestNeighbor(center_(ii, jj, kk), neighbor, id); maxDist = std::max(dist, maxDist); - state_(ii, jj, kk) = cloudStates[id]; - temperature_(ii, jj, kk) = state_(ii, jj, kk).Temperature(eqnState); + state_.InsertBlock(ii, jj, kk, cloudStates[id]); + MSG_ASSERT(state_(ii, jj, kk).Rho() > 0, "nonphysical density"); + MSG_ASSERT(state_(ii, jj, kk).P() > 0, "nonphysical pressure"); + temperature_(ii, jj, kk) = state_(ii, jj, kk).Temperature(phys.EoS()); + MSG_ASSERT(temperature_(ii, jj, kk) > 0, "nonphysical temperature"); if (inp.IsViscous()) { - viscosity_(ii, jj, kk) = trans->Viscosity(temperature_(ii, jj, kk)); + viscosity_(ii, jj, kk) = phys.Transport()->Viscosity( + temperature_(ii, jj, kk), state_(ii, jj, kk).MassFractions()); if (inp.IsTurbulent()) { eddyViscosity_(ii, jj, kk) = - turb->EddyViscNoLim(state_(ii, jj, kk)); + phys.Turbulence()->EddyViscNoLim(state_(ii, jj, kk)); } } } @@ -375,8 +319,10 @@ void procBlock::InitializeStates(const input &inp, } else { // get nondimensional state for initialization - primVars inputState; - inputState.NondimensionalInitialize(eqnState, inp, trans, parBlock_, turb); + primitive inputState(inp.NumEquations(), inp.NumSpecies()); + inputState.NondimensionalInitialize(phys, inp, parBlock_); + MSG_ASSERT(inputState.Rho() > 0, "nonphysical density"); + MSG_ASSERT(inputState.P() > 0, "nonphysical pressure"); const auto numI = this->NumI(); const auto numJ = this->NumJ(); @@ -384,16 +330,19 @@ void procBlock::InitializeStates(const input &inp, // pad stored variable vectors with ghost cells state_ = PadWithGhosts( - multiArray3d(numI, numJ, numK, 0, inputState), numGhosts_); + blkMultiArray3d(numI, numJ, numK, 0, inputState), + numGhosts_); - const auto inputTemperature = inputState.Temperature(eqnState); - temperature_ = {numI, numJ, numK, numGhosts_, inputTemperature}; + const auto inputTemperature = inputState.Temperature(phys.EoS()); + MSG_ASSERT(inputTemperature > 0, "nonphysical temperature"); + temperature_ = {numI, numJ, numK, numGhosts_, 1, inputTemperature}; if (isViscous_) { - const auto inputViscosity = trans->Viscosity(inputTemperature); - viscosity_ = {numI, numJ, numK, numGhosts_, inputViscosity}; + const auto inputViscosity = phys.Transport()->Viscosity( + inputTemperature, inputState.MassFractions()); + viscosity_ = {numI, numJ, numK, numGhosts_, 1, inputViscosity}; if (isTurbulent_) { - eddyViscosity_ = {numI, numJ, numK, numGhosts_, + eddyViscosity_ = {numI, numJ, numK, numGhosts_, 1, ic.EddyViscosityRatio() * inputViscosity}; } } @@ -427,13 +376,9 @@ a cell basis instead of a face bases, it is only calculated for the upper cell variable and is eventually used in the time step calculation if the time step isn't explicitly specified. */ -void procBlock::CalcInvFluxI(const unique_ptr &eqnState, - const unique_ptr &thermo, - const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { - // eqnState -- equation of state - // thermo -- thermodynamic model +void procBlock::CalcInvFluxI(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { + // phys -- physics models // inp -- all input variables // mainDiagonal -- main diagonal of LHS to store flux jacobians for implicit // solver @@ -442,77 +387,87 @@ void procBlock::CalcInvFluxI(const unique_ptr &eqnState, for (auto kk = fAreaI_.PhysStartK(); kk < fAreaI_.PhysEndK(); kk++) { for (auto jj = fAreaI_.PhysStartJ(); jj < fAreaI_.PhysEndJ(); jj++) { for (auto ii = fAreaI_.PhysStartI(); ii < fAreaI_.PhysEndI(); ii++) { - primVars faceStateLower, faceStateUpper; + primitive faceStateLower; + primitive faceStateUpper; // use constant reconstruction (first order) if (inp.OrderOfAccuracy() == "first") { - faceStateLower = state_(ii - 1, jj, kk).FaceReconConst(); - faceStateUpper = state_(ii, jj, kk).FaceReconConst(); + faceStateLower = FaceReconConst(state_(ii - 1, jj, kk)); + faceStateUpper = FaceReconConst(state_(ii, jj, kk)); } else { // second order accuracy if (inp.UsingMUSCLReconstruction()) { - faceStateLower = state_(ii - 1, jj, kk).FaceReconMUSCL( - state_(ii - 2, jj, kk), state_(ii, jj, kk), - inp.Kappa(), inp.Limiter(), cellWidthI_(ii - 1, jj, kk), - cellWidthI_(ii - 2, jj, kk), cellWidthI_(ii, jj, kk)); + faceStateLower = FaceReconMUSCL( + state_(ii - 2, jj, kk), state_(ii - 1, jj, kk), + state_(ii, jj, kk), inp.Kappa(), inp.Limiter(), + cellWidthI_(ii - 2, jj, kk), cellWidthI_(ii - 1, jj, kk), + cellWidthI_(ii, jj, kk)); - faceStateUpper = state_(ii, jj, kk).FaceReconMUSCL( - state_(ii + 1, jj, kk), state_(ii - 1, jj, kk), - inp.Kappa(), inp.Limiter(), cellWidthI_(ii, jj, kk), - cellWidthI_(ii + 1, jj, kk), cellWidthI_(ii - 1, jj, kk)); + faceStateUpper = FaceReconMUSCL( + state_(ii + 1, jj, kk), state_(ii, jj, kk), + state_(ii - 1, jj, kk), inp.Kappa(), inp.Limiter(), + cellWidthI_(ii + 1, jj, kk), cellWidthI_(ii, jj, kk), + cellWidthI_(ii - 1, jj, kk)); } else { // using higher order reconstruction (weno, wenoz) - faceStateLower = state_(ii - 1, jj, kk).FaceReconWENO( - state_(ii - 2, jj, kk), state_(ii - 3, jj, kk), - state_(ii, jj, kk), state_(ii + 1, jj, kk), - cellWidthI_(ii - 1, jj, kk), cellWidthI_(ii - 2, jj, kk), - cellWidthI_(ii - 3, jj, kk), cellWidthI_(ii, jj, kk), - cellWidthI_(ii + 1, jj, kk), inp.IsWenoZ()); - - faceStateUpper = state_(ii, jj, kk).FaceReconWENO( - state_(ii + 1, jj, kk), state_(ii + 2, jj, kk), - state_(ii - 1, jj, kk), state_(ii - 2, jj, kk), + faceStateLower = FaceReconWENO( + state_(ii - 3, jj, kk), state_(ii - 2, jj, kk), + state_(ii - 1, jj, kk), state_(ii, jj, kk), + state_(ii + 1, jj, kk), cellWidthI_(ii - 3, jj, kk), + cellWidthI_(ii - 2, jj, kk), cellWidthI_(ii - 1, jj, kk), cellWidthI_(ii, jj, kk), cellWidthI_(ii + 1, jj, kk), - cellWidthI_(ii + 2, jj, kk), cellWidthI_(ii - 1, jj, kk), - cellWidthI_(ii - 2, jj, kk), inp.IsWenoZ()); + inp.IsWenoZ()); + + faceStateUpper = FaceReconWENO( + state_(ii + 2, jj, kk), state_(ii + 1, jj, kk), + state_(ii, jj, kk), state_(ii - 1, jj, kk), + state_(ii - 2, jj, kk), cellWidthI_(ii + 2, jj, kk), + cellWidthI_(ii + 1, jj, kk), cellWidthI_(ii, jj, kk), + cellWidthI_(ii - 1, jj, kk), cellWidthI_(ii - 2, jj, kk), + inp.IsWenoZ()); } } + MSG_ASSERT(faceStateLower.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateLower.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(faceStateUpper.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateUpper.P() > 0.0, "nonphysical pressure"); // calculate inviscid flux at face const inviscidFlux tempFlux = - InviscidFlux(faceStateLower, faceStateUpper, eqnState, thermo, + InviscidFlux(faceStateLower, faceStateUpper, phys, this->FAreaUnitI(ii, jj, kk), inp.InviscidFlux()); // area vector points from left to right, so add to left cell, subtract // from right cell // at left boundary there is no left cell to add to if (ii > fAreaI_.PhysStartI()) { - this->AddToResidual(tempFlux * this->FAreaMagI(ii, jj, kk), - ii - 1, jj, kk); + this->AddToResidual(ii - 1, jj, kk, + tempFlux * this->FAreaMagI(ii, jj, kk)); // if using a block matrix on main diagonal, accumulate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateLower, eqnState, thermo, - this->FAreaI(ii, jj, kk), true, - inp, turb); - mainDiagonal(ii - 1, jj, kk) += fluxJac; + fluxJac.RusanovFluxJacobian(faceStateLower, phys, + this->FAreaI(ii, jj, kk), true, inp); + mainDiagonal.Add(ii - 1, jj, kk, fluxJac); } } // at right boundary there is no right cell to add to if (ii < fAreaI_.PhysEndI() - 1) { - this->SubtractFromResidual(tempFlux * - this->FAreaMagI(ii, jj, kk), - ii, jj, kk); + this->SubtractFromResidual(ii, jj, kk, + tempFlux * this->FAreaMagI(ii, jj, kk)); // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( - fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk), thermo, eqnState); + const auto invSpecRad = + InvCellSpectralRadius(state_(ii, jj, kk), fAreaI_(ii, jj, kk), + fAreaI_(ii + 1, jj, kk), phys); - const auto turbInvSpecRad = isRANS_ ? - turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaI_(ii, jj, kk), - fAreaI_(ii + 1, jj, kk)): 0.0; + const auto turbInvSpecRad = + isRANS_ ? phys.Turbulence()->InviscidCellSpecRad( + state_(ii, jj, kk), fAreaI_(ii, jj, kk), + fAreaI_(ii + 1, jj, kk)) + : 0.0; const uncoupledScalar specRad(invSpecRad, turbInvSpecRad); specRadius_(ii, jj, kk) += specRad; @@ -520,12 +475,11 @@ void procBlock::CalcInvFluxI(const unique_ptr &eqnState, // if using a block matrix on main diagonal, accumulate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateUpper, eqnState, thermo, - this->FAreaI(ii, jj, kk), false, - inp, turb); - mainDiagonal(ii, jj, kk) -= fluxJac; + fluxJac.RusanovFluxJacobian(faceStateUpper, phys, + this->FAreaI(ii, jj, kk), false, inp); + mainDiagonal.Subtract(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { - mainDiagonal(ii, jj, kk) += fluxJacobian(specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(specRad, isRANS_)); } } } @@ -560,13 +514,10 @@ a cell basis instead of a face bases, it is only calculated for the upper cell variable and is eventually used in the time step calculation if the time step isn't explicitly specified. */ -void procBlock::CalcInvFluxJ(const unique_ptr &eqnState, - const unique_ptr &thermo, +void procBlock::CalcInvFluxJ(const physics &phys, const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { - // eqnState -- equation of state - // thermo -- thermodynamic model + matMultiArray3d &mainDiagonal) { + // physics -- physics models // inp -- all input variables // mainDiagonal -- main diagonal of LHS to store flux jacobians for implicit // solver @@ -575,76 +526,86 @@ void procBlock::CalcInvFluxJ(const unique_ptr &eqnState, for (auto kk = fAreaJ_.PhysStartK(); kk < fAreaJ_.PhysEndK(); kk++) { for (auto jj = fAreaJ_.PhysStartJ(); jj < fAreaJ_.PhysEndJ(); jj++) { for (auto ii = fAreaJ_.PhysStartI(); ii < fAreaJ_.PhysEndI(); ii++) { - primVars faceStateLower, faceStateUpper; + primitive faceStateLower; + primitive faceStateUpper; // use constant reconstruction (first order) if (inp.OrderOfAccuracy() == "first") { - faceStateLower = state_(ii, jj - 1, kk).FaceReconConst(); - faceStateUpper = state_(ii, jj, kk).FaceReconConst(); + faceStateLower = FaceReconConst(state_(ii, jj - 1, kk)); + faceStateUpper = FaceReconConst(state_(ii, jj, kk)); } else { // second order accuracy if (inp.UsingMUSCLReconstruction()) { - faceStateLower = state_(ii, jj - 1, kk).FaceReconMUSCL( - state_(ii, jj - 2, kk), state_(ii, jj, kk), - inp.Kappa(), inp.Limiter(), cellWidthJ_(ii, jj - 1, kk), - cellWidthJ_(ii, jj - 2, kk), cellWidthJ_(ii, jj, kk)); + faceStateLower = FaceReconMUSCL( + state_(ii, jj - 2, kk), state_(ii, jj - 1, kk), + state_(ii, jj, kk), inp.Kappa(), inp.Limiter(), + cellWidthJ_(ii, jj - 2, kk), cellWidthJ_(ii, jj - 1, kk), + cellWidthJ_(ii, jj, kk)); - faceStateUpper = state_(ii, jj, kk).FaceReconMUSCL( - state_(ii, jj + 1, kk), state_(ii, jj - 1, kk), - inp.Kappa(), inp.Limiter(), cellWidthJ_(ii, jj, kk), - cellWidthJ_(ii, jj + 1, kk), cellWidthJ_(ii, jj - 1, kk)); + faceStateUpper = FaceReconMUSCL( + state_(ii, jj + 1, kk), state_(ii, jj, kk), + state_(ii, jj - 1, kk), inp.Kappa(), inp.Limiter(), + cellWidthJ_(ii, jj + 1, kk), cellWidthJ_(ii, jj, kk), + cellWidthJ_(ii, jj - 1, kk)); } else { // using higher order reconstruction (weno, wenoz) - faceStateLower = state_(ii, jj - 1, kk).FaceReconWENO( - state_(ii, jj - 2, kk), state_(ii, jj - 3, kk), - state_(ii, jj, kk), state_(ii, jj + 1, kk), - cellWidthJ_(ii, jj - 1, kk), cellWidthJ_(ii, jj - 2, kk), - cellWidthJ_(ii, jj - 3, kk), cellWidthJ_(ii, jj, kk), - cellWidthJ_(ii, jj + 1, kk), inp.IsWenoZ()); - - faceStateUpper = state_(ii, jj, kk).FaceReconWENO( - state_(ii, jj + 1, kk), state_(ii, jj + 2, kk), - state_(ii, jj - 1, kk), state_(ii, jj - 2, kk), + faceStateLower = FaceReconWENO( + state_(ii, jj - 3, kk), state_(ii, jj - 2, kk), + state_(ii, jj - 1, kk), state_(ii, jj, kk), + state_(ii, jj + 1, kk), cellWidthJ_(ii, jj - 3, kk), + cellWidthJ_(ii, jj - 2, kk), cellWidthJ_(ii, jj - 1, kk), cellWidthJ_(ii, jj, kk), cellWidthJ_(ii, jj + 1, kk), - cellWidthJ_(ii, jj + 2, kk), cellWidthJ_(ii, jj - 1, kk), - cellWidthJ_(ii, jj - 2, kk), inp.IsWenoZ()); + inp.IsWenoZ()); + + faceStateUpper = FaceReconWENO( + state_(ii, jj + 2, kk), state_(ii, jj + 1, kk), + state_(ii, jj, kk), state_(ii, jj - 1, kk), + state_(ii, jj - 2, kk), cellWidthJ_(ii, jj + 2, kk), + cellWidthJ_(ii, jj + 1, kk), cellWidthJ_(ii, jj, kk), + cellWidthJ_(ii, jj - 1, kk), cellWidthJ_(ii, jj - 2, kk), + inp.IsWenoZ()); } } + MSG_ASSERT(faceStateLower.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateLower.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(faceStateUpper.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateUpper.P() > 0.0, "nonphysical pressure"); // calculate inviscid flux at face const inviscidFlux tempFlux = - InviscidFlux(faceStateLower, faceStateUpper, eqnState, thermo, + InviscidFlux(faceStateLower, faceStateUpper, phys, this->FAreaUnitJ(ii, jj, kk), inp.InviscidFlux()); // area vector points from left to right, so add to left cell, subtract // from right cell // at left boundary no left cell to add to if (jj > fAreaJ_.PhysStartJ()) { - this->AddToResidual(tempFlux * this->FAreaMagJ(ii, jj, kk), - ii, jj - 1, kk); + this->AddToResidual(ii, jj - 1, kk, + tempFlux * this->FAreaMagJ(ii, jj, kk)); // if using block matrix on main diagonal, calculate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateLower, eqnState, thermo, - this->FAreaJ(ii, jj, kk), true, - inp, turb); - mainDiagonal(ii, jj - 1, kk) += fluxJac; + fluxJac.RusanovFluxJacobian(faceStateLower, phys, + this->FAreaJ(ii, jj, kk), true, inp); + mainDiagonal.Add(ii, jj - 1, kk, fluxJac); } } // at right boundary no right cell to add to if (jj < fAreaJ_.PhysEndJ() - 1) { - this->SubtractFromResidual(tempFlux * - this->FAreaMagJ(ii, jj, kk), - ii, jj, kk); + this->SubtractFromResidual(ii, jj, kk, + tempFlux * this->FAreaMagJ(ii, jj, kk)); // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( - fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk), thermo, eqnState); + const auto invSpecRad = + InvCellSpectralRadius(state_(ii, jj, kk), fAreaJ_(ii, jj, kk), + fAreaJ_(ii, jj + 1, kk), phys); - const auto turbInvSpecRad = isRANS_ ? - turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaJ_(ii, jj, kk), - fAreaJ_(ii, jj + 1, kk)): 0.0; + const auto turbInvSpecRad = + isRANS_ ? phys.Turbulence()->InviscidCellSpecRad( + state_(ii, jj, kk), fAreaJ_(ii, jj, kk), + fAreaJ_(ii, jj + 1, kk)) + : 0.0; const uncoupledScalar specRad(invSpecRad, turbInvSpecRad); specRadius_(ii, jj, kk) += specRad; @@ -652,12 +613,11 @@ void procBlock::CalcInvFluxJ(const unique_ptr &eqnState, // if using block matrix on main diagonal, calculate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateUpper, eqnState, thermo, - this->FAreaJ(ii, jj, kk), false, - inp, turb); - mainDiagonal(ii, jj, kk) -= fluxJac; + fluxJac.RusanovFluxJacobian(faceStateUpper, phys, + this->FAreaJ(ii, jj, kk), false, inp); + mainDiagonal.Subtract(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { - mainDiagonal(ii, jj, kk) += fluxJacobian(specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(specRad, isRANS_)); } } } @@ -692,13 +652,10 @@ a cell basis instead of a face bases, it is only calculated for the upper cell variable and is eventually used in the time step calculation if the time step isn't explicitly specified. */ -void procBlock::CalcInvFluxK(const unique_ptr &eqnState, - const unique_ptr &thermo, +void procBlock::CalcInvFluxK(const physics &phys, const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { - // eqnState -- equation of state - // thermo -- thermodynamic model + matMultiArray3d &mainDiagonal) { + // phys -- physics models // inp -- all input variables // mainDiagonal -- main diagonal of LHS to store flux jacobians for implicit // solver @@ -707,77 +664,86 @@ void procBlock::CalcInvFluxK(const unique_ptr &eqnState, for (auto kk = fAreaK_.PhysStartK(); kk < fAreaK_.PhysEndK(); kk++) { for (auto jj = fAreaK_.PhysStartJ(); jj < fAreaK_.PhysEndJ(); jj++) { for (auto ii = fAreaK_.PhysStartI(); ii < fAreaK_.PhysEndI(); ii++) { - primVars faceStateLower, faceStateUpper; + primitive faceStateLower; + primitive faceStateUpper; // use constant reconstruction (first order) if (inp.OrderOfAccuracy() == "first") { - faceStateLower = state_(ii, jj, kk - 1).FaceReconConst(); - faceStateUpper = state_(ii, jj, kk).FaceReconConst(); + faceStateLower = FaceReconConst(state_(ii, jj, kk - 1)); + faceStateUpper = FaceReconConst(state_(ii, jj, kk)); } else { // second order accuracy if (inp.UsingMUSCLReconstruction()) { - faceStateLower = state_(ii, jj, kk - 1).FaceReconMUSCL( - state_(ii, jj, kk - 2), state_(ii, jj, kk), - inp.Kappa(), inp.Limiter(), cellWidthK_(ii, jj, kk - 1), - cellWidthK_(ii, jj, kk - 2), cellWidthK_(ii, jj, kk)); + faceStateLower = FaceReconMUSCL( + state_(ii, jj, kk - 2), state_(ii, jj, kk - 1), + state_(ii, jj, kk), inp.Kappa(), inp.Limiter(), + cellWidthK_(ii, jj, kk - 2), cellWidthK_(ii, jj, kk - 1), + cellWidthK_(ii, jj, kk)); - faceStateUpper = state_(ii, jj, kk).FaceReconMUSCL( - state_(ii, jj, kk + 1), state_(ii, jj, kk - 1), - inp.Kappa(), inp.Limiter(), cellWidthK_(ii, jj, kk), - cellWidthK_(ii, jj, kk + 1), cellWidthK_(ii, jj, kk - 1)); + faceStateUpper = FaceReconMUSCL( + state_(ii, jj, kk + 1), state_(ii, jj, kk), + state_(ii, jj, kk - 1), inp.Kappa(), inp.Limiter(), + cellWidthK_(ii, jj, kk + 1), cellWidthK_(ii, jj, kk), + cellWidthK_(ii, jj, kk - 1)); } else { // using higher order reconstruction (weno, wenoz) - faceStateLower = state_(ii, jj, kk - 1).FaceReconWENO( - state_(ii, jj, kk - 2), state_(ii, jj, kk - 3), - state_(ii, jj, kk), state_(ii, jj, kk + 1), - cellWidthK_(ii, jj, kk - 1), cellWidthK_(ii, jj, kk - 2), - cellWidthK_(ii, jj, kk - 3), cellWidthK_(ii, jj, kk), - cellWidthK_(ii, jj, kk + 1), inp.IsWenoZ()); - - faceStateUpper = state_(ii, jj, kk).FaceReconWENO( - state_(ii, jj, kk + 1), state_(ii, jj, kk + 2), - state_(ii, jj, kk - 1), state_(ii, jj, kk - 2), + faceStateLower = FaceReconWENO( + state_(ii, jj, kk - 3), state_(ii, jj, kk - 2), + state_(ii, jj, kk - 1), state_(ii, jj, kk), + state_(ii, jj, kk + 1), cellWidthK_(ii, jj, kk - 3), + cellWidthK_(ii, jj, kk - 2), cellWidthK_(ii, jj, kk - 1), cellWidthK_(ii, jj, kk), cellWidthK_(ii, jj, kk + 1), - cellWidthK_(ii, jj, kk + 2), cellWidthK_(ii, jj, kk - 1), - cellWidthK_(ii, jj, kk - 2), inp.IsWenoZ()); + inp.IsWenoZ()); + + faceStateUpper = FaceReconWENO( + state_(ii, jj, kk + 2), state_(ii, jj, kk + 1), + state_(ii, jj, kk), state_(ii, jj, kk - 1), + state_(ii, jj, kk - 2), cellWidthK_(ii, jj, kk + 2), + cellWidthK_(ii, jj, kk + 1), cellWidthK_(ii, jj, kk), + cellWidthK_(ii, jj, kk - 1), cellWidthK_(ii, jj, kk - 2), + inp.IsWenoZ()); } } + MSG_ASSERT(faceStateLower.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateLower.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(faceStateUpper.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(faceStateUpper.P() > 0.0, "nonphysical pressure"); // calculate inviscid flux at face const inviscidFlux tempFlux = - InviscidFlux(faceStateLower, faceStateUpper, eqnState, thermo, + InviscidFlux(faceStateLower, faceStateUpper, phys, this->FAreaUnitK(ii, jj, kk), inp.InviscidFlux()); // area vector points from left to right, so add to left cell, subtract // from right cell // at left boundary no left cell to add to if (kk > fAreaK_.PhysStartK()) { - this->AddToResidual(tempFlux * - this->FAreaMagK(ii, jj, kk), - ii, jj, kk - 1); + this->AddToResidual(ii, jj, kk - 1, + tempFlux * this->FAreaMagK(ii, jj, kk)); // if using block matrix on main diagonal, calculate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateLower, eqnState, thermo, - this->FAreaK(ii, jj, kk), true, - inp, turb); - mainDiagonal(ii, jj, kk - 1) += fluxJac; + fluxJac.RusanovFluxJacobian(faceStateLower, phys, + this->FAreaK(ii, jj, kk), true, inp); + mainDiagonal.Add(ii, jj, kk - 1, fluxJac); } } // at right boundary no right cell to add to if (kk < fAreaK_.PhysEndK() - 1) { - this->SubtractFromResidual(tempFlux * - this->FAreaMagK(ii, jj, kk), - ii, jj, kk); + this->SubtractFromResidual(ii, jj, kk, + tempFlux * this->FAreaMagK(ii, jj, kk)); // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( - fAreaK_(ii, jj, kk), fAreaK_(ii, jj, kk + 1), thermo, eqnState); + const auto invSpecRad = + InvCellSpectralRadius(state_(ii, jj, kk), fAreaK_(ii, jj, kk), + fAreaK_(ii, jj, kk + 1), phys); - const auto turbInvSpecRad = isRANS_ ? - turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaK_(ii, jj, kk), - fAreaK_(ii, jj, kk + 1)) : 0.0; + const auto turbInvSpecRad = + isRANS_ ? phys.Turbulence()->InviscidCellSpecRad( + state_(ii, jj, kk), fAreaK_(ii, jj, kk), + fAreaK_(ii, jj, kk + 1)) + : 0.0; const uncoupledScalar specRad(invSpecRad, turbInvSpecRad); specRadius_(ii, jj, kk) += specRad; @@ -785,12 +751,11 @@ void procBlock::CalcInvFluxK(const unique_ptr &eqnState, // if using block matrix on main diagonal, calculate flux jacobian if (inp.IsBlockMatrix()) { fluxJacobian fluxJac; - fluxJac.RusanovFluxJacobian(faceStateUpper, eqnState, thermo, - this->FAreaK(ii, jj, kk), false, - inp, turb); - mainDiagonal(ii, jj, kk) -= fluxJac; + fluxJac.RusanovFluxJacobian(faceStateUpper, phys, + this->FAreaK(ii, jj, kk), false, inp); + mainDiagonal.Subtract(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { - mainDiagonal(ii, jj, kk) += fluxJacobian(specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(specRad, isRANS_)); } } } @@ -853,12 +818,9 @@ void procBlock::CalcBlockTimeStep(const input &inp) { explicit methods it calls the appropriate explicit method to update. For implicit methods it uses the correction du and calls the implicit updater. */ -void procBlock::UpdateBlock(const input &inputVars, const unique_ptr &eos, - const unique_ptr &thermo, - const unique_ptr &trans, - const multiArray3d &du, - const unique_ptr &turb, const int &rr, - genArray &l2, resid &linf) { +void procBlock::UpdateBlock(const input &inputVars, const physics &phys, + const blkMultiArray3d &du, const int &rr, + residual &l2, resid &linf) { // inputVars -- all input variables // eos -- equation of state // thermo -- thermodynamic model @@ -875,26 +837,24 @@ void procBlock::UpdateBlock(const input &inputVars, const unique_ptr &eos, for (auto ii = this->StartI(); ii < this->EndI(); ii++) { // explicit euler time integration if (inputVars.TimeIntegration() == "explicitEuler") { - this->ExplicitEulerTimeAdvance(eos, thermo, turb, ii, jj, kk); + this->ExplicitEulerTimeAdvance(phys, ii, jj, kk); // 4-stage runge-kutta method (explicit) } else if (inputVars.TimeIntegration() == "rk4") { // advance 1 RK stage - this->RK4TimeAdvance(consVarsN_(ii, jj, kk), eos, thermo, turb, ii, - jj, kk, rr); + this->RK4TimeAdvance(consVarsN_(ii, jj, kk), phys, ii, jj, kk, rr); } else if (inputVars.IsImplicit()) { // if implicit use update (du) - this->ImplicitTimeAdvance(du(ii, jj, kk), eos, thermo, turb, ii, jj, - kk); + this->ImplicitTimeAdvance(du(ii, jj, kk), phys, ii, jj, kk); } else { cerr << "ERROR: Time integration scheme " << inputVars.TimeIntegration() << " is not recognized!" << endl; } // accumulate l2 norm of residual - l2 = l2 + residual_(ii, jj, kk) * residual_(ii, jj, kk); + l2 += residual_(ii, jj, kk) * residual_(ii, jj, kk); // if any residual is larger than previous residual, a new linf // residual is found - for (auto ll = 0; ll < NUMVARS; ll++) { + for (auto ll = 0; ll < inputVars.NumEquations(); ll++) { if (this->Residual(ii, jj, kk, ll) > linf.Linf()) { linf.UpdateMax(this->Residual(ii, jj, kk, ll), parBlock_, ii, jj, kk, ll + 1); @@ -914,66 +874,56 @@ Un is the conserved variables at time n, Un+1 is the conserved variables at time n+1, dt_ is the cell's time step, V is the cell's volume, and R is the cell's residual. */ -void procBlock::ExplicitEulerTimeAdvance( - const unique_ptr &eqnState, const unique_ptr &thermo, - const unique_ptr &turb, const int &ii, const int &jj, - const int &kk) { - // eqnState -- equation of state - // thermo -- thermodynamic model - // turb -- turbulence model +void procBlock::ExplicitEulerTimeAdvance(const physics &phys, const int &ii, + const int &jj, const int &kk) { + // phys -- physics models // ii -- i-location of cell // jj -- j-location of cell // kk -- k-location of cell // Get conserved variables for current state (time n) - auto consVars = state_(ii, jj, kk).ConsVars(eqnState, thermo); + auto consVars = state_(ii, jj, kk).ConsVars(phys); // calculate updated conserved variables consVars -= dt_(ii, jj, kk) / vol_(ii, jj, kk) * residual_(ii, jj, kk); - // calculate updated primative variables and update state - state_(ii, jj, kk) = primVars(consVars, false, eqnState, thermo, turb); + // calculate updated primitive variables and update state + state_.InsertBlock(ii, jj, kk, primitive(consVars, phys)); + MSG_ASSERT(state_(ii, jj, kk).Rho() > 0, "nonphysical density"); + MSG_ASSERT(state_(ii, jj, kk).P() > 0, "nonphysical pressure"); } // member function to advance the state vector to time n+1 (for implicit // methods) -void procBlock::ImplicitTimeAdvance(const genArray &du, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &turb, +void procBlock::ImplicitTimeAdvance(const varArrayView &du, const physics &phys, const int &ii, const int &jj, const int &kk) { // du -- update for a specific cell (to move from time n to n+1) - // eqnState -- equation of state - // thermo -- thermodynamic model - // turb -- turbulence model + // phys -- physics models // ii -- i-location of cell // jj -- j-location of cell // kk -- k-location of cell - // calculate updated state (primative variables) - state_(ii, jj, kk) = - state_(ii, jj, kk).UpdateWithConsVars(eqnState, thermo, du, turb); + // calculate updated state (primitive variables) + state_.InsertBlock(ii, jj, kk, + state_(ii, jj, kk).UpdateWithConsVars(phys, du)); + MSG_ASSERT(state_(ii, jj, kk).Rho() > 0, "nonphysical density"); + MSG_ASSERT(state_(ii, jj, kk).P() > 0, "nonphysical pressure"); } -/*member function to advance the state_ vector to time n+1 using 4th order +/* member function to advance the state vector to time n+1 using 4th order (minimum storage) Runge-Kutta method (2nd order accurate) Un+1 = Un - dt/V * alpha * R Un is the conserved variables at time n, Un+1 is the conserved variables at time -n+1, dt_ is the cell's time step, V is the cell's volume, alpha is the runge-kutta +n+1, dt is the cell's time step, V is the cell's volume, alpha is the runge-kutta coefficient, and R is the cell's residual. */ -void procBlock::RK4TimeAdvance(const genArray &currState, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &turb, - const int &ii, const int &jj, const int &kk, - const int &rk) { - // currState -- current state (including steps within RK4) (primative) - // eqnState -- equation of state - // thermo -- thermodynamic model - // turb -- turbulence model +void procBlock::RK4TimeAdvance(const conservedView &currState, + const physics &phys, const int &ii, + const int &jj, const int &kk, const int &rk) { + // currState -- current state (including steps within RK4) + // physcs -- physics models // ii -- i-location of cell (including ghost cells) // jj -- j-location of cell (including ghost cells) // kk -- k-location of cell (including ghost cells) @@ -986,15 +936,17 @@ void procBlock::RK4TimeAdvance(const genArray &currState, auto consVars = currState - dt_(ii, jj, kk) / vol_(ii, jj, kk) * alpha[rk] * residual_(ii, jj, kk); - // calculate updated primative variables - state_(ii, jj, kk) = primVars(consVars, false, eqnState, thermo, turb); + // calculate updated primitive variables + state_.InsertBlock(ii, jj, kk, primitive(consVars, phys)); + MSG_ASSERT(state_(ii, jj, kk).Rho() > 0, "nonphysical density"); + MSG_ASSERT(state_(ii, jj, kk).P() > 0, "nonphysical pressure"); } // member function to reset the residual and wave speed back to zero after an // iteration. This is done because the residual and wave // speed are accumulated over many function calls. void procBlock::ResetResidWS() { - residual_.Zero(); + residual_.Zero(0.0); specRadius_.Zero(); } @@ -1004,6 +956,8 @@ void procBlock::ResetResidWS() { void procBlock::ResetGradients() { velocityGrad_.Zero(); temperatureGrad_.Zero(); + densityGrad_.Zero(); + pressureGrad_.Zero(); if (isRANS_) { tkeGrad_.Zero(); omegaGrad_.Zero(); @@ -1032,7 +986,7 @@ where n represents the time step. Theta and zeta are Beam & Warming parameters, t is the time step, V is the cell volume, and R is the residual. FD and BD are the forward and backward difference operators respectively. These opererators operate in the time domain. For example FD(U) = -Un+1 - Un and BD(U) = Un - Un-1. Solving the above equation for FD(Qn) we get +Un+1 - Un and BD(U) = Un - Un-1. Solving the above equation for FD(Un) we get the following: FD(Un) = (-t * Rn - t * theta * FD(Rn) + zeta * V * FD(Un-1)) / ((1 + zeta) * V) @@ -1053,12 +1007,10 @@ double procBlock::SolDeltaNCoeff(const int &ii, const int &jj, const int &kk, return (vol_(ii, jj, kk) * (1.0 + inp.Zeta())) / (dt_(ii, jj, kk) * inp.Theta()); } -genArray procBlock::SolDeltaMmN(const int &ii, const int &jj, const int &kk, - const input &inp, const unique_ptr &eos, - const unique_ptr &thermo) const { +varArray procBlock::SolDeltaMmN(const int &ii, const int &jj, const int &kk, + const input &inp, const physics &phys) const { const auto coeff = this->SolDeltaNCoeff(ii, jj, kk, inp); - return coeff * - (state_(ii, jj, kk).ConsVars(eos, thermo) - consVarsN_(ii, jj, kk)); + return coeff * (state_(ii, jj, kk).ConsVars(phys) - consVarsN_(ii, jj, kk)); } double procBlock::SolDeltaNm1Coeff(const int &ii, const int &jj, const int &kk, @@ -1066,17 +1018,17 @@ double procBlock::SolDeltaNm1Coeff(const int &ii, const int &jj, const int &kk, return (vol_(ii, jj, kk) * inp.Zeta()) / (dt_(ii, jj, kk) * inp.Theta()); } -genArray procBlock::SolDeltaNm1(const int &ii, const int &jj, const int &kk, +varArray procBlock::SolDeltaNm1(const int &ii, const int &jj, const int &kk, const input &inp) const { if (isMultiLevelTime_) { const auto coeff = this->SolDeltaNm1Coeff(ii, jj, kk, inp); return coeff * (consVarsN_(ii, jj, kk) - consVarsNm1_(ii, jj, kk)); } else { - return genArray(0.0); + return varArray(inp.NumEquations(), inp.NumSpecies()); } } -void procBlock::InvertDiagonal(multiArray3d &mainDiagonal, +void procBlock::InvertDiagonal(matMultiArray3d &mainDiagonal, const input &inp) const { // mainDiagonal -- main diagonal in implicit operator // inp -- input variables @@ -1085,8 +1037,7 @@ void procBlock::InvertDiagonal(multiArray3d &mainDiagonal, for (auto kk = 0; kk < this->NumK(); kk++) { for (auto jj = 0; jj < this->NumJ(); jj++) { for (auto ii = 0; ii < this->NumI(); ii++) { - auto diagVolTime = (vol_(ii, jj, kk) * (1.0 + inp.Zeta())) / - (dt_(ii, jj, kk) * inp.Theta()); + auto diagVolTime = this->SolDeltaNCoeff(ii, jj, kk, inp); if (inp.DualTimeCFL() > 0.0) { // use dual time stepping // equal to volume / tau diagVolTime += specRadius_(ii, jj, kk).Max() / @@ -1094,24 +1045,22 @@ void procBlock::InvertDiagonal(multiArray3d &mainDiagonal, } // add volume and time term - mainDiagonal(ii, jj, kk).MultiplyOnDiagonal(inp.MatrixRelaxation(), - isRANS_); - mainDiagonal(ii, jj, kk).AddOnDiagonal(diagVolTime, isRANS_); - mainDiagonal(ii, jj, kk).Inverse(isRANS_); + mainDiagonal.MultiplyOnDiagonal(ii, jj, kk, inp.MatrixRelaxation()); + mainDiagonal.AddOnDiagonal(ii, jj, kk, diagVolTime); + mainDiagonal.Inverse(ii, jj, kk); } } } } // assign current solution held in state_ to time n solution held in consVarsN_ -void procBlock::AssignSolToTimeN(const unique_ptr &eos, - const unique_ptr &thermo) { +void procBlock::AssignSolToTimeN(const physics &phys) { // loop over physical cells for (auto kk = this->StartK(); kk < this->EndK(); kk++) { for (auto jj = this->StartJ(); jj < this->EndJ(); jj++) { for (auto ii = this->StartI(); ii < this->EndI(); ii++) { // convert state to conservative variables - consVarsN_(ii, jj, kk) = state_(ii, jj, kk).ConsVars(eos, thermo); + consVarsN_.InsertBlock(ii, jj, kk, state_(ii, jj, kk).ConsVars(phys)); } } } @@ -1230,20 +1179,14 @@ For viscous simulations, the viscous contribution to the spectral radius K is used, and everything else remains the same. */ void procBlock::LUSGS_Forward(const vector> &reorder, - multiArray3d &x, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const multiArray3d &aInv, + blkMultiArray3d &x, const physics &phys, + const input &inp, const matMultiArray3d &aInv, const int &sweep) const { // reorder -- order of cells to visit (this should be ordered in hyperplanes) // x -- correction - added to solution at time n to get to time n+1 (assumed // to be zero to start) - // eqnState -- equation of state + // phys -- physics models // inp -- all input variables - // trans -- viscous transport model - // turb -- turbulence model // aInv -- inverse of main diagonal // sweep -- sweep number through domain @@ -1251,15 +1194,15 @@ void procBlock::LUSGS_Forward(const vector> &reorder, //-------------------------------------------------------------------- // forward sweep over all physical cells - for (auto nn = 0; nn < this->NumCells(); nn++) { + for (auto nn = 0; nn < this->NumCells(); ++nn) { // indices for variables without ghost cells const auto ii = reorder[nn].X(); const auto jj = reorder[nn].Y(); const auto kk = reorder[nn].Z(); // initialize term for contribution from lower/upper triangular matrix - genArray L(0.0); - genArray U(0.0); + varArray L(inp.NumEquations(), inp.NumSpecies()); + varArray U(inp.NumEquations(), inp.NumSpecies()); // if i lower diagonal cell is in physical location there is a contribution // from it @@ -1269,13 +1212,11 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); // update L matrix - L += OffDiagonal(state_(ii - 1, jj, kk), state_(ii, jj, kk), - x(ii - 1 , jj, kk), fAreaI_(ii, jj, kk), - this->Viscosity(ii - 1, jj, kk), - this->EddyViscosity(ii - 1, jj, kk), - this->F1(ii - 1, jj, kk), projDist, - this->VelGrad(ii - 1, jj, kk), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii - 1, jj, kk), state_(ii, jj, kk), x(ii - 1, jj, kk), + fAreaI_(ii, jj, kk), this->Viscosity(ii - 1, jj, kk), + this->EddyViscosity(ii - 1, jj, kk), this->F1(ii - 1, jj, kk), + projDist, this->VelGrad(ii - 1, jj, kk), phys, inp, true); } // ----------------------------------------------------------------------- @@ -1287,13 +1228,11 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); // update L matrix - L += OffDiagonal(state_(ii, jj - 1, kk), state_(ii, jj, kk), - x(ii, jj - 1, kk), fAreaJ_(ii, jj, kk), - this->Viscosity(ii, jj - 1, kk), - this->EddyViscosity(ii, jj - 1, kk), - this->F1(ii, jj - 1, kk), projDist, - this->VelGrad(ii, jj - 1, kk), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii, jj - 1, kk), state_(ii, jj, kk), x(ii, jj - 1, kk), + fAreaJ_(ii, jj, kk), this->Viscosity(ii, jj - 1, kk), + this->EddyViscosity(ii, jj - 1, kk), this->F1(ii, jj - 1, kk), + projDist, this->VelGrad(ii, jj - 1, kk), phys, inp, true); } // ----------------------------------------------------------------------- @@ -1305,16 +1244,13 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); // update L matrix - L += OffDiagonal(state_(ii, jj, kk - 1), state_(ii, jj, kk), - x(ii, jj, kk - 1), fAreaK_(ii, jj, kk), - this->Viscosity(ii, jj, kk - 1), - this->EddyViscosity(ii, jj, kk - 1), - this->F1(ii, jj, kk - 1), projDist, - this->VelGrad(ii, jj, kk - 1), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii, jj, kk - 1), state_(ii, jj, kk), x(ii, jj, kk - 1), + fAreaK_(ii, jj, kk), this->Viscosity(ii, jj, kk - 1), + this->EddyViscosity(ii, jj, kk - 1), this->F1(ii, jj, kk - 1), + projDist, this->VelGrad(ii, jj, kk - 1), phys, inp, true); } - // Only need to calculate contribution for U if matrix update has been // initialized, or if this is not the first sweep through the domain. // If the matrix is not initialized, the update x is 0 for the first @@ -1329,13 +1265,11 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); // update U matrix - U += OffDiagonal(state_(ii + 1, jj, kk), state_(ii, jj, kk), - x(ii + 1 , jj, kk), fAreaI_(ii + 1, jj, kk), - this->Viscosity(ii + 1, jj, kk), - this->EddyViscosity(ii + 1, jj, kk), - this->F1(ii + 1, jj, kk), projDist, - this->VelGrad(ii + 1, jj, kk), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii + 1, jj, kk), state_(ii, jj, kk), x(ii + 1, jj, kk), + fAreaI_(ii + 1, jj, kk), this->Viscosity(ii + 1, jj, kk), + this->EddyViscosity(ii + 1, jj, kk), this->F1(ii + 1, jj, kk), + projDist, this->VelGrad(ii + 1, jj, kk), phys, inp, false); } // ----------------------------------------------------------------------- @@ -1347,17 +1281,15 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); // update U matrix - U += OffDiagonal(state_(ii, jj + 1, kk), state_(ii, jj, kk), - x(ii, jj + 1, kk), fAreaJ_(ii, jj + 1, kk), - this->Viscosity(ii, jj + 1, kk), - this->EddyViscosity(ii, jj + 1, kk), - this->F1(ii, jj + 1, kk), projDist, - this->VelGrad(ii, jj + 1, kk), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii, jj + 1, kk), state_(ii, jj, kk), x(ii, jj + 1, kk), + fAreaJ_(ii, jj + 1, kk), this->Viscosity(ii, jj + 1, kk), + this->EddyViscosity(ii, jj + 1, kk), this->F1(ii, jj + 1, kk), + projDist, this->VelGrad(ii, jj + 1, kk), phys, inp, false); } // ----------------------------------------------------------------------- - // if k lower cell is in physical location there is a contribution + // if k upper cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj, kk + 1) || bc_.BCIsConnection(ii, jj, kk + 1, 6)) { @@ -1365,49 +1297,43 @@ void procBlock::LUSGS_Forward(const vector> &reorder, const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); // update U matrix - U += OffDiagonal(state_(ii, jj, kk + 1), state_(ii, jj, kk), - x(ii, jj, kk + 1), fAreaK_(ii, jj, kk + 1), - this->Viscosity(ii, jj, kk + 1), - this->EddyViscosity(ii, jj, kk + 1), - this->F1(ii, jj, kk + 1), projDist, - this->VelGrad(ii, jj, kk + 1), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii, jj, kk + 1), state_(ii, jj, kk), x(ii, jj, kk + 1), + fAreaK_(ii, jj, kk + 1), this->Viscosity(ii, jj, kk + 1), + this->EddyViscosity(ii, jj, kk + 1), this->F1(ii, jj, kk + 1), + projDist, this->VelGrad(ii, jj, kk + 1), phys, inp, false); } } // ----------------------------------------------------------------------- const auto solDeltaNm1 = this->SolDeltaNm1(ii, jj, kk, inp); - const auto solDeltaMmN = - this->SolDeltaMmN(ii, jj, kk, inp, eqnState, thermo); + const auto solDeltaMmN = this->SolDeltaMmN(ii, jj, kk, inp, phys); // calculate intermediate update // normal at lower boundaries needs to be reversed, so add instead // of subtract L - x(ii, jj, kk) = aInv(ii, jj, kk).ArrayMult(-thetaInv * - residual_(ii, jj, kk) - - solDeltaNm1 - solDeltaMmN + - L - U); + x.InsertBlock(ii, jj, kk, + aInv.ArrayMult(ii, jj, kk, + -thetaInv * residual_(ii, jj, kk) + + solDeltaNm1 - solDeltaMmN + L - U)); } // end forward sweep } -double procBlock::LUSGS_Backward( - const vector> &reorder, multiArray3d &x, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb, const multiArray3d &aInv, - const int &sweep) const { +double procBlock::LUSGS_Backward(const vector> &reorder, + blkMultiArray3d &x, + const physics &phys, const input &inp, + const matMultiArray3d &aInv, + const int &sweep) const { // reorder -- order of cells to visit (this should be ordered in hyperplanes) // x -- correction - added to solution at time n to get to time n+1 (assumed // to be zero to start) - // eqnState -- equation of state + // phys -- physics models // inp -- all input variables - // trans -- viscous transport model - // turb -- turbulence model // aInv -- inverse of main diagonal // sweep -- sweep number through domain const auto thetaInv = 1.0 / inp.Theta(); - genArray l2Error(0.0); + varArray l2Error(inp.NumEquations(), inp.NumSpecies()); // backward sweep over all physical cells for (auto nn = this->NumCells() - 1; nn >= 0; nn--) { @@ -1417,8 +1343,8 @@ double procBlock::LUSGS_Backward( const auto kk = reorder[nn].Z(); // initialize term for contribution from upper/lower triangular matrix - genArray U(0.0); - genArray L(0.0); + varArray U(inp.NumEquations(), inp.NumSpecies()); + varArray L(inp.NumEquations(), inp.NumSpecies()); // ----------------------------------------------------------------------- // if i upper diagonal cell is in physical location there is a contribution @@ -1429,13 +1355,11 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); // update U matrix - U += OffDiagonal(state_(ii + 1, jj, kk), state_(ii, jj, kk), - x(ii + 1, jj, kk), fAreaI_(ii + 1, jj, kk), - this->Viscosity(ii + 1, jj, kk), - this->EddyViscosity(ii + 1, jj, kk), - this->F1(ii + 1, jj, kk), projDist, - this->VelGrad(ii + 1, jj, kk), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii + 1, jj, kk), state_(ii, jj, kk), x(ii + 1, jj, kk), + fAreaI_(ii + 1, jj, kk), this->Viscosity(ii + 1, jj, kk), + this->EddyViscosity(ii + 1, jj, kk), this->F1(ii + 1, jj, kk), + projDist, this->VelGrad(ii + 1, jj, kk), phys, inp, false); } // ----------------------------------------------------------------------- @@ -1447,13 +1371,11 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); // update U matrix - U += OffDiagonal(state_(ii, jj + 1, kk), state_(ii, jj, kk), - x(ii, jj + 1, kk), fAreaJ_(ii, jj + 1, kk), - this->Viscosity(ii, jj + 1, kk), - this->EddyViscosity(ii, jj + 1, kk), - this->F1(ii, jj + 1, kk), projDist, - this->VelGrad(ii, jj + 1, kk), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii, jj + 1, kk), state_(ii, jj, kk), x(ii, jj + 1, kk), + fAreaJ_(ii, jj + 1, kk), this->Viscosity(ii, jj + 1, kk), + this->EddyViscosity(ii, jj + 1, kk), this->F1(ii, jj + 1, kk), + projDist, this->VelGrad(ii, jj + 1, kk), phys, inp, false); } // ----------------------------------------------------------------------- @@ -1465,16 +1387,13 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); // update U matrix - U += OffDiagonal(state_(ii, jj, kk + 1), state_(ii, jj, kk), - x(ii, jj, kk + 1), fAreaK_(ii, jj, kk + 1), - this->Viscosity(ii, jj, kk + 1), - this->EddyViscosity(ii, jj, kk + 1), - this->F1(ii, jj, kk + 1), projDist, - this->VelGrad(ii, jj, kk + 1), - eqnState, thermo, trans, turb, inp, false); + U += OffDiagonal( + state_(ii, jj, kk + 1), state_(ii, jj, kk), x(ii, jj, kk + 1), + fAreaK_(ii, jj, kk + 1), this->Viscosity(ii, jj, kk + 1), + this->EddyViscosity(ii, jj, kk + 1), this->F1(ii, jj, kk + 1), + projDist, this->VelGrad(ii, jj, kk + 1), phys, inp, false); } - // Only need to calculate contribution for L if matrix update has been // initialized, or if this is not the first sweep through the domain. // If the matrix is not initialized, then b - Lx^* was already solved for @@ -1489,13 +1408,11 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); // update U matrix - L += OffDiagonal(state_(ii - 1, jj, kk), state_(ii, jj, kk), - x(ii - 1, jj, kk), fAreaI_(ii, jj, kk), - this->Viscosity(ii - 1, jj, kk), - this->EddyViscosity(ii - 1, jj, kk), - this->F1(ii - 1, jj, kk), projDist, - this->VelGrad(ii - 1, jj, kk), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii - 1, jj, kk), state_(ii, jj, kk), x(ii - 1, jj, kk), + fAreaI_(ii, jj, kk), this->Viscosity(ii - 1, jj, kk), + this->EddyViscosity(ii - 1, jj, kk), this->F1(ii - 1, jj, kk), + projDist, this->VelGrad(ii - 1, jj, kk), phys, inp, true); } // ----------------------------------------------------------------------- @@ -1507,13 +1424,11 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); // update U matrix - L += OffDiagonal(state_(ii, jj - 1, kk), state_(ii, jj, kk), - x(ii, jj - 1, kk), fAreaJ_(ii, jj, kk), - this->Viscosity(ii, jj - 1, kk), - this->EddyViscosity(ii, jj - 1, kk), - this->F1(ii, jj - 1, kk), projDist, - this->VelGrad(ii, jj - 1, kk), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii, jj - 1, kk), state_(ii, jj, kk), x(ii, jj - 1, kk), + fAreaJ_(ii, jj, kk), this->Viscosity(ii, jj - 1, kk), + this->EddyViscosity(ii, jj - 1, kk), this->F1(ii, jj - 1, kk), + projDist, this->VelGrad(ii, jj - 1, kk), phys, inp, true); } // ----------------------------------------------------------------------- @@ -1525,29 +1440,26 @@ double procBlock::LUSGS_Backward( const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); // update U matrix - L += OffDiagonal(state_(ii, jj, kk - 1), state_(ii, jj, kk), - x(ii, jj, kk - 1), fAreaK_(ii, jj, kk), - this->Viscosity(ii, jj, kk - 1), - this->EddyViscosity(ii, jj, kk - 1), - this->F1(ii, jj, kk - 1), projDist, - this->VelGrad(ii, jj, kk - 1), - eqnState, thermo, trans, turb, inp, true); + L += OffDiagonal( + state_(ii, jj, kk - 1), state_(ii, jj, kk), x(ii, jj, kk - 1), + fAreaK_(ii, jj, kk), this->Viscosity(ii, jj, kk - 1), + this->EddyViscosity(ii, jj, kk - 1), this->F1(ii, jj, kk - 1), + projDist, this->VelGrad(ii, jj, kk - 1), phys, inp, true); } } // ----------------------------------------------------------------------- const auto solDeltaNm1 = this->SolDeltaNm1(ii, jj, kk, inp); - const auto solDeltaMmN = - this->SolDeltaMmN(ii, jj, kk, inp, eqnState, thermo); + const auto solDeltaMmN = this->SolDeltaMmN(ii, jj, kk, inp, phys); // calculate update - auto xold = x(ii, jj, kk); + const auto xold = x.GetCopy(ii, jj, kk); if (sweep > 0 || inp.MatrixRequiresInitialization()) { - x(ii, jj, kk) = aInv(ii, jj, kk).ArrayMult(-thetaInv * - residual_(ii, jj, kk) - - solDeltaNm1 - solDeltaMmN + - L - U); + x.InsertBlock(ii, jj, kk, + aInv.ArrayMult(ii, jj, kk, + -thetaInv * residual_(ii, jj, kk) + + solDeltaNm1 - solDeltaMmN + L - U)); } else { - x(ii, jj, kk) -= aInv(ii, jj, kk).ArrayMult(U); + x.InsertBlock(ii, jj, kk, xold - aInv.ArrayMult(ii, jj, kk, U)); } const auto error = x(ii, jj, kk) - xold; l2Error += error * error; @@ -1559,24 +1471,18 @@ double procBlock::LUSGS_Backward( /* Member function to calculate the implicit update via the DP-LUR method */ -double procBlock::DPLUR(multiArray3d &x, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const multiArray3d &aInv) const { +double procBlock::DPLUR(blkMultiArray3d &x, const physics &phys, + const input &inp, const matMultiArray3d &aInv) const { // x -- correction - added to solution at time n to get to time n+1 (assumed // to be zero to start) - // eqnState -- equation of state + // phys -- physics models // inp -- all input variables - // trans -- viscous transport model - // turb -- turbulence model // aInv -- inverse of main diagonal const auto thetaInv = 1.0 / inp.Theta(); // initialize residuals - genArray l2Error(0.0); + varArray l2Error(inp.NumEquations(), inp.NumSpecies()); // copy old update const auto xold = x; @@ -1585,7 +1491,7 @@ double procBlock::DPLUR(multiArray3d &x, for (auto jj = 0; jj < this->NumJ(); jj++) { for (auto ii = 0; ii < this->NumI(); ii++) { // calculate off diagonal terms - initialize to zero - genArray offDiagonal(0.0); + varArray offDiagonal(inp.NumEquations(), inp.NumSpecies()); // ------------------------------------------------------------- // if i lower diagonal cell is in physical location there is a @@ -1596,13 +1502,11 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); // update off diagonal - offDiagonal += OffDiagonal(state_(ii - 1, jj, kk), state_(ii, jj, kk), - xold(ii - 1, jj, kk), fAreaI_(ii, jj, kk), - this->Viscosity(ii - 1, jj, kk), - this->EddyViscosity(ii - 1, jj, kk), - this->F1(ii - 1, jj, kk), projDist, - this->VelGrad(ii - 1, jj, kk), - eqnState, thermo, trans, turb, inp, true); + offDiagonal += OffDiagonal( + state_(ii - 1, jj, kk), state_(ii, jj, kk), xold(ii - 1, jj, kk), + fAreaI_(ii, jj, kk), this->Viscosity(ii - 1, jj, kk), + this->EddyViscosity(ii - 1, jj, kk), this->F1(ii - 1, jj, kk), + projDist, this->VelGrad(ii - 1, jj, kk), phys, inp, true); } // -------------------------------------------------------------- @@ -1614,13 +1518,11 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); // update off diagonal - offDiagonal += OffDiagonal(state_(ii, jj - 1, kk), state_(ii, jj, kk), - xold(ii, jj - 1, kk), fAreaJ_(ii, jj, kk), - this->Viscosity(ii, jj - 1 , kk), - this->EddyViscosity(ii, jj - 1 , kk), - this->F1(ii, jj - 1 , kk), projDist, - this->VelGrad(ii, jj - 1, kk), - eqnState, thermo, trans, turb, inp, true); + offDiagonal += OffDiagonal( + state_(ii, jj - 1, kk), state_(ii, jj, kk), xold(ii, jj - 1, kk), + fAreaJ_(ii, jj, kk), this->Viscosity(ii, jj - 1, kk), + this->EddyViscosity(ii, jj - 1, kk), this->F1(ii, jj - 1, kk), + projDist, this->VelGrad(ii, jj - 1, kk), phys, inp, true); } // -------------------------------------------------------------- @@ -1632,13 +1534,11 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); // update off diagonal - offDiagonal += OffDiagonal(state_(ii, jj, kk - 1), state_(ii, jj, kk), - xold(ii, jj, kk - 1), fAreaK_(ii, jj, kk), - this->Viscosity(ii, jj, kk - 1), - this->EddyViscosity(ii, jj, kk - 1), - this->F1(ii, jj, kk - 1), projDist, - this->VelGrad(ii, jj, kk - 1), - eqnState, thermo, trans, turb, inp, true); + offDiagonal += OffDiagonal( + state_(ii, jj, kk - 1), state_(ii, jj, kk), xold(ii, jj, kk - 1), + fAreaK_(ii, jj, kk), this->Viscosity(ii, jj, kk - 1), + this->EddyViscosity(ii, jj, kk - 1), this->F1(ii, jj, kk - 1), + projDist, this->VelGrad(ii, jj, kk - 1), phys, inp, true); } // -------------------------------------------------------------- @@ -1650,14 +1550,11 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); // update off diagonal - offDiagonal -= OffDiagonal(state_(ii + 1, jj, kk), state_(ii, jj, kk), - xold(ii + 1, jj, kk), - fAreaI_(ii + 1, jj, kk), - this->Viscosity(ii + 1, jj, kk), - this->EddyViscosity(ii + 1, jj, kk), - this->F1(ii + 1, jj, kk), projDist, - this->VelGrad(ii + 1, jj, kk), - eqnState, thermo, trans, turb, inp, false); + offDiagonal -= OffDiagonal( + state_(ii + 1, jj, kk), state_(ii, jj, kk), xold(ii + 1, jj, kk), + fAreaI_(ii + 1, jj, kk), this->Viscosity(ii + 1, jj, kk), + this->EddyViscosity(ii + 1, jj, kk), this->F1(ii + 1, jj, kk), + projDist, this->VelGrad(ii + 1, jj, kk), phys, inp, false); } // -------------------------------------------------------------- @@ -1669,14 +1566,11 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); // update off diagonal - offDiagonal -= OffDiagonal(state_(ii, jj + 1, kk), state_(ii, jj, kk), - xold(ii, jj + 1, kk), - fAreaJ_(ii, jj + 1, kk), - this->Viscosity(ii, jj + 1, kk), - this->EddyViscosity(ii, jj + 1, kk), - this->F1(ii, jj + 1, kk), projDist, - this->VelGrad(ii, jj + 1, kk), - eqnState, thermo, trans, turb, inp, false); + offDiagonal -= OffDiagonal( + state_(ii, jj + 1, kk), state_(ii, jj, kk), xold(ii, jj + 1, kk), + fAreaJ_(ii, jj + 1, kk), this->Viscosity(ii, jj + 1, kk), + this->EddyViscosity(ii, jj + 1, kk), this->F1(ii, jj + 1, kk), + projDist, this->VelGrad(ii, jj + 1, kk), phys, inp, false); } // -------------------------------------------------------------- @@ -1688,25 +1582,23 @@ double procBlock::DPLUR(multiArray3d &x, const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); // update off diagonal - offDiagonal -= OffDiagonal(state_(ii, jj, kk + 1), state_(ii, jj, kk), - xold(ii, jj, kk + 1), - fAreaK_(ii, jj, kk + 1), - this->Viscosity(ii, jj, kk + 1), - this->EddyViscosity(ii, jj, kk + 1), - this->F1(ii, jj, kk + 1), projDist, - this->VelGrad(ii, jj, kk + 1), - eqnState, thermo, trans, turb, inp, false); + offDiagonal -= OffDiagonal( + state_(ii, jj, kk + 1), state_(ii, jj, kk), xold(ii, jj, kk + 1), + fAreaK_(ii, jj, kk + 1), this->Viscosity(ii, jj, kk + 1), + this->EddyViscosity(ii, jj, kk + 1), this->F1(ii, jj, kk + 1), + projDist, this->VelGrad(ii, jj, kk + 1), phys, inp, false); } // -------------------------------------------------------------- const auto solDeltaNm1 = this->SolDeltaNm1(ii, jj, kk, inp); - const auto solDeltaMmN = - this->SolDeltaMmN(ii, jj, kk, inp, eqnState, thermo); + const auto solDeltaMmN = this->SolDeltaMmN(ii, jj, kk, inp, phys); // calculate update - x(ii, jj, kk) = aInv(ii, jj, kk).ArrayMult( - -thetaInv * residual_(ii, jj, kk) - solDeltaNm1 - solDeltaMmN - + offDiagonal); + x.InsertBlock( + ii, jj, kk, + aInv.ArrayMult(ii, jj, kk, + -thetaInv * residual_(ii, jj, kk) + solDeltaNm1 - + solDeltaMmN + offDiagonal)); // calculate matrix error const auto error = x(ii, jj, kk) - xold(ii, jj, kk); @@ -1718,18 +1610,16 @@ double procBlock::DPLUR(multiArray3d &x, return l2Error.Sum(); } -multiArray3d procBlock::InitializeMatrixUpdate( - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, - const multiArray3d &aInv) const { +blkMultiArray3d procBlock::InitializeMatrixUpdate( + const input &inp, const physics &phys, const matMultiArray3d &aInv) const { // inp -- input variables - // eqnState -- equation of state - // thermo -- thermodynamic model + // phys -- physics models // aInv -- inverse of main diagonal // allocate multiarray for update - multiArray3d x(this->NumI(), this->NumJ(), this->NumK(), numGhosts_, - genArray(0.0)); + blkMultiArray3d x(this->NumI(), this->NumJ(), this->NumK(), + numGhosts_, inp.NumEquations(), inp.NumSpecies(), + 0.0); if (inp.MatrixRequiresInitialization()) { const auto thetaInv = 1.0 / inp.Theta(); @@ -1738,10 +1628,12 @@ multiArray3d procBlock::InitializeMatrixUpdate( for (auto jj = this->StartJ(); jj < this->EndJ(); jj++) { for (auto ii = this->StartI(); ii < this->EndI(); ii++) { // calculate update - x(ii, jj, kk) = aInv(ii, jj, kk).ArrayMult( - -thetaInv * residual_(ii, jj, kk) - - this->SolDeltaNm1(ii, jj, kk, inp) - - this->SolDeltaMmN(ii, jj, kk, inp, eqnState, thermo)); + x.InsertBlock( + ii, jj, kk, + aInv.ArrayMult(ii, jj, kk, + -thetaInv * residual_(ii, jj, kk) - + this->SolDeltaNm1(ii, jj, kk, inp) - + this->SolDeltaMmN(ii, jj, kk, inp, phys))); } } } @@ -1751,44 +1643,6 @@ multiArray3d procBlock::InitializeMatrixUpdate( } -/* Function to pad a multiArray3d with a specified number of ghost cells - ___ ___ ___ ___ ___ ___ ___ ___ - | E | E | G | G | G | G | E | E | - |___|___|___|___|___|___|___|___| - | E | E | G | G | G | G | E | E | - |___|___|___|___|___|___|___|___| - | G | G | X | X | X | X | G | G | - |___|___|___|___|___|___|___|___| - | G | G | X | X | X | X | G | G | - |___|___|___|___|___|___|___|___| - | E | E | G | G | G | G | E | E | - |___|___|___|___|___|___|___|___| - | E | E | G | G | G | G | E | E | - |___|___|___|___|___|___|___|___| - -In the above diagram, the cells marked with an "X" represent physical cells. The -entire diagram represents the block (in 2D) padded with 2 layers of ghost cells. -The cells marked with "G" are regualar ghost cells. The cells marked with "E" are -ghost cells located along one of the 12 edges that form a plot3d block. In 3D -there are also "corner" cells located at the 8 corners that form the plot3d block. -These cells are not used though. There is a place in the vector for them to make -accessing the padded vector of cells the same as for a plot3d block without ghost -cells. -*/ -template -multiArray3d PadWithGhosts(const multiArray3d &var, - const int &numGhosts) { - // var -- vector of variables to pad (no ghost cells included) - // numGhosts -- number of layers of ghost cells to pad var with - - // initialize added array - multiArray3d padBlk(var.NumI(), var.NumJ(), var.NumK(), numGhosts); - - padBlk.Insert(var.RangeI(), var.RangeJ(), var.RangeK(), var); - return padBlk; -} - - /* Function to calculate the viscous fluxes on the i-faces. All phyiscal (non-ghost) i-faces are looped over. The left and right states are calculated, and then the flux at the face is calculated. The flux at the @@ -1859,18 +1713,10 @@ in/out of the page). The stencil for the gradients of all faces in a cell touches 15 cells. The gradient calculation with this stencil uses the "edge" ghost cells, but not the "corner" ghost cells. */ -void procBlock::CalcViscFluxI(const unique_ptr &trans, - const unique_ptr &thermo, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { - // trans -- viscous transport model - // thermo -- thermodynamic model - // eqnState -- equation of state +void procBlock::CalcViscFluxI(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { + // phys -- physics models // inp -- all input variables - // grads -- class holding gradients at face for velocity, temperature, tke, - // and omega - // turb -- turbulence model // mainDiagonal -- main diagonal of LHS used to store flux jacobians for // implicit solver @@ -1883,16 +1729,18 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, for (auto ii = fAreaI_.PhysStartI(); ii < fAreaI_.PhysEndI(); ii++) { // calculate gradients tensor velGrad; - vector3d tempGrad, tkeGrad, omegaGrad; - this->CalcGradsI(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsI(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); // declare variables needed throughout function - primVars state; + primitive state(inp.NumEquations(), inp.NumSpecies()); auto f1 = 0.0; auto f2 = 0.0; auto mu = 0.0; auto mut = 0.0; - viscousFlux tempViscFlux; + viscousFlux tempViscFlux(inp.NumEquations(), inp.NumSpecies()); // get surface info it at boundary auto surfType = 0; @@ -1923,17 +1771,18 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, f1 = 1.0; f2 = 1.0; mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * - trans->InvNondimScaling(); + phys.Transport()->InvNondimScaling(); mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * - trans->InvNondimScaling(); - state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + phys.Transport()->InvNondimScaling(); + wallData_[wallDataInd].WallState(ii, jj, kk, phys.EoS(), state); tempViscFlux.CalcWallLawFlux( wallData_[wallDataInd].WallShearStress(ii, jj, kk), wallData_[wallDataInd].WallHeatFlux(ii, jj, kk), wallData_[wallDataInd].WallViscosity(ii, jj, kk), wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk), wallData_[wallDataInd].WallVelocity(), - this->FAreaUnitI(ii, jj, kk), tkeGrad, omegaGrad, turb); + this->FAreaUnitI(ii, jj, kk), tkeGrad, omegaGrad, + phys.Turbulence()); } else { // not boundary, or low Re wall boundary auto wDist = 0.0; if (inp.ViscousFaceReconstruction() == "central") { @@ -1944,7 +1793,7 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, // Get state at face state = FaceReconCentral(state_(ii - 1, jj, kk), state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face wDist = FaceReconCentral(wallDist_(ii - 1, jj, kk), @@ -1964,34 +1813,45 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, state = FaceReconCentral4th( state_(ii - 2, jj, kk), state_(ii - 1, jj, kk), state_(ii, jj, kk), state_(ii + 1, jj, kk), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face - wDist = FaceReconCentral4th( - wallDist_(ii - 2, jj, kk), wallDist_(ii - 1, jj, kk), - wallDist_(ii, jj, kk), wallDist_(ii + 1, jj, kk), cellWidth); + // Use regular central to avoid negative values + wDist = FaceReconCentral( + wallDist_(ii - 1, jj, kk), + wallDist_(ii, jj, kk), {cellWidth[1], cellWidth[2]}); // Get viscosity at face mu = FaceReconCentral4th( viscosity_(ii - 2, jj, kk), viscosity_(ii - 1, jj, kk), viscosity_(ii, jj, kk), viscosity_(ii + 1, jj, kk), cellWidth); } + // correct wall distance if within tolerance + if (wDist < 0.0 && wDist > WALL_DIST_NEG_TOL) { + wDist = 0.0; + } + + // sanity checks + MSG_ASSERT(state.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(state.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(mu > 0.0, "nonphysical viscosity"); + MSG_ASSERT(wDist >= 0.0, "nonphysical wall distance"); // calculate turbulent eddy viscosity and blending coefficients if (isTurbulent_) { // calculate length scale const auto lengthScale = 0.5 * (cellWidthI_(ii - 1, jj, kk) + cellWidthI_(ii, jj, kk)); - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, trans, lengthScale, mut, f1, f2); + phys.Turbulence()->EddyViscAndBlending( + state, velGrad, tkeGrad, omegaGrad, mu, wDist, phys.Transport(), + lengthScale, mut, f1, f2); } if (isLowReBoundary) { // calculate viscous flux auto wVars = tempViscFlux.CalcWallFlux( - velGrad, trans, thermo, eqnState, tempGrad, - this->FAreaUnitI(ii, jj, kk), tkeGrad, omegaGrad, turb, state, - mu, mut, f1); + velGrad, phys, tempGrad, this->FAreaUnitI(ii, jj, kk), tkeGrad, + omegaGrad, state, mu, mut, f1); auto y = (surfType == 1) ? wallDist_(ii, jj, kk) : wallDist_(ii - 1, jj, kk); wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / @@ -1999,9 +1859,9 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, wallData_[wallDataInd](ii, jj, kk) = wVars; } else { // calculate viscous flux - tempViscFlux.CalcFlux(velGrad, trans, thermo, eqnState, tempGrad, + tempViscFlux.CalcFlux(velGrad, phys, tempGrad, this->FAreaUnitI(ii, jj, kk), tkeGrad, - omegaGrad, turb, state, mu, mut, f1); + omegaGrad, mixGrad, state, mu, mut, f1); } } @@ -2013,13 +1873,14 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, // fluxes, so sign is reversed // at left boundary there is no left cell to add to if (ii > fAreaI_.PhysStartI()) { - this->SubtractFromResidual(tempViscFlux * - this->FAreaMagI(ii, jj, kk), - ii - 1, jj, kk); + this->SubtractFromResidual( + ii - 1, jj, kk, tempViscFlux * this->FAreaMagI(ii, jj, kk)); // store gradients velocityGrad_(ii - 1, jj, kk) += sixth * velGrad; temperatureGrad_(ii - 1, jj, kk) += sixth * tempGrad; + densityGrad_(ii - 1, jj, kk) += sixth * denGrad; + pressureGrad_(ii - 1, jj, kk) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii - 1, jj, kk) += sixth * mut; if (isRANS_) { @@ -2029,26 +1890,32 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, f2_(ii - 1, jj, kk) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii - 1, jj, kk, ss) += sixth * mixGrad[ii]; + } + } // if using block matrix on main diagonal, accumulate flux jacobian if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaI(ii, jj, kk), c2cDist, - turb, inp, true, velGrad); - mainDiagonal(ii - 1, jj, kk) -= fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaI(ii, jj, kk), c2cDist, inp, + true, velGrad); + mainDiagonal.Subtract(ii - 1, jj, kk, fluxJac); } } // at right boundary there is no right cell to add to if (ii < fAreaI_.PhysEndI() - 1) { - this->AddToResidual(tempViscFlux * - this->FAreaMagI(ii, jj, kk), - ii, jj, kk); + this->AddToResidual(ii, jj, kk, + tempViscFlux * this->FAreaMagI(ii, jj, kk)); // store gradients velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii, jj, kk) += sixth * mut; if (isRANS_) { @@ -2058,22 +1925,24 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, f2_(ii, jj, kk) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ii]; + } + } // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto viscSpecRad = - state_(ii, jj, kk) - .ViscCellSpectralRadius(fAreaI_(ii, jj, kk), - fAreaI_(ii + 1, jj, kk), thermo, - eqnState, trans, vol_(ii, jj, kk), - viscosity_(ii, jj, kk), mut, turb); - - const auto turbViscSpecRad = isRANS_ ? - turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaI_(ii, jj, kk), - fAreaI_(ii + 1, jj, kk), - viscosity_(ii, jj, kk), - trans, vol_(ii, jj, kk), mut, f1) - : 0.0; + const auto viscSpecRad = ViscCellSpectralRadius( + state_(ii, jj, kk), fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk), + phys, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut); + + const auto turbViscSpecRad = + isRANS_ ? phys.Turbulence()->ViscCellSpecRad( + state_(ii, jj, kk), fAreaI_(ii, jj, kk), + fAreaI_(ii + 1, jj, kk), viscosity_(ii, jj, kk), + phys.Transport(), vol_(ii, jj, kk), mut, f1) + : 0.0; const uncoupledScalar specRad(viscSpecRad, turbViscSpecRad); specRadius_(ii, jj, kk) += specRad * viscCoeff; @@ -2082,13 +1951,13 @@ void procBlock::CalcViscFluxI(const unique_ptr &trans, if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaI(ii, jj, kk), c2cDist, - turb, inp, false, velGrad); - mainDiagonal(ii, jj, kk) += fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaI(ii, jj, kk), c2cDist, inp, + false, velGrad); + mainDiagonal.Add(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { // factor 2 because visc spectral radius is not halved (Blazek 6.53) - mainDiagonal(ii, jj, kk) += fluxJacobian(2.0 * specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(2.0 * specRad, isRANS_)); } } } @@ -2167,18 +2036,10 @@ In three dimensions each gradient calculation touches the values at 10 cells faces in a cell touches 15 cells. The gradient calculation with this stencil uses the "edge" ghost cells, but not the "corner" ghost cells. */ -void procBlock::CalcViscFluxJ(const unique_ptr &trans, - const unique_ptr &thermo, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { - // trans -- viscous transport model - // thermo -- thermodynamic model - // eqnState -- equation of state +void procBlock::CalcViscFluxJ(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { + // phys -- physics models // inp -- all input variables - // grads -- class holding gradients at face for velocity, temperature, tke, - // and omega - // turb -- turbulence model // mainDiagonal -- main diagonal of LHS used to store flux jacobians for // implicit solver @@ -2191,16 +2052,18 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, for (auto ii = fAreaJ_.PhysStartI(); ii < fAreaJ_.PhysEndI(); ii++) { // calculate gradients tensor velGrad; - vector3d tempGrad, tkeGrad, omegaGrad; - this->CalcGradsJ(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsJ(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); // declare variables needed throughout function - primVars state; + primitive state(inp.NumEquations(), inp.NumSpecies()); auto f1 = 0.0; auto f2 = 0.0; auto mu = 0.0; auto mut = 0.0; - viscousFlux tempViscFlux; + viscousFlux tempViscFlux(inp.NumEquations(), inp.NumSpecies()); // get surface info if at boundary auto surfType = 0; @@ -2231,17 +2094,18 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, f1 = 1.0; f2 = 1.0; mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * - trans->InvNondimScaling(); + phys.Transport()->InvNondimScaling(); mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * - trans->InvNondimScaling(); - state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + phys.Transport()->InvNondimScaling(); + wallData_[wallDataInd].WallState(ii, jj, kk, phys.EoS(), state); tempViscFlux.CalcWallLawFlux( wallData_[wallDataInd].WallShearStress(ii, jj, kk), wallData_[wallDataInd].WallHeatFlux(ii, jj, kk), wallData_[wallDataInd].WallViscosity(ii, jj, kk), wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk), wallData_[wallDataInd].WallVelocity(), - this->FAreaUnitJ(ii, jj, kk), tkeGrad, omegaGrad, turb); + this->FAreaUnitJ(ii, jj, kk), tkeGrad, omegaGrad, + phys.Turbulence()); } else { // not boundary, or low Re wall boundary auto wDist = 0.0; if (inp.ViscousFaceReconstruction() == "central") { @@ -2252,7 +2116,7 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, // Get velocity at face state = FaceReconCentral(state_(ii, jj - 1, kk), state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face wDist = FaceReconCentral(wallDist_(ii, jj - 1, kk), @@ -2272,34 +2136,44 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, state = FaceReconCentral4th( state_(ii, jj - 2, kk), state_(ii, jj - 1, kk), state_(ii, jj, kk), state_(ii, jj + 1, kk), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face - wDist = FaceReconCentral4th( - wallDist_(ii, jj - 2, kk), wallDist_(ii, jj - 1, kk), - wallDist_(ii, jj, kk), wallDist_(ii, jj + 1, kk), cellWidth); + // Use regular central to avoid negative values + wDist = FaceReconCentral( + wallDist_(ii, jj - 1, kk), + wallDist_(ii, jj, kk), {cellWidth[1], cellWidth[2]}); // Get wall distance at face mu = FaceReconCentral4th( viscosity_(ii, jj - 2, kk), viscosity_(ii, jj - 1, kk), viscosity_(ii, jj, kk), viscosity_(ii, jj + 1, kk), cellWidth); } + // correct wall distance if within tolerance + if (wDist < 0.0 && wDist > WALL_DIST_NEG_TOL) { + wDist = 0.0; + } + + MSG_ASSERT(state.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(state.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(mu > 0.0, "nonphysical viscosity"); + MSG_ASSERT(wDist >= 0.0, "nonphysical wall distance"); // calculate turbulent eddy viscosity and blending coefficients if (isTurbulent_) { // calculate length scale const auto lengthScale = 0.5 * (cellWidthJ_(ii, jj - 1, kk) + cellWidthJ_(ii, jj, kk)); - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, trans, lengthScale, mut, f1, f2); + phys.Turbulence()->EddyViscAndBlending( + state, velGrad, tkeGrad, omegaGrad, mu, wDist, phys.Transport(), + lengthScale, mut, f1, f2); } if (isLowReBoundary) { // calculate viscous flux auto wVars = tempViscFlux.CalcWallFlux( - velGrad, trans, thermo, eqnState, tempGrad, - this->FAreaUnitJ(ii, jj, kk), tkeGrad, omegaGrad, turb, state, - mu, mut, f1); + velGrad, phys, tempGrad, this->FAreaUnitJ(ii, jj, kk), tkeGrad, + omegaGrad, state, mu, mut, f1); auto y = (surfType == 3) ? wallDist_(ii, jj, kk) : wallDist_(ii, jj - 1, kk); wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / @@ -2307,9 +2181,9 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, wallData_[wallDataInd](ii, jj, kk) = wVars; } else { // calculate viscous flux - tempViscFlux.CalcFlux(velGrad, trans, thermo, eqnState, tempGrad, + tempViscFlux.CalcFlux(velGrad, phys, tempGrad, this->FAreaUnitJ(ii, jj, kk), tkeGrad, - omegaGrad, turb, state, mu, mut, f1); + omegaGrad, mixGrad, state, mu, mut, f1); } } @@ -2322,13 +2196,14 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, // fluxes, so sign is reversed // at left boundary there is no left cell to add to if (jj > fAreaJ_.PhysStartJ()) { - this->SubtractFromResidual(tempViscFlux * - this->FAreaMagJ(ii, jj, kk), - ii, jj - 1, kk); + this->SubtractFromResidual( + ii, jj - 1, kk, tempViscFlux * this->FAreaMagJ(ii, jj, kk)); // store gradients velocityGrad_(ii, jj - 1, kk) += sixth * velGrad; temperatureGrad_(ii, jj - 1, kk) += sixth * tempGrad; + densityGrad_(ii, jj - 1, kk) += sixth * denGrad; + pressureGrad_(ii, jj - 1, kk) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii, jj - 1, kk) += sixth * mut; if (isRANS_) { @@ -2338,26 +2213,32 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, f2_(ii, jj - 1, kk) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj - 1, kk, ss) += sixth * mixGrad[ii]; + } + } // if using block matrix on main diagonal, accumulate flux jacobian if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaJ(ii, jj, kk), c2cDist, - turb, inp, true, velGrad); - mainDiagonal(ii, jj - 1, kk) -= fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaJ(ii, jj, kk), c2cDist, inp, + true, velGrad); + mainDiagonal.Subtract(ii, jj - 1, kk, fluxJac); } } // at right boundary there is no right cell to add to if (jj < fAreaJ_.PhysEndJ() - 1) { - this->AddToResidual(tempViscFlux * - this->FAreaMagJ(ii, jj, kk), - ii, jj, kk); + this->AddToResidual(ii, jj, kk, + tempViscFlux * this->FAreaMagJ(ii, jj, kk)); // store gradients velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii, jj, kk) += sixth * mut; if (isRANS_) { @@ -2367,22 +2248,24 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, f2_(ii, jj, kk) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ii]; + } + } // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto viscSpecRad = - state_(ii, jj, kk) - .ViscCellSpectralRadius(fAreaJ_(ii, jj, kk), - fAreaJ_(ii, jj + 1, kk), thermo, - eqnState, trans, vol_(ii, jj, kk), - viscosity_(ii, jj, kk), mut, turb); - - const auto turbViscSpecRad = isRANS_ ? - turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaJ_(ii, jj, kk), - fAreaJ_(ii, jj + 1, kk), - viscosity_(ii, jj, kk), - trans, vol_(ii, jj, kk), mut, f1) - : 0.0; + const auto viscSpecRad = ViscCellSpectralRadius( + state_(ii, jj, kk), fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk), + phys, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut); + + const auto turbViscSpecRad = + isRANS_ ? phys.Turbulence()->ViscCellSpecRad( + state_(ii, jj, kk), fAreaJ_(ii, jj, kk), + fAreaJ_(ii, jj + 1, kk), viscosity_(ii, jj, kk), + phys.Transport(), vol_(ii, jj, kk), mut, f1) + : 0.0; const uncoupledScalar specRad(viscSpecRad, turbViscSpecRad); specRadius_(ii, jj, kk) += specRad * viscCoeff; @@ -2392,13 +2275,13 @@ void procBlock::CalcViscFluxJ(const unique_ptr &trans, if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaJ(ii, jj, kk), c2cDist, - turb, inp, false, velGrad); - mainDiagonal(ii, jj, kk) += fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaJ(ii, jj, kk), c2cDist, inp, + false, velGrad); + mainDiagonal.Add(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { // factor 2 because visc spectral radius is not halved (Blazek 6.53) - mainDiagonal(ii, jj, kk) += fluxJacobian(2.0 * specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(2.0 * specRad, isRANS_)); } } } @@ -2476,11 +2359,8 @@ In three dimensions each gradient calculation touches the values at 10 cells faces in a cell touches 15 cells. The gradient calculation with this stencil uses the "edge" ghost cells, but not the "corner" ghost cells. */ -void procBlock::CalcViscFluxK(const unique_ptr &trans, - const unique_ptr &thermo, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { +void procBlock::CalcViscFluxK(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { // trans -- viscous transport model // thermo -- thermodynamic model // eqnState -- equation of state @@ -2500,16 +2380,18 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, for (auto ii = fAreaK_.PhysStartI(); ii < fAreaK_.PhysEndI(); ii++) { // calculate gradients tensor velGrad; - vector3d tempGrad, tkeGrad, omegaGrad; - this->CalcGradsK(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsK(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); // declare variables needed throughout function - primVars state; + primitive state(inp.NumEquations(), inp.NumSpecies()); auto f1 = 0.0; auto f2 = 0.0; auto mu = 0.0; auto mut = 0.0; - viscousFlux tempViscFlux; + viscousFlux tempViscFlux(inp.NumEquations(), inp.NumSpecies()); // get surface info if at boundary auto surfType = 0; @@ -2540,17 +2422,18 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, f1 = 1.0; f2 = 1.0; mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * - trans->InvNondimScaling(); + phys.Transport()->InvNondimScaling(); mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * - trans->InvNondimScaling(); - state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + phys.Transport()->InvNondimScaling(); + wallData_[wallDataInd].WallState(ii, jj, kk, phys.EoS(), state); tempViscFlux.CalcWallLawFlux( wallData_[wallDataInd].WallShearStress(ii, jj, kk), wallData_[wallDataInd].WallHeatFlux(ii, jj, kk), wallData_[wallDataInd].WallViscosity(ii, jj, kk), wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk), wallData_[wallDataInd].WallVelocity(), - this->FAreaUnitK(ii, jj, kk), tkeGrad, omegaGrad, turb); + this->FAreaUnitK(ii, jj, kk), tkeGrad, omegaGrad, + phys.Turbulence()); } else { // not boundary, or low Re wall boundary auto wDist = 0.0; if (inp.ViscousFaceReconstruction() == "central") { @@ -2561,7 +2444,7 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, // Get state at face state = FaceReconCentral(state_(ii, jj, kk - 1), state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face wDist = FaceReconCentral(wallDist_(ii, jj, kk - 1), @@ -2581,34 +2464,45 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, state = FaceReconCentral4th( state_(ii, jj, kk - 2), state_(ii, jj, kk - 1), state_(ii, jj, kk), state_(ii, jj, kk + 1), cellWidth); - state.LimitTurb(turb); + state.LimitTurb(phys.Turbulence()); // Get wall distance at face - wDist = FaceReconCentral4th( - wallDist_(ii, jj, kk - 2), wallDist_(ii, jj, kk - 1), - wallDist_(ii, jj, kk), wallDist_(ii, jj, kk + 1), cellWidth); + // Use regular central to avoid negative values + wDist = FaceReconCentral( + wallDist_(ii, jj, kk - 1), + wallDist_(ii, jj, kk), {cellWidth[1], cellWidth[2]}); // Get wall distance at face mu = FaceReconCentral4th( viscosity_(ii, jj, kk - 2), viscosity_(ii, jj, kk - 1), viscosity_(ii, jj, kk), viscosity_(ii, jj, kk + 1), cellWidth); } + // correct wall distance if within tolerance + if (wDist < 0.0 && wDist > WALL_DIST_NEG_TOL) { + wDist = 0.0; + } + + // sanity checks + MSG_ASSERT(state.Rho() > 0.0, "nonphysical density"); + MSG_ASSERT(state.P() > 0.0, "nonphysical pressure"); + MSG_ASSERT(mu > 0.0, "nonphysical viscosity"); + MSG_ASSERT(wDist >= 0.0, "nonphysical wall distance"); // calculate turbulent eddy viscosity and blending coefficients if (isTurbulent_) { // calculate length scale const auto lengthScale = 0.5 * (cellWidthK_(ii, jj, kk - 1) + cellWidthK_(ii, jj, kk)); - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, trans, lengthScale, mut, f1, f2); + phys.Turbulence()->EddyViscAndBlending( + state, velGrad, tkeGrad, omegaGrad, mu, wDist, phys.Transport(), + lengthScale, mut, f1, f2); } if (isLowReBoundary) { // calculate viscous flux auto wVars = tempViscFlux.CalcWallFlux( - velGrad, trans, thermo, eqnState, tempGrad, - this->FAreaUnitK(ii, jj, kk), tkeGrad, omegaGrad, turb, state, - mu, mut, f1); + velGrad, phys, tempGrad, this->FAreaUnitK(ii, jj, kk), tkeGrad, + omegaGrad, state, mu, mut, f1); auto y = (surfType == 5) ? wallDist_(ii, jj, kk) : wallDist_(ii, jj, kk - 1); wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / @@ -2616,9 +2510,9 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, wallData_[wallDataInd](ii, jj, kk) = wVars; } else { // calculate viscous flux - tempViscFlux.CalcFlux(velGrad, trans, thermo, eqnState, tempGrad, + tempViscFlux.CalcFlux(velGrad, phys, tempGrad, this->FAreaUnitK(ii, jj, kk), tkeGrad, - omegaGrad, turb, state, mu, mut, f1); + omegaGrad, mixGrad, state, mu, mut, f1); } } @@ -2631,13 +2525,14 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, // fluxes, so sign is reversed // at left boundary there is no left cell to add to if (kk > fAreaK_.PhysStartK()) { - this->SubtractFromResidual(tempViscFlux * - this->FAreaMagK(ii, jj, kk), - ii, jj, kk - 1); + this->SubtractFromResidual( + ii, jj, kk - 1, tempViscFlux * this->FAreaMagK(ii, jj, kk)); // store gradients velocityGrad_(ii, jj, kk - 1) += sixth * velGrad; temperatureGrad_(ii, jj, kk - 1) += sixth * tempGrad; + densityGrad_(ii, jj, kk - 1) += sixth * denGrad; + pressureGrad_(ii, jj, kk - 1) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii, jj, kk - 1) += sixth * mut; if (isRANS_) { @@ -2647,26 +2542,32 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, f2_(ii, jj, kk - 1) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk - 1, ss) += sixth * mixGrad[ii]; + } + } // if using block matrix on main diagonal, accumulate flux jacobian if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaK(ii, jj, kk), c2cDist, - turb, inp, true, velGrad); - mainDiagonal(ii, jj, kk - 1) -= fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaK(ii, jj, kk), c2cDist, inp, + true, velGrad); + mainDiagonal.Subtract(ii, jj, kk - 1, fluxJac); } } // at right boundary there is no right cell to add to if (kk < fAreaK_.PhysEndK() - 1) { - this->AddToResidual(tempViscFlux * - this->FAreaMagK(ii, jj, kk), - ii, jj, kk); + this->AddToResidual(ii, jj, kk, + tempViscFlux * this->FAreaMagK(ii, jj, kk)); // store gradients velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; if (isTurbulent_) { eddyViscosity_(ii, jj, kk) += sixth * mut; if (isRANS_) { @@ -2676,22 +2577,24 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, f2_(ii, jj, kk) += sixth * f2; } } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ii]; + } + } // calculate component of wave speed. This is done on a cell by cell // basis, so only at the upper faces - const auto viscSpecRad = - state_(ii, jj, kk) - .ViscCellSpectralRadius(fAreaK_(ii, jj, kk), - fAreaK_(ii, jj, kk + 1), thermo, - eqnState, trans, vol_(ii, jj, kk), - viscosity_(ii, jj, kk), mut, turb); - - const auto turbViscSpecRad = isRANS_ ? - turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaK_(ii, jj, kk), - fAreaK_(ii, jj, kk + 1), - viscosity_(ii, jj, kk), - trans, vol_(ii, jj, kk), mut, f1) - : 0.0; + const auto viscSpecRad = ViscCellSpectralRadius( + state_(ii, jj, kk), fAreaK_(ii, jj, kk), fAreaK_(ii, jj, kk + 1), + phys, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut); + + const auto turbViscSpecRad = + isRANS_ ? phys.Turbulence()->ViscCellSpecRad( + state_(ii, jj, kk), fAreaK_(ii, jj, kk), + fAreaK_(ii, jj, kk + 1), viscosity_(ii, jj, kk), + phys.Transport(), vol_(ii, jj, kk), mut, f1) + : 0.0; const uncoupledScalar specRad(viscSpecRad, turbViscSpecRad); specRadius_(ii, jj, kk) += specRad * viscCoeff; @@ -2700,13 +2603,13 @@ void procBlock::CalcViscFluxK(const unique_ptr &trans, if (inp.IsBlockMatrix()) { // using mu, mut, and f1 at face fluxJacobian fluxJac; - fluxJac.ApproxTSLJacobian(state, mu, mut, f1, eqnState, trans, - thermo, this->FAreaK(ii, jj, kk), c2cDist, - turb, inp, false, velGrad); - mainDiagonal(ii, jj, kk) += fluxJac; + fluxJac.ApproxTSLJacobian(state, mu, mut, f1, phys, + this->FAreaK(ii, jj, kk), c2cDist, inp, + false, velGrad); + mainDiagonal.Add(ii, jj, kk, fluxJac); } else if (inp.IsImplicit()) { // factor 2 because visc spectral radius is not halved (Blazek 6.53) - mainDiagonal(ii, jj, kk) += fluxJacobian(2.0 * specRad); + mainDiagonal.Add(ii, jj, kk, fluxJacobian(2.0 * specRad, isRANS_)); } } } @@ -3028,15 +2931,10 @@ In the above diagram where X represents the physical cells, cells marked G values. G1 represents the first layer of ghost cells and G2 represents the second layer. */ -void procBlock::AssignInviscidGhostCells( - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb) { +void procBlock::AssignInviscidGhostCells(const input &inp, + const physics &phys) { // inp -- all input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // loop over all layers of ghost cells for (auto layer = 1; layer <= numGhosts_; layer++) { @@ -3090,14 +2988,24 @@ void procBlock::AssignInviscidGhostCells( } const auto wDist = wallDist_.Slice(dir, aCell, r1, r2); + const auto dt = dt_.Slice(dir, aCell, r1, r2); + // nu wall not used for inviscid BCs + const multiArray3d nuW; + // get boundary state at time n + const auto consVarsN = consVarsN_.IsEmpty() + ? consVarsN_ + : consVarsN_.Slice(dir, aCell, r1, r2); + // get gradients at time n + const auto pGrad = pressureGrad_.Slice(dir, aCell, r1, r2); + const auto velGrad = velocityGrad_.Slice(dir, aCell, r1, r2); // if slipWall reflect interior state instead of extrapolation const auto boundaryStates = (bcName == "slipWall") ? state_.Slice(dir, iCell, r1, r2) : state_.Slice(dir, aCell, r1, r2); - const auto ghostStates = - this->GetGhostStates(boundaryStates, bcName, faceAreas, wDist, surf, - inp, eqnState, thermo, trans, turb, layer); + const auto ghostStates = this->GetGhostStates( + boundaryStates, bcName, faceAreas, wDist, surf, inp, phys, layer, + nuW, dt, consVarsN, pGrad, velGrad); state_.Insert(dir, gCell, r1, r2, ghostStates); } @@ -3142,37 +3050,35 @@ When this occurs the wall boundaries are "extended" into the ghost cells. This implementation is described in Blazek. */ void procBlock::AssignInviscidGhostCellsEdge( - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb) { + const input &inp, const physics &phys) { // inp -- all input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- unique_ptr's law for viscosity - // turb -- turbulence model + // phys -- physics models // loop over directions i, j, k for (auto dd = 0; dd < 3; dd++) { string dir = ""; - auto max1 = 0, max2 = 0, max3 = 0, surfStart = 0; + auto max1 = 0, max2 = 0, max3 = 0, surfStart2 = 0, surfStart3 = 0; if (dd == 0) { dir = "i"; max1 = this->NumI(); max2 = this->NumJ(); max3 = this->NumK(); - surfStart = 1; + surfStart2 = 3; + surfStart3 = 5; } else if (dd == 1) { dir = "j"; max1 = this->NumJ(); max2 = this->NumK(); max3 = this->NumI(); - surfStart = 3; + surfStart2 = 5; + surfStart3 = 1; } else { dir = "k"; max1 = this->NumK(); max2 = this->NumI(); max3 = this->NumJ(); - surfStart = 5; + surfStart2 = 1; + surfStart3 = 3; } // direction 1 is direction of line of cells, directions 2/3 are next in @@ -3198,8 +3104,8 @@ void procBlock::AssignInviscidGhostCellsEdge( const auto gCellD3 = upper3 ? pCellD3 + 1 : pCellD3 - 1; // surface types of surfaces forming edge - const auto surf2 = upper2 ? surfStart + 1 : surfStart; - const auto surf3 = upper3 ? surfStart + 1 : surfStart; + const auto surf2 = upper2 ? surfStart2 + 1 : surfStart2; + const auto surf3 = upper3 ? surfStart3 + 1 : surfStart3; // face indices at corner // these only change from cell indices for upper edges @@ -3213,7 +3119,7 @@ void procBlock::AssignInviscidGhostCellsEdge( const auto cFaceD3_3 = upper3 ? max3 : 0; // loop over edge - for (auto d1 = 0; d1 <= max1; d1++) { + for (auto d1 = 0; d1 < max1; d1++) { boundarySurface bcSurf_2, bcSurf_3; vector3d fArea2, fArea3; if (dir == "i") { @@ -3258,32 +3164,33 @@ void procBlock::AssignInviscidGhostCellsEdge( const auto wDist2 = wallDist_(dir, d1, cFaceD3_2, gCellD3); const auto wDist3 = wallDist_(dir, d1, gCellD2, cFaceD2_3); - wallVars wVars; // not used, only for calling GetGhostState + // not used, only for calling GetGhostState + wallVars wVars(this->NumSpecies()); // assign states ------------------------------------------------- - // surface-2 is a wall, but surface-3 is not - extend wall bc if (bc_2 == "slipWall" && bc_3 != "slipWall") { - state_(dir, d1, gCellD2, gCellD3) = - state_(dir, d1, pCellD2, gCellD3) - .GetGhostState(bc_2, fArea2, wDist2, surf2, inp, tag2, - eqnState, thermo, trans, turb, wVars, - layer2); - // surface-3 is a wall, but surface-2 is not - extend wall bc + // surface-2 is a wall, but surface-3 is not - extend wall bc + auto ghost = + GetGhostState(state_(dir, d1, pCellD2, gCellD3), bc_2, fArea2, + wDist2, surf2, inp, tag2, phys, wVars, layer2); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); } else if (bc_2 != "slipWall" && bc_3 == "slipWall") { - state_(dir, d1, gCellD2, gCellD3) = - state_(dir, d1, gCellD2, pCellD3) - .GetGhostState(bc_3, fArea3, wDist3, surf3, inp, tag3, - eqnState, thermo, trans, turb, wVars, - layer3); + // surface-3 is a wall, but surface-2 is not - extend wall bc + auto ghost = + GetGhostState(state_(dir, d1, gCellD2, pCellD3), bc_3, fArea3, + wDist3, surf3, inp, tag3, phys, wVars, layer3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); } else { // both surfaces or neither are walls - proceed as normal if (layer2 == layer3) { // need to average - state_(dir, d1, gCellD2, gCellD3) = 0.5 * - (state_(dir, d1, pCellD2, gCellD3) + - state_(dir, d1, gCellD2, pCellD3)); + auto ghost = 0.5 * (state_(dir, d1, pCellD2, gCellD3) + + state_(dir, d1, gCellD2, pCellD3)); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); } else if (layer2 > layer3) { // values come from direction 3 - state_(dir, d1, gCellD2, gCellD3) = state_(dir, d1, gCellD2, pCellD3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, + state_(dir, d1, gCellD2, pCellD3)); } else { // values come from direction 2 - state_(dir, d1, gCellD2, gCellD3) = state_(dir, d1, pCellD2, gCellD3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, + state_(dir, d1, pCellD2, gCellD3)); } } } @@ -3299,15 +3206,9 @@ void procBlock::AssignInviscidGhostCellsEdge( condition. It overwrites both regular and edge ghost cells. */ void procBlock::AssignViscousGhostCells(const input &inp, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb) { + const physics &phys) { // inp -- all input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // loop over all layers of ghost cells for (auto layer = 1; layer <= numGhosts_; layer++) { @@ -3358,19 +3259,28 @@ void procBlock::AssignViscousGhostCells(const input &inp, } const auto wDist = wallDist_.Slice(dir, aCell, r1, r2); + auto nuW = viscosity_.Slice(dir, aCell, r1, r2); + const auto adjacentStates = state_.Slice(dir, aCell, r1, r2); + for (auto kk = nuW.StartK(); kk < nuW.EndK(); ++kk) { + for (auto jj = nuW.StartJ(); jj < nuW.EndJ(); ++jj) { + for (auto ii = nuW.StartI(); ii < nuW.EndI(); ++ii) { + nuW(ii, jj, kk) /= adjacentStates(ii, jj, kk).Rho(); + } + } + } // get interior boundary states and ghost states const auto boundaryStates = state_.Slice(dir, iCell, r1, r2); const auto ghostStates = this->GetGhostStates(boundaryStates, bcName, faceAreas, wDist, surf, - inp, eqnState, thermo, trans, turb, layer); + inp, phys, layer, nuW); state_.Insert(dir, gCell, r1, r2, ghostStates); } } } // Assign edge ghost cells - this->AssignViscousGhostCellsEdge(inp, eqnState, thermo, trans, turb); + this->AssignViscousGhostCellsEdge(inp, phys); } @@ -3409,38 +3319,36 @@ meet at the corner are viscousWall boundaries and the other is not. When this occurs the viscousWall boundaries are "extended" into the ghost cells. This implementation is described in Blazek. */ -void procBlock::AssignViscousGhostCellsEdge( - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb) { +void procBlock::AssignViscousGhostCellsEdge(const input &inp, + const physics &phys) { // inp -- all input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- unique_ptr's law for viscosity - // turb -- turbulence model + // phys -- physics models // loop over directions i, j, k for (auto dd = 0; dd < 3; dd++) { string dir = ""; - auto max1 = 0, max2 = 0, max3 = 0, surfStart = 0; + auto max1 = 0, max2 = 0, max3 = 0, surfStart2 = 0, surfStart3 = 0; if (dd == 0) { dir = "i"; max1 = this->NumI(); max2 = this->NumJ(); max3 = this->NumK(); - surfStart = 1; + surfStart2 = 3; + surfStart3 = 5; } else if (dd == 1) { dir = "j"; max1 = this->NumJ(); max2 = this->NumK(); max3 = this->NumI(); - surfStart = 3; + surfStart2 = 5; + surfStart3 = 1; } else { dir = "k"; max1 = this->NumK(); max2 = this->NumI(); max3 = this->NumJ(); - surfStart = 5; + surfStart2 = 1; + surfStart3 = 3; } // direction 1 is direction of line of cells, directions 2/3 are next in @@ -3466,8 +3374,8 @@ void procBlock::AssignViscousGhostCellsEdge( const auto gCellD3 = upper3 ? pCellD3 + 1 : pCellD3 - 1; // surface types of surfaces forming edge - const auto surf2 = upper2 ? surfStart + 1 : surfStart; - const auto surf3 = upper3 ? surfStart + 1 : surfStart; + const auto surf2 = upper2 ? surfStart2 + 1 : surfStart2; + const auto surf3 = upper3 ? surfStart3 + 1 : surfStart3; // face indices at corner // these only change from cell indices for upper edges @@ -3481,7 +3389,7 @@ void procBlock::AssignViscousGhostCellsEdge( const auto cFaceD3_3 = upper3 ? max3 : 0; // loop over edge - for (auto d1 = 0; d1 <= max1; d1++) { + for (auto d1 = 0; d1 < max1; d1++) { boundarySurface bcSurf_2, bcSurf_3; vector3d fArea2, fArea3; if (dir == "i") { @@ -3523,33 +3431,41 @@ void procBlock::AssignViscousGhostCellsEdge( const auto wDist2 = wallDist_(dir, d1, cFaceD3_2, gCellD3); const auto wDist3 = wallDist_(dir, d1, gCellD2, cFaceD2_3); - wallVars wVars; // not used, only for calling GetGhostState + // get wall adjacent viscosity, nu + auto nuW2 = viscosity_(dir, d1, cFaceD3_2, gCellD3) / + state_(dir, d1, cFaceD3_2, gCellD3).Rho(); + + auto nuW3 = viscosity_(dir, d1, gCellD2, cFaceD2_3) / + state_(dir, d1, gCellD2, cFaceD2_3).Rho(); + + // not used, only for calling GetGhostState + wallVars wVars(this->NumSpecies()); // assign states ------------------------------------------------- // surface-2 is a wall, but surface-3 is not - extend wall bc if (bc_2 == "slipWall" && bc_3 != "slipWall") { - state_(dir, d1, gCellD2, gCellD3) = - state_(dir, d1, pCellD2, gCellD3) - .GetGhostState(bc_2, fArea2, wDist2, surf2, inp, tag2, - eqnState, thermo, trans, turb, wVars, - layer2); + auto ghost = GetGhostState(state_(dir, d1, pCellD2, gCellD3), + bc_2, fArea2, wDist2, surf2, inp, tag2, + phys, wVars, layer2, nuW2); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); // surface-3 is a wall, but surface-2 is not - extend wall bc } else if (bc_2 != "slipWall" && bc_3 == "slipWall") { - state_(dir, d1, gCellD2, gCellD3) = - state_(dir, d1, gCellD2, pCellD3) - .GetGhostState(bc_3, fArea3, wDist3, surf3, inp, tag3, - eqnState, thermo, trans, turb, wVars, - layer3); + auto ghost = GetGhostState(state_(dir, d1, gCellD2, pCellD3), + bc_3, fArea3, wDist3, surf3, inp, tag3, + phys, wVars, layer3, nuW3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); // both surfaces are walls - proceed as normal } else if (bc_2 == "viscousWall" && bc_3 == "viscousWall") { if (layer2 == layer3) { // need to average - state_(dir, d1, gCellD2, gCellD3) = 0.5 * - (state_(dir, d1, pCellD2, gCellD3) + - state_(dir, d1, gCellD2, pCellD3)); + auto ghost = 0.5 * (state_(dir, d1, pCellD2, gCellD3) + + state_(dir, d1, gCellD2, pCellD3)); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, ghost); } else if (layer2 > layer3) { // values come from direction 3 - state_(dir, d1, gCellD2, gCellD3) = state_(dir, d1, gCellD2, pCellD3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, + state_(dir, d1, gCellD2, pCellD3)); } else { // values come from direction 2 - state_(dir, d1, gCellD2, gCellD3) = state_(dir, d1, pCellD2, gCellD3); + state_.InsertBlock(dir, d1, gCellD2, gCellD3, + state_(dir, d1, pCellD2, gCellD3)); } } // if neither surfaces are walls, do nothing @@ -3789,22 +3705,18 @@ void procBlock::SwapWallDistSlice(const connection &inter, procBlock &blk) { wallDist_.SwapSlice(inter, blk.wallDist_); } +// This is done for the implicit solver so the off diagonal data adjacent to +// an interblock boundary condition can be accessed void procBlock::SwapEddyViscAndGradientSlice(const connection &inter, procBlock &blk) { // inter -- connection boundary information // blk -- second block involved in connection boundary + + velocityGrad_.SwapSlice(inter, blk.velocityGrad_); - if (isViscous_) { - velocityGrad_.SwapSlice(inter, blk.velocityGrad_); - temperatureGrad_.SwapSlice(inter, blk.temperatureGrad_); - } if (isTurbulent_) { eddyViscosity_.SwapSlice(inter, blk.eddyViscosity_); } - if (isRANS_) { - tkeGrad_.SwapSlice(inter, blk.tkeGrad_); - omegaGrad_.SwapSlice(inter, blk.omegaGrad_); - } } @@ -3812,13 +3724,10 @@ void procBlock::SwapEddyViscAndGradientSlice(const connection &inter, function, but is called when the neighboring procBlocks are on different processors. */ -void procBlock::SwapStateSliceMPI(const connection &inter, const int &rank, - const MPI_Datatype &MPI_cellData) { +void procBlock::SwapStateSliceMPI(const connection &inter, const int &rank) { // inter -- connection boundary information // rank -- processor rank - // MPI_cellData -- MPI datatype for passing primVars, genArray - - state_.SwapSliceMPI(inter, rank, MPI_cellData); + state_.SwapSliceMPI(inter, rank, MPI_DOUBLE); } void procBlock::SwapTurbSliceMPI(const connection &inter, const int &rank) { @@ -3842,16 +3751,10 @@ void procBlock::SwapEddyViscAndGradientSliceMPI( // inter -- connection boundary information // rank -- processor rank - if (isViscous_) { - velocityGrad_.SwapSliceMPI(inter, rank, MPI_tensorDouble, 1); - temperatureGrad_.SwapSliceMPI(inter, rank, MPI_vec3d, 2); - } + velocityGrad_.SwapSliceMPI(inter, rank, MPI_tensorDouble, 1); + if (isTurbulent_) { - eddyViscosity_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 1); - } - if (isRANS_) { - tkeGrad_.SwapSliceMPI(inter, rank, MPI_vec3d, 3); - omegaGrad_.SwapSliceMPI(inter, rank, MPI_vec3d, 4); + eddyViscosity_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 5); } } @@ -4511,9 +4414,9 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, connection &inter, if (l3 == (d3 - 1)) { // at end of direction 3 line fCenterJ_(indB[0], indB[1] + 1, indB[2]) = - slice.FCenterJ(indS[0], indS[1], indS[2] + fac3); + slice.FCenterK(indS[0], indS[1], indS[2] + fac3); fAreaJ_(indB[0], indB[1] + 1, indB[2]) = aFac3 * - slice.FAreaJ(indS[0], indS[1], indS[2] + fac3); + slice.FAreaK(indS[0], indS[1], indS[2] + fac3); } if (inter.IsLowerLowerOrUpperUpper()) { indS[2]--; @@ -4759,7 +4662,7 @@ slice of states. The function uses the orientation supplied in the connection to orient the slice relative to the procBlock. It assumes that the procBlock is listed first, and the slice second in the connection data structure. */ -void procBlock::PutStateSlice(const multiArray3d &slice, +void procBlock::PutStateSlice(const blkMultiArray3d &slice, const connection &inter, const int &d3, const int &numG) { // slice -- slice to insert in procBlock @@ -4773,15 +4676,11 @@ void procBlock::PutStateSlice(const multiArray3d &slice, /*Member function to pack and send procBlock geometry data to appropriate * processor. */ -void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, - const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_vec3dMag, - const MPI_Datatype &MPI_wallData) const { - // MPI_cellData -- MPI data type for cell data +void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_vec3d, + const MPI_Datatype &MPI_vec3dMag) const { // MPI_vec3d -- MPI data type for a vector3d // MPI_vec3dMag -- MPI data type for a unitVect3dMag - // MPI_vec3dMag -- MPI data type for a wallData - + // determine size of buffer to send auto sendBufSize = 0; auto tempSize = 0; @@ -4789,13 +4688,13 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, MPI_Pack_size(8, MPI_INT, MPI_COMM_WORLD, &tempSize); // add size for ints in class procBlock sendBufSize += tempSize; - MPI_Pack_size(5, MPI_CXX_BOOL, MPI_COMM_WORLD, + MPI_Pack_size(6, MPI_CXX_BOOL, MPI_COMM_WORLD, &tempSize); // add size for bools in class procBlock sendBufSize += tempSize; - MPI_Pack_size(state_.Size(), MPI_cellData, MPI_COMM_WORLD, + MPI_Pack_size(state_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for states sendBufSize += tempSize; - MPI_Pack_size(consVarsNm1_.Size(), MPI_cellData, MPI_COMM_WORLD, + MPI_Pack_size(consVarsNm1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for solution n-1 sendBufSize += tempSize; MPI_Pack_size(center_.Size(), MPI_vec3d, MPI_COMM_WORLD, @@ -4840,7 +4739,7 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, sendBufSize += stringSize; for (auto &wd : wallData_) { - wd.PackSize(sendBufSize, MPI_wallData); + wd.PackSize(sendBufSize, MPI_vec3d); } // allocate buffer to pack data into @@ -4881,10 +4780,12 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, &position, MPI_COMM_WORLD); MPI_Pack(&isMultiLevelTime_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); - MPI_Pack(&(*std::begin(state_)), state_.Size(), MPI_cellData, sendBuffer, + MPI_Pack(&isMultiSpecies_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, + &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(state_)), state_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); if (isMultiLevelTime_) { - MPI_Pack(&(*std::begin(consVarsNm1_)), consVarsNm1_.Size(), MPI_cellData, + MPI_Pack(&(*std::begin(consVarsNm1_)), consVarsNm1_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); } MPI_Pack(&(*std::begin(center_)), center_.Size(), MPI_vec3d, sendBuffer, @@ -4909,7 +4810,7 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, // pack wall data for (auto &wd : wallData_) { - wd.PackWallData(sendBuffer, sendBufSize, position, MPI_wallData); + wd.PackWallData(sendBuffer, sendBufSize, position, MPI_vec3d); } // send buffer to appropriate processor @@ -4917,15 +4818,11 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, MPI_COMM_WORLD); } -void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, - const MPI_Datatype &MPI_vec3d, +void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_vec3d, const MPI_Datatype &MPI_vec3dMag, - const MPI_Datatype &MPI_wallData, const input &inp) { - // MPI_cellData -- MPI data type for cell data // MPI_vec3d -- MPI data type for a vector3d // MPI_vec3dMag -- MPI data type for a unitVect3dMag - // MPI_wallData -- MPI data type for a wallData // input -- input variables MPI_Status status; // allocate MPI_Status structure @@ -4976,17 +4873,20 @@ void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, MPI_CXX_BOOL, MPI_COMM_WORLD); MPI_Unpack(recvBuffer, recvBufSize, &position, &isMultiLevelTime_, 1, MPI_CXX_BOOL, MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &isMultiSpecies_, 1, + MPI_CXX_BOOL, MPI_COMM_WORLD); // clean and resize the vectors in the class to - this->CleanResizeVecs(numI, numJ, numK, numGhosts_); + this->CleanResizeVecs(numI, numJ, numK, numGhosts_, inp.NumEquations(), + inp.NumSpecies()); // unpack vector data into allocated vectors MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(state_)), - state_.Size(), MPI_cellData, + state_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack states if (isMultiLevelTime_) { MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(consVarsNm1_)), - consVarsNm1_.Size(), MPI_cellData, + consVarsNm1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack sol n-1 } MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(center_)), @@ -5020,25 +4920,26 @@ void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, // unpack wall data wallData_.resize(bc_.NumViscousSurfaces()); for (auto &wd : wallData_) { - wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_wallData, inp); + wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_vec3d, inp); } } /*Member function to zero and resize the vectors in a procBlock to their * appropriate size given the i, j, and k dimensions.*/ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, - const int &numK, const int &numGhosts) { + const int &numK, const int &numGhosts, + const int &numEqns, const int &numSpecies) { // numI -- i-dimension to resize to (no ghosts) // numJ -- j-dimension to resize to (no ghosts) // numK -- k-dimension to resize to (no ghosts) // numGhosts -- number of ghost cells - state_.ClearResize(numI, numJ, numK, numGhosts); + state_.ClearResize(numI, numJ, numK, numGhosts, numEqns, numSpecies); if (storeTimeN_) { - consVarsN_.ClearResize(numI, numJ, numK, 0); + consVarsN_.ClearResize(numI, numJ, numK, 0, numEqns, numSpecies); } if (isMultiLevelTime_) { - consVarsNm1_.ClearResize(numI, numJ, numK, 0); + consVarsNm1_.ClearResize(numI, numJ, numK, 0, numEqns, numSpecies); } center_.ClearResize(numI, numJ, numK, numGhosts); @@ -5053,21 +4954,25 @@ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, fCenterK_.ClearResize(numI, numJ, numK + 1, numGhosts); fAreaK_.ClearResize(numI, numJ, numK + 1, numGhosts); - cellWidthI_.ClearResize(numI, numJ, numK, numGhosts, 0.0); - cellWidthJ_.ClearResize(numI, numJ, numK, numGhosts, 0.0); - cellWidthK_.ClearResize(numI, numJ, numK, numGhosts, 0.0); + cellWidthI_.ClearResize(numI, numJ, numK, numGhosts, 1, 0.0); + cellWidthJ_.ClearResize(numI, numJ, numK, numGhosts, 1, 0.0); + cellWidthK_.ClearResize(numI, numJ, numK, numGhosts, 1, 0.0); - wallDist_.ClearResize(numI, numJ, numK, numGhosts, DEFAULTWALLDIST); + wallDist_.ClearResize(numI, numJ, numK, numGhosts, 1, DEFAULT_WALL_DIST); - residual_.ClearResize(numI, numJ, numK, 0); + residual_.ClearResize(numI, numJ, numK, 0, numEqns, numSpecies); specRadius_.ClearResize(numI, numJ, numK, 0); dt_.ClearResize(numI, numJ, numK, 0); temperature_.ClearResize(numI, numJ, numK, numGhosts); + // vel grad ghosts for off diag term along interblock bc in implicit solver + velocityGrad_.ClearResize(numI, numJ, numK, numGhosts); + temperatureGrad_.ClearResize(numI, numJ, numK, 0); + densityGrad_.ClearResize(numI, numJ, numK, 0); + pressureGrad_.ClearResize(numI, numJ, numK, 0); + if (isViscous_) { - velocityGrad_.ClearResize(numI, numJ, numK, numGhosts); - temperatureGrad_.ClearResize(numI, numJ, numK, numGhosts); viscosity_.ClearResize(numI, numJ, numK, numGhosts); } @@ -5076,35 +4981,34 @@ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, } if (isRANS_) { - tkeGrad_.ClearResize(numI, numJ, numK, numGhosts); - omegaGrad_.ClearResize(numI, numJ, numK, numGhosts); + tkeGrad_.ClearResize(numI, numJ, numK, 0); + omegaGrad_.ClearResize(numI, numJ, numK, 0); f1_.ClearResize(numI, numJ, numK, numGhosts); f2_.ClearResize(numI, numJ, numK, numGhosts); } + + if (isMultiSpecies_) { + mixtureGrad_.ClearResize(numI, numJ, numK, 0, numSpecies); + } } /*Member function to receive and unpack procBlock state data. This is used to * gather the solution on the ROOT processor to write out the solution. */ -void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, - const MPI_Datatype &MPI_uncoupledScalar, +void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, const MPI_Datatype &MPI_tensorDouble, - const MPI_Datatype &MPI_wallData, const input &inp) { - // MPI_cellData -- MPI data type for cell data // MPI_uncoupledScalar -- MPI data type for uncoupledScalar // MPI_vec3d -- MPI data type for vector3d // MPI_tensorDouble -- MPI data taype for tensor - // MPI_wallData -- MPI data taype for wallData // input -- input variables MPI_Status status; // allocate MPI_Status structure // probe message to get correct data size auto recvBufSize = 0; - MPI_Probe(rank_, globalPos_, MPI_COMM_WORLD, - &status); // global position used as tag because each block has a - // unique one + // global position used as tag because each block has a unique one + MPI_Probe(rank_, globalPos_, MPI_COMM_WORLD, &status); MPI_Get_count(&status, MPI_CHAR, &recvBufSize); // use MPI_CHAR because // sending buffer was // allocated with chars @@ -5114,21 +5018,21 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, auto *recvBuffer = unqRecvBuffer.get(); // receive message from non-ROOT - MPI_Recv(recvBuffer, recvBufSize, MPI_PACKED, rank_, - globalPos_, MPI_COMM_WORLD, &status); + MPI_Recv(recvBuffer, recvBufSize, MPI_PACKED, rank_, globalPos_, + MPI_COMM_WORLD, &status); // unpack vector data into allocated vectors auto position = 0; MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(state_)), - state_.Size(), MPI_cellData, + state_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack states if (isMultiLevelTime_) { MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(consVarsNm1_)), - consVarsNm1_.Size(), MPI_cellData, + consVarsNm1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack states } MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(residual_)), - residual_.Size(), MPI_cellData, + residual_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack residuals MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(dt_)), dt_.Size(), MPI_DOUBLE, @@ -5152,16 +5056,23 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, temperature_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack temperature + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(velocityGrad_)), + velocityGrad_.Size(), MPI_tensorDouble, + MPI_COMM_WORLD); // unpack velocity gradient + MPI_Unpack(recvBuffer, recvBufSize, &position, + &(*std::begin(temperatureGrad_)), temperatureGrad_.Size(), + MPI_vec3d, MPI_COMM_WORLD); // unpack temperature gradient + MPI_Unpack(recvBuffer, recvBufSize, &position, + &(*std::begin(densityGrad_)), densityGrad_.Size(), + MPI_vec3d, MPI_COMM_WORLD); // unpack density gradient + MPI_Unpack(recvBuffer, recvBufSize, &position, + &(*std::begin(pressureGrad_)), pressureGrad_.Size(), + MPI_vec3d, MPI_COMM_WORLD); // unpack pressure gradient + if (isViscous_) { MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(viscosity_)), viscosity_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack viscosity - MPI_Unpack(recvBuffer, recvBufSize, &position, - &(*std::begin(velocityGrad_)), velocityGrad_.Size(), - MPI_tensorDouble, MPI_COMM_WORLD); // unpack velocity gradient - MPI_Unpack(recvBuffer, recvBufSize, &position, - &(*std::begin(temperatureGrad_)), temperatureGrad_.Size(), - MPI_vec3d, MPI_COMM_WORLD); // unpack temperature gradient } if (isTurbulent_) { @@ -5185,39 +5096,41 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, MPI_COMM_WORLD); // unpack omega gradient } + if (isMultiSpecies_) { + // unpack mixture gradients + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(mixtureGrad_)), + mixtureGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD); + } + // unpack wall data wallData_.resize(bc_.NumViscousSurfaces()); for (auto &wd : wallData_) { - wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_wallData, inp); + wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_vec3d, inp); } } /*Member function to pack and send procBlock state data to the ROOT proecessor. * This is used to gather the solution on the ROOT processor to write out the * solution. */ -void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, - const MPI_Datatype &MPI_uncoupledScalar, +void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_tensorDouble, - const MPI_Datatype &MPI_wallData) const { - // MPI_cellData -- MPI data type for cell data + const MPI_Datatype &MPI_tensorDouble) const { // MPI_uncoupledScalar -- MPI data type for uncoupledScalar // MPI_vec3d -- MPI data type for vector3d // MPI_tensorDouble -- MPI data taype for tensor - // MPI_wallData -- MPI data taype for wallData // determine size of buffer to send auto sendBufSize = 0; auto tempSize = 0; - MPI_Pack_size(state_.Size(), MPI_cellData, MPI_COMM_WORLD, + MPI_Pack_size(state_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for states sendBufSize += tempSize; if (isMultiLevelTime_) { - MPI_Pack_size(consVarsNm1_.Size(), MPI_cellData, MPI_COMM_WORLD, + MPI_Pack_size(consVarsNm1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for sol n-1 sendBufSize += tempSize; } - MPI_Pack_size(residual_.Size(), MPI_cellData, MPI_COMM_WORLD, + MPI_Pack_size(residual_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for residuals sendBufSize += tempSize; MPI_Pack_size(dt_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, @@ -5242,16 +5155,23 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, &tempSize); // add size for temperature sendBufSize += tempSize; + MPI_Pack_size(velocityGrad_.Size(), MPI_tensorDouble, MPI_COMM_WORLD, + &tempSize); // add size for velocity gradient + sendBufSize += tempSize; + MPI_Pack_size(temperatureGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD, + &tempSize); // add size for temperature gradient + sendBufSize += tempSize; + MPI_Pack_size(densityGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD, + &tempSize); // add size for density gradient + sendBufSize += tempSize; + MPI_Pack_size(pressureGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD, + &tempSize); // add size for pressure gradient + sendBufSize += tempSize; + if (isViscous_) { MPI_Pack_size(viscosity_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for viscosity sendBufSize += tempSize; - MPI_Pack_size(velocityGrad_.Size(), MPI_tensorDouble, MPI_COMM_WORLD, - &tempSize); // add size for velocity gradient - sendBufSize += tempSize; - MPI_Pack_size(temperatureGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD, - &tempSize); // add size for temperature gradient - sendBufSize += tempSize; } if (isTurbulent_) { @@ -5275,8 +5195,14 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, sendBufSize += tempSize; } + if (isMultiSpecies_) { + MPI_Pack_size(mixtureGrad_.Size(), MPI_vec3d, MPI_COMM_WORLD, + &tempSize); // add size for mixture gradients + sendBufSize += tempSize; + } + for (auto &wd : wallData_) { - wd.PackSize(sendBufSize, MPI_wallData); + wd.PackSize(sendBufSize, MPI_vec3d); } // allocate buffer to pack data into @@ -5286,13 +5212,13 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, // pack data to send into buffer auto position = 0; - MPI_Pack(&(*std::begin(state_)), state_.Size(), MPI_cellData, sendBuffer, + MPI_Pack(&(*std::begin(state_)), state_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); if (isMultiLevelTime_) { - MPI_Pack(&(*std::begin(consVarsNm1_)), consVarsNm1_.Size(), MPI_cellData, + MPI_Pack(&(*std::begin(consVarsNm1_)), consVarsNm1_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); } - MPI_Pack(&(*std::begin(residual_)), residual_.Size(), MPI_cellData, + MPI_Pack(&(*std::begin(residual_)), residual_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&(*std::begin(dt_)), dt_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); @@ -5309,14 +5235,19 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, MPI_Pack(&(*std::begin(temperature_)), temperature_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(velocityGrad_)), velocityGrad_.Size(), + MPI_tensorDouble, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(temperatureGrad_)), temperatureGrad_.Size(), MPI_vec3d, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(densityGrad_)), densityGrad_.Size(), MPI_vec3d, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(pressureGrad_)), pressureGrad_.Size(), MPI_vec3d, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + if (isViscous_) { MPI_Pack(&(*std::begin(viscosity_)), viscosity_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); - MPI_Pack(&(*std::begin(velocityGrad_)), velocityGrad_.Size(), - MPI_tensorDouble, sendBuffer, sendBufSize, &position, - MPI_COMM_WORLD); - MPI_Pack(&(*std::begin(temperatureGrad_)), temperatureGrad_.Size(), - MPI_vec3d, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); } if (isTurbulent_) { @@ -5335,9 +5266,14 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); } + if (isMultiSpecies_) { + MPI_Pack(&(*std::begin(mixtureGrad_)), mixtureGrad_.Size(), MPI_vec3d, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + } + // pack wall data for (auto &wd : wallData_) { - wd.PackWallData(sendBuffer, sendBufSize, position, MPI_wallData); + wd.PackWallData(sendBuffer, sendBufSize, position, MPI_vec3d); } // send buffer to appropriate processor @@ -5391,10 +5327,12 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, exit(EXIT_FAILURE); } - procBlock blk1(numI1, numJ1, numK1, numGhosts_, isViscous_, isTurbulent_, - isRANS_, storeTimeN_, isMultiLevelTime_); - procBlock blk2(numI2, numJ2, numK2, numGhosts_, isViscous_, isTurbulent_, - isRANS_, storeTimeN_, isMultiLevelTime_); + procBlock blk1(numI1, numJ1, numK1, numGhosts_, this->NumEquations(), + this->NumSpecies(), isViscous_, isTurbulent_, isRANS_, + storeTimeN_, isMultiLevelTime_, isMultiSpecies_); + procBlock blk2(numI2, numJ2, numK2, numGhosts_, this->NumEquations(), + this->NumSpecies(), isViscous_, isTurbulent_, isRANS_, + storeTimeN_, isMultiLevelTime_, isMultiSpecies_); blk1.parBlock_ = parBlock_; blk2.parBlock_ = parBlock_; @@ -5437,19 +5375,24 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk1.dt_.Fill(dt_.Slice(dir, {dt_.Start(dir), blk1.dt_.End(dir)})); blk1.residual_.Fill(residual_.Slice(dir, {residual_.Start(dir), blk1.residual_.End(dir)})); - if (isViscous_) { - blk1.velocityGrad_.Fill(velocityGrad_.Slice(dir, {velocityGrad_.Start(dir), - blk1.velocityGrad_.End(dir)})); - blk1.temperatureGrad_.Fill( - temperatureGrad_.Slice(dir, {temperatureGrad_.Start(dir), - blk1.temperatureGrad_.End(dir)})); - } + blk1.velocityGrad_.Fill(velocityGrad_.Slice( + dir, {velocityGrad_.Start(dir), blk1.velocityGrad_.End(dir)})); + blk1.temperatureGrad_.Fill(temperatureGrad_.Slice( + dir, {temperatureGrad_.Start(dir), blk1.temperatureGrad_.End(dir)})); + blk1.densityGrad_.Fill(densityGrad_.Slice( + dir, {densityGrad_.Start(dir), blk1.densityGrad_.End(dir)})); + blk1.pressureGrad_.Fill(pressureGrad_.Slice( + dir, {pressureGrad_.Start(dir), blk1.pressureGrad_.End(dir)})); if (isRANS_) { blk1.tkeGrad_.Fill(tkeGrad_.Slice(dir, {tkeGrad_.Start(dir), blk1.tkeGrad_.End(dir)})); blk1.omegaGrad_.Fill(omegaGrad_.Slice(dir, {omegaGrad_.Start(dir), blk1.omegaGrad_.End(dir)})); } + if (isMultiSpecies_) { + blk1.mixtureGrad_.Fill(mixtureGrad_.Slice( + dir, {mixtureGrad_.Start(dir), blk1.mixtureGrad_.End(dir)})); + } // assign face variables blk1.fAreaI_.Fill(fAreaI_.Slice(dir, {fAreaI_.Start(dir), @@ -5493,17 +5436,25 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk2.specRadius_.Fill(specRadius_.Slice(dir, {ind, specRadius_.End(dir)})); blk2.dt_.Fill(dt_.Slice(dir, {ind, dt_.End(dir)})); blk2.residual_.Fill(residual_.Slice(dir, {ind, residual_.End(dir)})); - if (isViscous_) { - blk2.velocityGrad_.Fill(velocityGrad_.Slice(dir, {ind, - velocityGrad_.End(dir)})); - blk2.temperatureGrad_.Fill( - temperatureGrad_.Slice(dir, {ind, temperatureGrad_.End(dir)})); - } + blk2.velocityGrad_.Fill( + velocityGrad_.Slice(dir, {ind, velocityGrad_.End(dir)})); + blk2.temperatureGrad_.Fill( + temperatureGrad_.Slice(dir, {ind, temperatureGrad_.End(dir)})); + blk2.densityGrad_.Fill( + densityGrad_.Slice(dir, {ind, densityGrad_.End(dir)})); + blk2.pressureGrad_.Fill( + pressureGrad_.Slice(dir, {ind, pressureGrad_.End(dir)})); + if (isRANS_) { blk2.tkeGrad_.Fill(tkeGrad_.Slice(dir, {ind, tkeGrad_.End(dir)})); blk2.omegaGrad_.Fill(omegaGrad_.Slice(dir, {ind, omegaGrad_.End(dir)})); } + if (isMultiSpecies_) { + blk2.mixtureGrad_.Fill( + mixtureGrad_.Slice(dir, {ind, mixtureGrad_.End(dir)})); + } + // assign face variables blk2.fAreaI_.Fill(fAreaI_.Slice(dir, {ind, fAreaI_.End(dir)})); blk2.fAreaJ_.Fill(fAreaJ_.Slice(dir, {ind, fAreaJ_.End(dir)})); @@ -5556,8 +5507,9 @@ void procBlock::Join(const procBlock &blk, const string &dir, exit(EXIT_FAILURE); } - procBlock newBlk(iTot, jTot, kTot, numGhosts_, isViscous_, isTurbulent_, - isRANS_, storeTimeN_, isMultiLevelTime_); + procBlock newBlk(iTot, jTot, kTot, numGhosts_, this->NumEquations(), + this->NumSpecies(), isViscous_, isTurbulent_, isRANS_, + storeTimeN_, isMultiLevelTime_, isMultiSpecies_); newBlk.bc_ = bc_; newBlk.bc_.Join(blk.bc_, dir, alteredSurf); @@ -5628,17 +5580,26 @@ void procBlock::Join(const procBlock &blk, const string &dir, residual_.Slice(dir, {residual_.Start(dir), residual_.PhysEnd(dir)})); - if (isViscous_) { - newBlk.velocityGrad_.Insert(dir, {velocityGrad_.Start(dir), - velocityGrad_.PhysEnd(dir)}, - velocityGrad_.Slice(dir, {velocityGrad_.Start(dir), - velocityGrad_.PhysEnd(dir)})); - - newBlk.temperatureGrad_.Insert(dir, {temperatureGrad_.Start(dir), - temperatureGrad_.PhysEnd(dir)}, - temperatureGrad_.Slice(dir, {temperatureGrad_.Start(dir), - temperatureGrad_.PhysEnd(dir)})); - } + newBlk.velocityGrad_.Insert( + dir, {velocityGrad_.Start(dir), velocityGrad_.PhysEnd(dir)}, + velocityGrad_.Slice( + dir, {velocityGrad_.Start(dir), velocityGrad_.PhysEnd(dir)})); + + newBlk.temperatureGrad_.Insert( + dir, {temperatureGrad_.Start(dir), temperatureGrad_.PhysEnd(dir)}, + temperatureGrad_.Slice( + dir, {temperatureGrad_.Start(dir), temperatureGrad_.PhysEnd(dir)})); + + newBlk.densityGrad_.Insert( + dir, {densityGrad_.Start(dir), densityGrad_.PhysEnd(dir)}, + densityGrad_.Slice( + dir, {densityGrad_.Start(dir), densityGrad_.PhysEnd(dir)})); + + newBlk.pressureGrad_.Insert( + dir, {pressureGrad_.Start(dir), pressureGrad_.PhysEnd(dir)}, + pressureGrad_.Slice( + dir, {pressureGrad_.Start(dir), pressureGrad_.PhysEnd(dir)})); + if (isRANS_) { newBlk.tkeGrad_.Insert(dir, {tkeGrad_.Start(dir), tkeGrad_.PhysEnd(dir)}, tkeGrad_.Slice(dir, {tkeGrad_.Start(dir), @@ -5649,6 +5610,13 @@ void procBlock::Join(const procBlock &blk, const string &dir, omegaGrad_.Slice(dir, {omegaGrad_.Start(dir), omegaGrad_.PhysEnd(dir)})); } + if (isMultiSpecies_) { + newBlk.mixtureGrad_.Insert( + dir, {mixtureGrad_.Start(dir), mixtureGrad_.PhysEnd(dir)}, + mixtureGrad_.Slice( + dir, {mixtureGrad_.Start(dir), mixtureGrad_.PhysEnd(dir)})); + } + // assign face variables newBlk.fAreaI_.Insert(dir, {fAreaI_.Start(dir), fAreaI_.PhysEnd(dir)}, fAreaI_.Slice(dir, {fAreaI_.Start(dir), @@ -5748,17 +5716,26 @@ void procBlock::Join(const procBlock &blk, const string &dir, blk.residual_.Slice(dir, {blk.residual_.PhysStart(dir), blk.residual_.End(dir)})); - if (isViscous_) { - newBlk.velocityGrad_.Insert(dir, {velocityGrad_.PhysEnd(dir), - newBlk.velocityGrad_.End(dir)}, - blk.velocityGrad_.Slice(dir, {blk.velocityGrad_.PhysStart(dir), - blk.velocityGrad_.End(dir)})); + newBlk.velocityGrad_.Insert( + dir, {velocityGrad_.PhysEnd(dir), newBlk.velocityGrad_.End(dir)}, + blk.velocityGrad_.Slice( + dir, {blk.velocityGrad_.PhysStart(dir), blk.velocityGrad_.End(dir)})); - newBlk.temperatureGrad_.Insert(dir, {temperatureGrad_.PhysEnd(dir), - newBlk.temperatureGrad_.End(dir)}, + newBlk.temperatureGrad_.Insert( + dir, {temperatureGrad_.PhysEnd(dir), newBlk.temperatureGrad_.End(dir)}, blk.temperatureGrad_.Slice(dir, {blk.temperatureGrad_.PhysStart(dir), - blk.temperatureGrad_.End(dir)})); - } + blk.temperatureGrad_.End(dir)})); + + newBlk.densityGrad_.Insert( + dir, {densityGrad_.PhysEnd(dir), newBlk.densityGrad_.End(dir)}, + blk.densityGrad_.Slice(dir, {blk.densityGrad_.PhysStart(dir), + blk.densityGrad_.End(dir)})); + + newBlk.pressureGrad_.Insert( + dir, {pressureGrad_.PhysEnd(dir), newBlk.pressureGrad_.End(dir)}, + blk.pressureGrad_.Slice(dir, {blk.pressureGrad_.PhysStart(dir), + blk.pressureGrad_.End(dir)})); + if (isRANS_) { newBlk.tkeGrad_.Insert(dir, {tkeGrad_.PhysEnd(dir), newBlk.tkeGrad_.End(dir)}, @@ -5771,6 +5748,13 @@ void procBlock::Join(const procBlock &blk, const string &dir, blk.omegaGrad_.End(dir)})); } + if (isMultiSpecies_) { + newBlk.mixtureGrad_.Insert( + dir, {mixtureGrad_.PhysEnd(dir), newBlk.mixtureGrad_.End(dir)}, + blk.mixtureGrad_.Slice( + dir, {blk.mixtureGrad_.PhysStart(dir), blk.mixtureGrad_.End(dir)})); + } + // assign face variables newBlk.fAreaI_.Insert(dir, {fAreaI_.PhysEnd(dir), newBlk.fAreaI_.End(dir)}, blk.fAreaI_.Slice(dir, @@ -5807,15 +5791,20 @@ void procBlock::Join(const procBlock &blk, const string &dir, void procBlock::CalcGradsI(const int &ii, const int &jj, const int &kk, tensor &velGrad, vector3d &tGrad, + vector3d &dGrad, vector3d &pGrad, vector3d &tkeGrad, - vector3d &omegaGrad) const { + vector3d &omegaGrad, + vector> &mixGrad) const { // ii -- i-index for face (including ghosts) // jj -- j-index for face (including ghosts) // kk -- k-index for face (including ghosts) // velGrad -- tensor to store velocity gradient // tGrad -- vector3d to store temperature gradient + // dGrad -- vector3d to store density gradient + // pGrad -- vector3d to store pressure gradient // tkeGrad -- vector3d to store tke gradient // omegaGrad -- vector3d to store omega gradient + // mixGrad -- mixture gradients // calculate areas of faces in alternate control volume const auto aiu = 0.5 * (fAreaI_(ii, jj, kk).Vector() + @@ -5860,6 +5849,54 @@ void procBlock::CalcGradsI(const int &ii, const int &jj, const int &kk, state_(ii, jj, kk).Velocity(), vjl, vju, vkl, vku, ail, aiu, ajl, aju, akl, aku, vol); + // calculate average density on j and k faces of alternate control volume + const auto dju = 0.25 * (state_(ii - 1, jj, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj + 1, kk).Rho() + + state_(ii - 1, jj + 1, kk).Rho()); + const auto djl = 0.25 * (state_(ii - 1, jj, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj - 1, kk).Rho() + + state_(ii - 1, jj - 1, kk).Rho()); + + const auto dku = 0.25 * (state_(ii - 1, jj, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj, kk + 1).Rho() + + state_(ii - 1, jj, kk + 1).Rho()); + const auto dkl = 0.25 * (state_(ii - 1, jj, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj, kk - 1).Rho() + + state_(ii - 1, jj, kk - 1).Rho()); + + // Get density gradient at face + dGrad = ScalarGradGG(state_(ii - 1, jj, kk).Rho(), + state_(ii, jj, kk).Rho(), djl, dju, + dkl, dku, ail, aiu, ajl, aju, akl, aku, vol); + + // calculate average pressure on j and k faces of alternate control volume + const auto pju = 0.25 * (state_(ii - 1, jj, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj + 1, kk).P() + + state_(ii - 1, jj + 1, kk).P()); + const auto pjl = 0.25 * (state_(ii - 1, jj, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj - 1, kk).P() + + state_(ii - 1, jj - 1, kk).P()); + + const auto pku = 0.25 * (state_(ii - 1, jj, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj, kk + 1).P() + + state_(ii - 1, jj, kk + 1).P()); + const auto pkl = 0.25 * (state_(ii - 1, jj, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj, kk - 1).P() + + state_(ii - 1, jj, kk - 1).P()); + + // Get pressure gradient at face + pGrad = ScalarGradGG(state_(ii - 1, jj, kk).P(), + state_(ii, jj, kk).P(), pjl, pju, + pkl, pku, ail, aiu, ajl, aju, akl, aku, vol); + // calculate average temperature on j and k faces of alternate control volume const auto tju = 0.25 * (temperature_(ii - 1, jj, kk) + temperature_(ii, jj, kk) + @@ -5925,19 +5962,54 @@ void procBlock::CalcGradsI(const int &ii, const int &jj, const int &kk, state_(ii - 1, jj, kk).Omega(), state_(ii, jj, kk).Omega(), omgjl, omgju, omgkl, omgku, ail, aiu, ajl, aju, akl, aku, vol); } + + if (isMultiSpecies_) { + mixGrad.resize(this->NumSpecies()); + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + // calculate average mf on j and k faces of alternate control volume + const auto mfju = 0.25 * (state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj + 1, kk).MassFractionN(ss) + + state_(ii - 1, jj + 1, kk).MassFractionN(ss)); + const auto mfjl = 0.25 * (state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii - 1, jj - 1, kk).MassFractionN(ss)); + + const auto mfku = 0.25 * (state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk + 1).MassFractionN(ss) + + state_(ii - 1, jj, kk + 1).MassFractionN(ss)); + const auto mfkl = 0.25 * (state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii - 1, jj, kk - 1).MassFractionN(ss)); + + // Get tke gradient at face + mixGrad[ss] = + ScalarGradGG(state_(ii - 1, jj, kk).MassFractionN(ss), + state_(ii, jj, kk).MassFractionN(ss), mfjl, mfju, mfkl, + mfku, ail, aiu, ajl, aju, akl, aku, vol); + } + } } void procBlock::CalcGradsJ(const int &ii, const int &jj, const int &kk, tensor &velGrad, vector3d &tGrad, + vector3d &dGrad, vector3d &pGrad, vector3d &tkeGrad, - vector3d &omegaGrad) const { + vector3d &omegaGrad, + vector> &mixGrad) const { // ii -- i-index for face (including ghosts) // jj -- j-index for face (including ghosts) // kk -- k-index for face (including ghosts) // velGrad -- tensor to store velocity gradient // tGrad -- vector3d to store temperature gradient + // dGrad -- vector3d to store density gradient + // pGrad -- vector3d to store pressure gradient // tkeGrad -- vector3d to store tke gradient // omegaGrad -- vector3d to store omega gradient + // mixGrad -- mixture gradients // calculate areas of faces in alternate control volume const auto aju = 0.5 * (fAreaJ_(ii, jj, kk).Vector() + @@ -5982,6 +6054,55 @@ void procBlock::CalcGradsJ(const int &ii, const int &jj, const int &kk, state_(ii, jj, kk).Velocity(), vkl, vku, ail, aiu, ajl, aju, akl, aku, vol); + // calculate average density on i and k faces of alternate control volume + const auto diu = 0.25 * (state_(ii, jj - 1, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii + 1, jj, kk).Rho() + + state_(ii + 1, jj - 1, kk).Rho()); + const auto dil = 0.25 * (state_(ii, jj - 1, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii - 1, jj, kk).Rho() + + state_(ii - 1, jj - 1, kk).Rho()); + + const auto dku = 0.25 * (state_(ii, jj - 1, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj, kk + 1).Rho() + + state_(ii, jj - 1, kk + 1).Rho()); + const auto dkl = 0.25 * (state_(ii, jj - 1, kk).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj, kk - 1).Rho() + + state_(ii, jj - 1, kk - 1).Rho()); + + // Get density gradient at face + dGrad = ScalarGradGG(dil, diu, state_(ii, jj - 1, kk).Rho(), + state_(ii, jj, kk).Rho(), dkl, dku, + ail, aiu, ajl, aju, akl, aku, vol); + + // calculate average pressure on i and k faces of alternate control volume + const auto piu = 0.25 * (state_(ii, jj - 1, kk).P() + + state_(ii, jj, kk).P() + + state_(ii + 1, jj, kk).P() + + state_(ii + 1, jj - 1, kk).P()); + const auto pil = 0.25 * (state_(ii, jj - 1, kk).P() + + state_(ii, jj, kk).P() + + state_(ii - 1, jj, kk).P() + + state_(ii - 1, jj - 1, kk).P()); + + const auto pku = 0.25 * (state_(ii, jj - 1, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj, kk + 1).P() + + state_(ii, jj - 1, kk + 1).P()); + const auto pkl = 0.25 * (state_(ii, jj - 1, kk).P() + + state_(ii, jj, kk).P() + + state_(ii, jj, kk - 1).P() + + state_(ii, jj - 1, kk - 1).P()); + + // Get pressure gradient at face + pGrad = ScalarGradGG(pil, piu, state_(ii, jj - 1, kk).P(), + state_(ii, jj, kk).P(), pkl, pku, + ail, aiu, ajl, aju, akl, aku, vol); + + // calculate average temperature on i and k faces of alternate control volume const auto tiu = 0.25 * (temperature_(ii, jj - 1, kk) + temperature_(ii, jj, kk) + @@ -6047,19 +6168,54 @@ void procBlock::CalcGradsJ(const int &ii, const int &jj, const int &kk, state_(ii, jj, kk).Omega(), omgkl, omgku, ail, aiu, ajl, aju, akl, aku, vol); } + + if (isMultiSpecies_) { + mixGrad.resize(this->NumSpecies()); + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + // calculate average mf on i and k faces of alternate control volume + const auto mfiu = 0.25 * (state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii + 1, jj, kk).MassFractionN(ss) + + state_(ii + 1, jj - 1, kk).MassFractionN(ss)); + const auto mfil = 0.25 * (state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii - 1, jj - 1, kk).MassFractionN(ss)); + + const auto mfku = 0.25 * (state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk + 1).MassFractionN(ss) + + state_(ii, jj - 1, kk + 1).MassFractionN(ss)); + const auto mfkl = 0.25 * (state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii, jj - 1, kk - 1).MassFractionN(ss)); + + // Get temperature gradient at face + mixGrad[ss] = + ScalarGradGG(mfil, mfiu, state_(ii, jj - 1, kk).MassFractionN(ss), + state_(ii, jj, kk).MassFractionN(ss), mfkl, mfku, ail, + aiu, ajl, aju, akl, aku, vol); + } + } } void procBlock::CalcGradsK(const int &ii, const int &jj, const int &kk, tensor &velGrad, vector3d &tGrad, + vector3d &dGrad, vector3d &pGrad, vector3d &tkeGrad, - vector3d &omegaGrad) const { + vector3d &omegaGrad, + vector> &mixGrad) const { // ii -- i-index for face (including ghosts) // jj -- j-index for face (including ghosts) // kk -- k-index for face (including ghosts) // velGrad -- tensor to store velocity gradient // tGrad -- vector3d to store temperature gradient + // dGrad -- vector3d to store density gradient + // pGrad -- vector3d to store pressure gradient // tkeGrad -- vector3d to store tke gradient // omegaGrad -- vector3d to store omega gradient + // mixGrad -- mixture gradients // calculate areas of faces in alternate control volume const auto aku = 0.5 * (fAreaK_(ii, jj, kk).Vector() + @@ -6104,6 +6260,55 @@ void procBlock::CalcGradsK(const int &ii, const int &jj, const int &kk, state_(ii, jj, kk).Velocity(), ail, aiu, ajl, aju, akl, aku, vol); + // calculate average density on i and j faces of alternate control volume + const auto diu = 0.25 * (state_(ii, jj, kk - 1).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii + 1, jj, kk).Rho() + + state_(ii + 1, jj, kk - 1).Rho()); + const auto dil = 0.25 * (state_(ii, jj, kk - 1).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii - 1, jj, kk).Rho() + + state_(ii - 1, jj, kk - 1).Rho()); + + const auto dju = 0.25 * (state_(ii, jj, kk - 1).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj + 1, kk).Rho() + + state_(ii, jj + 1, kk - 1).Rho()); + const auto djl = 0.25 * (state_(ii, jj, kk - 1).Rho() + + state_(ii, jj, kk).Rho() + + state_(ii, jj - 1, kk).Rho() + + state_(ii, jj - 1, kk - 1).Rho()); + + // Get density gradient at face + dGrad = ScalarGradGG(dil, diu, djl, dju, state_(ii, jj, kk - 1).Rho(), + state_(ii, jj, kk).Rho(), ail, aiu, + ajl, aju, akl, aku, vol); + + // calculate average pressure on i and j faces of alternate control volume + const auto piu = 0.25 * (state_(ii, jj, kk - 1).P() + + state_(ii, jj, kk).P() + + state_(ii + 1, jj, kk).P() + + state_(ii + 1, jj, kk - 1).P()); + const auto pil = 0.25 * (state_(ii, jj, kk - 1).P() + + state_(ii, jj, kk).P() + + state_(ii - 1, jj, kk).P() + + state_(ii - 1, jj, kk - 1).P()); + + const auto pju = 0.25 * (state_(ii, jj, kk - 1).P() + + state_(ii, jj, kk).P() + + state_(ii, jj + 1, kk).P() + + state_(ii, jj + 1, kk - 1).P()); + const auto pjl = 0.25 * (state_(ii, jj, kk - 1).P() + + state_(ii, jj, kk).P() + + state_(ii, jj - 1, kk).P() + + state_(ii, jj - 1, kk - 1).P()); + + // Get density gradient at face + pGrad = ScalarGradGG(pil, piu, pjl, pju, state_(ii, jj, kk - 1).P(), + state_(ii, jj, kk).P(), ail, aiu, + ajl, aju, akl, aku, vol); + + // calculate average temperature on i and j faces of alternate control volume const auto tiu = 0.25 * (temperature_(ii, jj, kk - 1) + temperature_(ii, jj, kk) + @@ -6169,15 +6374,207 @@ void procBlock::CalcGradsK(const int &ii, const int &jj, const int &kk, omgil, omgiu, omgjl, omgju, state_(ii, jj, kk - 1).Omega(), state_(ii, jj, kk).Omega(), ail, aiu, ajl, aju, akl, aku, vol); } + + if (isMultiSpecies_) { + mixGrad.resize(this->NumSpecies()); + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + // calculate average mf on i and j faces of alternate control volume + const auto mfiu = 0.25 * (state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii + 1, jj, kk).MassFractionN(ss) + + state_(ii + 1, jj, kk - 1).MassFractionN(ss)); + const auto mfil = 0.25 * (state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii - 1, jj, kk).MassFractionN(ss) + + state_(ii - 1, jj, kk - 1).MassFractionN(ss)); + + const auto mfju = 0.25 * (state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj + 1, kk).MassFractionN(ss) + + state_(ii, jj + 1, kk - 1).MassFractionN(ss)); + const auto mfjl = 0.25 * (state_(ii, jj, kk - 1).MassFractionN(ss) + + state_(ii, jj, kk).MassFractionN(ss) + + state_(ii, jj - 1, kk).MassFractionN(ss) + + state_(ii, jj - 1, kk - 1).MassFractionN(ss)); + + // Get temperature gradient at face + mixGrad[ss] = ScalarGradGG(mfil, mfiu, mfjl, mfju, + state_(ii, jj, kk - 1).MassFractionN(ss), + state_(ii, jj, kk).MassFractionN(ss), ail, aiu, + ajl, aju, akl, aku, vol); + } + } +} + +void procBlock::CalcGradsI() { + + constexpr auto sixth = 1.0 / 6.0; + + // loop over all physical i-faces + for (auto kk = fAreaI_.PhysStartK(); kk < fAreaI_.PhysEndK(); kk++) { + for (auto jj = fAreaI_.PhysStartJ(); jj < fAreaI_.PhysEndJ(); jj++) { + for (auto ii = fAreaI_.PhysStartI(); ii < fAreaI_.PhysEndI(); ii++) { + // calculate gradients + tensor velGrad; + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsI(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); + + // at left boundary there is no left cell to add to + if (ii > fAreaI_.PhysStartI()) { + // store gradients + velocityGrad_(ii - 1, jj, kk) += sixth * velGrad; + temperatureGrad_(ii - 1, jj, kk) += sixth * tempGrad; + densityGrad_(ii - 1, jj, kk) += sixth * denGrad; + pressureGrad_(ii - 1, jj, kk) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii - 1, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii - 1, jj, kk) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii - 1, jj, kk, ss) += sixth * mixGrad[ss]; + } + } + } + + // at right boundary there is no right cell to add to + if (ii < fAreaI_.PhysEndI() - 1) { + // store gradients + velocityGrad_(ii, jj, kk) += sixth * velGrad; + temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ss]; + } + } + } + } + } + } +} + +void procBlock::CalcGradsJ() { + + constexpr auto sixth = 1.0 / 6.0; + + // loop over all physical j-faces + for (auto kk = fAreaJ_.PhysStartK(); kk < fAreaJ_.PhysEndK(); kk++) { + for (auto jj = fAreaJ_.PhysStartJ(); jj < fAreaJ_.PhysEndJ(); jj++) { + for (auto ii = fAreaJ_.PhysStartI(); ii < fAreaJ_.PhysEndI(); ii++) { + // calculate gradients + tensor velGrad; + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsJ(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); + + // at left boundary there is no left cell to add to + if (jj > fAreaJ_.PhysStartJ()) { + // store gradients + velocityGrad_(ii, jj - 1, kk) += sixth * velGrad; + temperatureGrad_(ii, jj - 1, kk) += sixth * tempGrad; + densityGrad_(ii, jj - 1, kk) += sixth * denGrad; + pressureGrad_(ii, jj - 1, kk) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii, jj - 1, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj - 1, kk) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj - 1, kk, ss) += sixth * mixGrad[ss]; + } + } + } + + // at right boundary there is no right cell to add to + if (jj < fAreaJ_.PhysEndJ() - 1) { + // store gradients + velocityGrad_(ii, jj, kk) += sixth * velGrad; + temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ss]; + } + } + } + } + } + } +} + +void procBlock::CalcGradsK() { + + constexpr auto sixth = 1.0 / 6.0; + + // loop over all physical k-faces + for (auto kk = fAreaK_.PhysStartK(); kk < fAreaK_.PhysEndK(); kk++) { + for (auto jj = fAreaK_.PhysStartJ(); jj < fAreaK_.PhysEndJ(); jj++) { + for (auto ii = fAreaK_.PhysStartI(); ii < fAreaK_.PhysEndI(); ii++) { + // calculate gradients + tensor velGrad; + vector3d tempGrad, denGrad, pressGrad, tkeGrad, omegaGrad; + vector> mixGrad; + this->CalcGradsK(ii, jj, kk, velGrad, tempGrad, denGrad, pressGrad, + tkeGrad, omegaGrad, mixGrad); + + // at left boundary there is no left cell to add to + if (kk > fAreaK_.PhysStartK()) { + // store gradients + velocityGrad_(ii, jj, kk - 1) += sixth * velGrad; + temperatureGrad_(ii, jj, kk - 1) += sixth * tempGrad; + densityGrad_(ii, jj, kk - 1) += sixth * denGrad; + pressureGrad_(ii, jj, kk - 1) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii, jj, kk - 1) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk - 1) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk - 1, ss) += sixth * mixGrad[ss]; + } + } + } + + // at right boundary there is no right cell to add to + if (kk < fAreaK_.PhysEndK() - 1) { + // store gradients + velocityGrad_(ii, jj, kk) += sixth * velGrad; + temperatureGrad_(ii, jj, kk) += sixth * tempGrad; + densityGrad_(ii, jj, kk) += sixth * denGrad; + pressureGrad_(ii, jj, kk) += sixth * pressGrad; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + } + if (isMultiSpecies_) { + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + mixtureGrad_(ii, jj, kk, ss) += sixth * mixGrad[ss]; + } + } + } + } + } + } } // Member function to calculate the source terms and add them to the residual -void procBlock::CalcSrcTerms(const unique_ptr &trans, - const unique_ptr &turb, - const input &inp, - multiArray3d &mainDiagonal) { - // trans -- unique_ptr's law for viscosity - // turb -- turbulence model +void procBlock::CalcSrcTerms(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { + // phys -- phyics models // mainDiagonal -- main diagonal of LHS used to store flux jacobians for // implicit solver @@ -6186,35 +6583,32 @@ void procBlock::CalcSrcTerms(const unique_ptr &trans, for (auto jj = 0; jj < this->NumJ(); jj++) { for (auto ii = 0; ii < this->NumI(); ii++) { // calculate turbulent source terms - const auto phi = turb->UsePhi() ? this->MaxCellWidth(ii, jj, kk) : 1.0; - source src; - const auto srcJac = src.CalcTurbSrc(turb, state_(ii, jj, kk), - velocityGrad_(ii, jj, kk), - temperatureGrad_(ii, jj, kk), - tkeGrad_(ii, jj, kk), - omegaGrad_(ii, jj, kk), trans, - vol_(ii, jj, kk), - eddyViscosity_(ii, jj, kk), - f1_(ii, jj, kk), f2_(ii, jj, kk), - phi); + const auto phi = + phys.Turbulence()->UsePhi() ? this->MaxCellWidth(ii, jj, kk) : 1.0; + source src(this->NumEquations(), this->NumSpecies()); + const auto srcJac = src.CalcTurbSrc( + phys.Turbulence(), state_(ii, jj, kk), velocityGrad_(ii, jj, kk), + temperatureGrad_(ii, jj, kk), tkeGrad_(ii, jj, kk), + omegaGrad_(ii, jj, kk), phys.Transport(), vol_(ii, jj, kk), + eddyViscosity_(ii, jj, kk), f1_(ii, jj, kk), f2_(ii, jj, kk), phi); // add source terms to residual // subtract because residual is initially on opposite side of equation - this->SubtractFromResidual(src * vol_(ii, jj, kk), - ii, jj, kk); + this->SubtractFromResidual(ii, jj, kk, src * vol_(ii, jj, kk)); // add source spectral radius for turbulence equations // subtract because residual is initially on opposite side of equation - const auto turbSpecRad = turb->SrcSpecRad(state_(ii, jj, kk), trans, - vol_(ii, jj, kk), phi); + const auto turbSpecRad = phys.Turbulence()->SrcSpecRad( + state_(ii, jj, kk), phys.Transport(), vol_(ii, jj, kk), phi); specRadius_(ii, jj, kk).SubtractFromTurbVariable(turbSpecRad); // add contribution of source spectral radius to flux jacobian if (inp.IsBlockMatrix()) { - mainDiagonal(ii, jj, kk).SubtractFromTurbJacobian(srcJac); + mainDiagonal.SubtractFromTurb(ii, jj, kk, srcJac); } else if (inp.IsImplicit()) { const uncoupledScalar srcJacScalar(0.0, turbSpecRad); - mainDiagonal(ii, jj, kk) -= fluxJacobian(srcJacScalar); + mainDiagonal.Subtract(ii, jj, kk, + fluxJacobian(srcJacScalar, isRANS_)); } } } @@ -6227,55 +6621,75 @@ void procBlock::CalcSrcTerms(const unique_ptr &trans, void procBlock::CalcWallDistance(const kdtree &tree) { vector3d neighbor; auto id = 0; + // loop over physical cells + for (auto kk = this->StartK(); kk < this->EndK(); kk++) { + for (auto jj = this->StartJ(); jj < this->EndJ(); jj++) { + for (auto ii = this->StartI(); ii < this->EndI(); ii++) { + wallDist_(ii, jj, kk) = + tree.NearestNeighbor(center_(ii, jj, kk), neighbor, id); + } + } + } + string surf = "none"; auto type = 0; - // loop over cells, including ghosts + // populate ghost cells (not edge ghosts) for (auto kk = wallDist_.StartK(); kk < wallDist_.EndK(); kk++) { for (auto jj = wallDist_.StartJ(); jj < wallDist_.EndJ(); jj++) { for (auto ii = wallDist_.StartI(); ii < wallDist_.EndI(); ii++) { // ghost cells across viscous boundaries should have negative wall // distance so that wall distance at viscous face will be 0 during flux // calculation - if (this->IsPhysical(ii, jj, kk)) { - wallDist_(ii, jj, kk) = tree.NearestNeighbor(center_(ii, jj, kk), - neighbor, id); - } else if (this->AtGhostNonEdge(ii, jj, kk, surf, type)) { + // other ghost cells just use distance of interior cell + if (this->AtGhostNonEdge(ii, jj, kk, surf, type)) { if (type == 1) { auto bcType = bc_.GetBCName(this->StartI(), jj, kk, type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(this->StartI(), jj, kk), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->StartI() + std::abs(ii) - 1; + wallDist_(ii, jj, kk) = -1.0 * wallDist_(index, jj, kk); + } else { + wallDist_(ii, jj, kk) = wallDist_(this->StartI(), jj, kk); + } } else if (type == 2) { auto bcType = bc_.GetBCName(this->EndI(), jj, kk, type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(this->EndI() - 1, jj, kk), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->EndI() - (ii - this->EndI() + 1); + wallDist_(ii, jj, kk) = -1.0 * wallDist_(index, jj, kk); + } else { + wallDist_(ii, jj, kk) = wallDist_(this->EndI() - 1, jj, kk); + } } else if (type == 3) { auto bcType = bc_.GetBCName(ii, this->StartJ(), kk, type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(ii, this->StartJ(), kk), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->StartJ() + std::abs(jj) - 1; + wallDist_(ii, jj, kk) = -1.0 * wallDist_(ii, index, kk); + } else { + wallDist_(ii, jj, kk) = wallDist_(ii, this->StartJ(), kk); + } } else if (type == 4) { auto bcType = bc_.GetBCName(ii, this->EndJ(), kk, type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(ii, this->EndJ() - 1, kk), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->EndJ() - (jj - this->EndJ() + 1); + wallDist_(ii, jj, kk) = -1.0 * wallDist_(ii, index, kk); + } else { + wallDist_(ii, jj, kk) = wallDist_(ii, this->EndJ() - 1, kk); + } } else if (type == 5) { auto bcType = bc_.GetBCName(ii, jj, this->StartK(), type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(ii, jj, this->StartK()), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->StartK() + std::abs(kk) - 1; + wallDist_(ii, jj, kk) = -1.0 * wallDist_(ii, jj, index); + } else { + wallDist_(ii, jj, kk) = wallDist_(ii, jj, this->StartK()); + } } else if (type == 6) { auto bcType = bc_.GetBCName(ii, jj, this->EndK(), type); - auto fac = (bcType == "viscousWall") ? -1.0 : 1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(ii, jj, this->EndK() - 1), - neighbor, id); + if (bcType == "viscousWall") { + auto index = this->EndK() - (kk - this->EndK() + 1); + wallDist_(ii, jj, kk) = -1.0 * wallDist_(ii, jj, index); + } else { + wallDist_(ii, jj, kk) = wallDist_(ii, jj, this->EndK() - 1); + } } } } @@ -6285,51 +6699,49 @@ void procBlock::CalcWallDistance(const kdtree &tree) { // member function to calculate the residual (RHS) excluding any contributions // from source terms -void procBlock::CalcResidualNoSource(const unique_ptr &trans, - const unique_ptr &thermo, - const unique_ptr &eos, - const input &inp, - const unique_ptr &turb, - multiArray3d &mainDiagonal) { +void procBlock::CalcResidualNoSource(const physics &phys, const input &inp, + matMultiArray3d &mainDiagonal) { // Zero spectral radii, residuals, gradients, turbulence variables this->ResetResidWS(); - if (isViscous_) { - this->ResetGradients(); - if (isTurbulent_) { - this->ResetTurbVars(); - } + this->ResetGradients(); + if (isTurbulent_) { + this->ResetTurbVars(); } // Calculate inviscid fluxes - this->CalcInvFluxI(eos, thermo, inp, turb, mainDiagonal); - this->CalcInvFluxJ(eos, thermo, inp, turb, mainDiagonal); - this->CalcInvFluxK(eos, thermo, inp, turb, mainDiagonal); + this->CalcInvFluxI(phys, inp, mainDiagonal); + this->CalcInvFluxJ(phys, inp, mainDiagonal); + this->CalcInvFluxK(phys, inp, mainDiagonal); // If viscous change ghost cells and calculate viscous fluxes if (isViscous_) { // Determine ghost cell values for viscous fluxes - this->AssignViscousGhostCells(inp, eos, thermo, trans, turb); + this->AssignViscousGhostCells(inp, phys); // Update temperature and viscosity - this->UpdateAuxillaryVariables(eos, trans); + this->UpdateAuxillaryVariables(phys); // Calculate viscous fluxes - this->CalcViscFluxI(trans, thermo, eos, inp, turb, mainDiagonal); - this->CalcViscFluxJ(trans, thermo, eos, inp, turb, mainDiagonal); - this->CalcViscFluxK(trans, thermo, eos, inp, turb, mainDiagonal); + this->CalcViscFluxI(phys, inp, mainDiagonal); + this->CalcViscFluxJ(phys, inp, mainDiagonal); + this->CalcViscFluxK(phys, inp, mainDiagonal); } else { // Update temperature - this->UpdateAuxillaryVariables(eos, trans); + this->UpdateAuxillaryVariables(phys); + + // calculate gradients + this->CalcGradsI(); + this->CalcGradsJ(); + this->CalcGradsK(); } } - // member function to get a slice of the state variables -multiArray3d procBlock::SliceState(const int &is, const int &ie, - const int &js, const int &je, - const int &ks, - const int &ke) const { +blkMultiArray3d procBlock::SliceState(const int &is, const int &ie, + const int &js, const int &je, + const int &ks, + const int &ke) const { return state_.Slice({is, ie}, {js, je}, {ks, ke}); } @@ -6347,17 +6759,19 @@ multiArray3d> procBlock::SliceBoundaryCenters( } } -void procBlock::UpdateAuxillaryVariables(const unique_ptr &eos, - const unique_ptr &trans, +void procBlock::UpdateAuxillaryVariables(const physics &phys, const bool includeGhosts) { for (auto kk = temperature_.StartK(); kk < temperature_.EndK(); kk++) { for (auto jj = temperature_.StartJ(); jj < temperature_.EndJ(); jj++) { for (auto ii = temperature_.StartI(); ii < temperature_.EndI(); ii++) { if (!this->AtCorner(ii, jj, kk) && (includeGhosts || this->IsPhysical(ii, jj, kk))) { - temperature_(ii, jj, kk) = state_(ii, jj, kk).Temperature(eos); + temperature_(ii, jj, kk) = state_(ii, jj, kk).Temperature(phys.EoS()); + MSG_ASSERT(temperature_(ii, jj, kk) > 0.0, "nonphysical temperature"); if (isViscous_) { - viscosity_(ii, jj, kk) = trans->Viscosity(temperature_(ii, jj, kk)); + viscosity_(ii, jj, kk) = phys.Transport()->Viscosity( + temperature_(ii, jj, kk), state_(ii, jj, kk).MassFractions()); + MSG_ASSERT(viscosity_(ii, jj, kk) >= 0.0, "nonphysical viscosity"); } } } @@ -6382,39 +6796,85 @@ void procBlock::UpdateUnlimTurbEddyVisc(const unique_ptr &turb, } } -multiArray3d procBlock::GetGhostStates( - const multiArray3d &bndStates, const string &bcName, +blkMultiArray3d procBlock::GetGhostStates( + const blkMultiArray3d &bndStates, const string &bcName, const multiArray3d> &faceAreas, const multiArray3d &wDist, const boundarySurface &surf, - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, const unique_ptr &trans, - const unique_ptr &turb, const int layer) { + const input &inp, const physics &phys, const int &layer, + const multiArray3d &nuW, const multiArray3d &dt, + const blkMultiArray3d &consVarsN, + const multiArray3d> &pGrad, + const multiArray3d> &velGrad) { // bndStates -- states at cells adjacent to boundary // bcName -- boundary condition type // faceAreas -- face areas of boundary // surf -- boundary surface // inp -- input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // layer -- layer of ghost cell to return // (1 closest to boundary, or 2 farthest) + // nuW -- wall adjacent kinematic viscosity + // dt -- time step at cells adjacent to boundary + // consVarsN -- conservative variables at time n + // pGrad -- pressure gradient at adjacent cell + // velGrad -- velocity gradient at adjacent cell + + // get surface type and tag + const auto surfType = surf.SurfaceType(); + const auto tag = surf.Tag(); + + // find average and max mach on boundary for nonreflecting pressure outlet + // only using data on local surface patch here, not bothering to make MPI + // calls to get data over global patch + auto avgMach = 0.0; + auto maxMach = -1.0 * std::numeric_limits::max(); + if (bcName == "pressureOutlet" || bcName == "inlet") { + const auto &bcData = inp.BCData(tag); + if (bcData->IsNonreflecting()) { + // face area vector (should always point out of domain) + // at lower surface normal should point out of domain for ghost cell calc + const auto isLower = surfType % 2 == 1; + for (auto kk = bndStates.StartK(); kk < bndStates.EndK(); kk++) { + for (auto jj = bndStates.StartJ(); jj < bndStates.EndJ(); jj++) { + for (auto ii = bndStates.StartI(); ii < bndStates.EndI(); ii++) { + const auto area = isLower + ? -1.0 * faceAreas(ii, jj, kk).UnitVector() + : faceAreas(ii, jj, kk).UnitVector(); + auto mach = bndStates(ii, jj, kk).Velocity().DotProd(area) / + bndStates(ii, jj, kk).SoS(phys); + maxMach = std::max(maxMach, mach); + avgMach += mach; + } + } + } + avgMach /= bndStates.NumBlocks(); + } + } - multiArray3d ghostStates( + blkMultiArray3d ghostStates( bndStates.NumINoGhosts(), bndStates.NumJNoGhosts(), - bndStates.NumKNoGhosts(), bndStates.GhostLayers()); + bndStates.NumKNoGhosts(), bndStates.GhostLayers(), bndStates.BlockSize(), + this->NumSpecies()); for (auto kk = bndStates.StartK(); kk < bndStates.EndK(); kk++) { for (auto jj = bndStates.StartJ(); jj < bndStates.EndJ(); jj++) { for (auto ii = bndStates.StartI(); ii < bndStates.EndI(); ii++) { - const auto surfType = surf.SurfaceType(); - const auto tag = surf.Tag(); - wallVars wVars; - ghostStates(ii, jj, kk) = - bndStates(ii, jj, kk) - .GetGhostState(bcName, faceAreas(ii, jj, kk).UnitVector(), - wDist(ii, jj, kk), surfType, inp, tag, eqnState, - thermo, trans, turb, wVars, layer); + wallVars wVars(this->NumSpecies()); + const auto nuWall = nuW.IsEmpty() ? 0.0 : nuW(ii, jj, kk); + if (consVarsN.IsEmpty()) { + const auto ghost = GetGhostState(bndStates(ii, jj, kk), bcName, + faceAreas(ii, jj, kk).UnitVector(), + wDist(ii, jj, kk), surfType, inp, + tag, phys, wVars, layer, nuWall); + ghostStates.InsertBlock(ii, jj, kk, ghost); + } else { // using dt, state at time n, press grad, vel grad in BC + const auto stateN = primitive(consVarsN(ii, jj, kk), phys); + const auto ghost = GetGhostState( + bndStates(ii, jj, kk), bcName, faceAreas(ii, jj, kk).UnitVector(), + wDist(ii, jj, kk), surfType, inp, tag, phys, wVars, layer, nuWall, + dt(ii, jj, kk), stateN, pGrad(ii, jj, kk), velGrad(ii, jj, kk), + avgMach, maxMach); + ghostStates.InsertBlock(ii, jj, kk, ghost); + } if (bcName == "viscousWall" && layer == 1) { const auto ind = this->WallDataIndex(surf); wallData_[ind](ii, jj, kk, true) = wVars; @@ -6507,6 +6967,10 @@ void procBlock::DumpToFile(const string &var, const string &fName) const { outFile << velocityGrad_ << endl; } else if (var == "temperatureGradient") { outFile << temperatureGrad_ << endl; + } else if (var == "densityGradient") { + outFile << densityGrad_ << endl; + } else if (var == "pressureGradient") { + outFile << pressureGrad_ << endl; } else if (var == "viscosity") { outFile << viscosity_ << endl; } else if (var == "eddyViscosity") { @@ -6538,11 +7002,11 @@ void procBlock::CalcCellWidths() { } -void procBlock::GetStatesFromRestart(const multiArray3d &restart) { +void procBlock::GetStatesFromRestart(const blkMultiArray3d &restart) { state_.Insert(restart.RangeI(), restart.RangeJ(), restart.RangeK(), restart); } -void procBlock::GetSolNm1FromRestart(const multiArray3d &restart) { +void procBlock::GetSolNm1FromRestart(const blkMultiArray3d &restart) { consVarsNm1_ = restart; } diff --git a/src/range.cpp b/src/range.cpp index 7086312..ed8c06b 100644 --- a/src/range.cpp +++ b/src/range.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/resid.cpp b/src/resid.cpp index 663d8ba..f939985 100644 --- a/src/resid.cpp +++ b/src/resid.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/slices.cpp b/src/slices.cpp index 214ad13..d2af080 100644 --- a/src/slices.cpp +++ b/src/slices.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/source.cpp b/src/source.cpp index 2072c59..d7cf677 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +19,6 @@ #include #include "source.hpp" #include "turbulence.hpp" -#include "primVars.hpp" #include "transport.hpp" #include "vector3d.hpp" #include "tensor.hpp" @@ -30,27 +29,23 @@ using std::endl; using std::cerr; using std::unique_ptr; -// operator overload for << - allows use of cout, cerr, etc. -ostream &operator<<(ostream &os, const source &src) { - os << src.SrcMass() << endl; - os << src.SrcMomX() << endl; - os << src.SrcMomY() << endl; - os << src.SrcMomZ() << endl; - os << src.SrcEngy() << endl; - os << src.SrcTke() << endl; - os << src.SrcOmg() << endl; +// operation overload for << - allows use of cout, cerr, etc. +ostream &operator<<(ostream &os, const source &m) { + for (auto rr = 0; rr < m.Size(); rr++) { + os << m[rr] << endl; + } return os; } // Member function to calculate the source terms for the turbulence equations squareMatrix source::CalcTurbSrc( - const unique_ptr &turb, const primVars &state, + const unique_ptr &turb, const primitiveView &state, const tensor &velGrad, const vector3d &tGrad, const vector3d &tkeGrad, const vector3d &omegaGrad, const unique_ptr &trans, const double &vol, const double &mut, const double &f1, const double &f2, const double &phi) { // turb -- turbulence model - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // tGrad -- temperature gradient // tkeGrad -- tke gradient @@ -63,15 +58,15 @@ squareMatrix source::CalcTurbSrc( // phi -- factor to reduce tke destruction by for des // calculate turbulent source terms - auto ksrc = 0.0; - auto wsrc = 0.0; + vector turbSrc(this->NumTurbulence(), 0.0); const auto srcJac = turb->CalcTurbSrc(state, velGrad, tkeGrad, omegaGrad, trans, vol, mut, f1, - f2, phi, ksrc, wsrc); + f2, phi, turbSrc); // assign turbulent source terms - data_[5] = ksrc; - data_[6] = wsrc; + for (auto ii = 0; ii < this->NumTurbulence(); ++ii) { + (*this)[this->TurbulenceIndex() + ii] = turbSrc[ii]; + } // return source jacobian return srcJac; diff --git a/src/thermodynamic.cpp b/src/thermodynamic.cpp index 34f447c..d6cac33 100644 --- a/src/thermodynamic.cpp +++ b/src/thermodynamic.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,26 +17,108 @@ #include // cout #include "thermodynamic.hpp" #include "utility.hpp" // FindRoot +#include "fluid.hpp" +#include "macros.hpp" using std::cout; using std::endl; using std::cerr; -// Member functions for thermodynamic class +// constructor +caloricallyPerfect::caloricallyPerfect(const vector& fl, + const double& tRef, const double& aRef) { + const auto numSpecies = fl.size(); + n_.reserve(numSpecies); + gasConst_.reserve(numSpecies); + for (auto &f : fl) { + n_.push_back(f.N()); + gasConst_.push_back(f.GasConstant() * tRef / (aRef * aRef)); + } +} + +thermallyPerfect::thermallyPerfect(const vector& fl, const double& tRef, + const double& aRef) + : caloricallyPerfect(fl, tRef, aRef) { + vibTemp_.reserve(fl.size()); + for (auto& f : fl) { + vibTemp_.push_back(f.VibrationalTemperature()); + } +} + +// --------------------------------------------------------------------------- +// shared functions +double thermodynamic::Cp(const double& t, const vector& mf) const { + MSG_ASSERT(this->NumSpecies() == static_cast(mf.size()), + "species size mismatch"); + auto cp = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + cp += mf[ss] * this->SpeciesCp(t, ss); + } + return cp; +} + +double thermodynamic::Cv(const double& t, const vector& mf) const { + MSG_ASSERT(this->NumSpecies() == static_cast(mf.size()), + "species size mismatch"); + auto cv = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + cv += mf[ss] * this->SpeciesCv(t, ss); + } + return cv; +} -double caloricallyPerfect::TemperatureFromSpecEnergy(const double& e) const { +// --------------------------------------------------------------------------- +// Member functions for calorically perfect class +double caloricallyPerfect::TemperatureFromSpecEnergy( + const double& e, const vector& mf) const { const auto t = 1.0; // cpg has constant Cv, so value of t is meaningless - return e / this->Cv(t); + return e / this->Cv(t, mf); +} + +// --------------------------------------------------------------------------- +// thermally perfect functions +double thermallyPerfect::SpeciesSpecEnergy(const double& t, + const int& ss) const { + MSG_ASSERT(ss <= this->NumSpecies(), "species out of range"); + return this->R(ss) * (this->N(ss) * t + this->VibEqTerm(t, ss)); +} + +double thermallyPerfect::SpecEnergy(const double& t, + const vector& mf) const { + MSG_ASSERT(this->NumSpecies() == static_cast(mf.size()), + "species size mismatch"); + auto e = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + e += mf[ss] * this->SpeciesSpecEnergy(t, ss); + } + return e; +} + +double thermallyPerfect::SpeciesSpecEnthalpy(const double& t, + const int& ss) const { + MSG_ASSERT(ss <= this->NumSpecies(), "species out of range"); + return this->R(ss) * ((this->N(ss) + 1) * t + this->VibEqTerm(t, ss)); +} + +double thermallyPerfect::SpecEnthalpy(const double& t, + const vector& mf) const { + MSG_ASSERT(this->NumSpecies() == static_cast(mf.size()), + "species size mismatch"); + auto h = 0.0; + for (auto ss = 0; ss < this->NumSpecies(); ++ss) { + h += mf[ss] * this->SpeciesSpecEnthalpy(t, ss); + } + return h; } -double thermallyPerfect::TemperatureFromSpecEnergy(const double& e) const { +double thermallyPerfect::TemperatureFromSpecEnergy( + const double& e, const vector& mf) const { auto temperature = 0.0; auto func = [&](const double& t) { temperature = t; - //cout << "t: " << temperature << endl; - return e - this->SpecEnergy(t); + return e - this->SpecEnergy(t, mf); }; FindRoot(func, 1.0e-8, 1.0e4, 1.0e-8); - + return temperature; } \ No newline at end of file diff --git a/src/transport.cpp b/src/transport.cpp index 87c456c..7ba2c7b 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,32 +14,183 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include #include // cout #include // exit() +#include #include "transport.hpp" +#include "fluid.hpp" +#include "macros.hpp" +using std::vector; using std::cout; using std::endl; using std::cerr; +// constructor for sutherland class +sutherland::sutherland(const vector &fl, const double &tRef, + const double &rRef, const double &lRef, + const double &aRef, const vector &mixRef) { + MSG_ASSERT(fl.size() == mixRef.size(), "mixture must be same size as fluids"); + + auto numSpecies = fl.size(); + // size coefficient vectors + viscC1_.reserve(numSpecies); + viscS_.reserve(numSpecies); + condC1_.reserve(numSpecies); + condS_.reserve(numSpecies); + molarMass_.reserve(numSpecies); + + tRef_ = tRef; + + vector muSpecRef; + muSpecRef.reserve(numSpecies); + + // get data from fluid class + for (auto &f : fl) { + auto viscCoeffs = f.ViscosityCoeffs(); + viscC1_.push_back(viscCoeffs[0]); + viscS_.push_back(viscCoeffs[1]); + + auto condCoeffs = f.ConductivityCoeffs(); + condC1_.push_back(condCoeffs[0]); + condS_.push_back(condCoeffs[1]); + + muSpecRef.push_back(viscCoeffs[0] * pow(tRef_, 1.5) / + (tRef_ + viscCoeffs[1])); + molarMass_.push_back(f.MolarMass()); + } + + // calculate reference viscosity for reference mixture and set scaling + muMixRef_ = + numSpecies == 1 ? muSpecRef[0] : this->WilkesVisc(muSpecRef, mixRef); + kNonDim_ = (aRef * aRef * muMixRef_) / tRef_; + this->SetScaling(rRef, lRef, muMixRef_, aRef); +} + +// member function to use Wilke's method to calculate mixture viscosity +double sutherland::WilkesVisc(const vector &specVisc, + const vector &mf) const { + // specVisc -- vector of species viscosities + // mf -- vector of species mass fractions + MSG_ASSERT(mf.size() == specVisc.size(), "mismatch in species size"); + + // calculate mole fractions + auto moleFrac = this->MoleFractions(mf); + + auto mixtureVisc = 0.0; + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + auto moleVisc = moleFrac[ii] * specVisc[ii]; + auto denom = 0.0; + for (auto jj = 0; jj < this->NumSpecies(); ++jj) { + denom += moleFrac[jj] / sqrt(1.0 + molarMass_[ii] / molarMass_[jj]) * + pow(1.0 + sqrt(specVisc[ii] / specVisc[jj]) * + pow(molarMass_[jj] / molarMass_[ii], 0.25), + 2.0); + } + mixtureVisc += moleVisc / denom; + } + return 4.0 / sqrt(2.0) * mixtureVisc; +} + +// member function to use Wilke's method to calculate mixture conductivity +double sutherland::WilkesCond(const vector &specCond, + const vector &mf) const { + // calculate mole fractions + auto moleFrac = this->MoleFractions(mf); + + auto weightedAvg = 0.0; + auto harmonicAvg = 0.0; + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + weightedAvg += moleFrac[ii] * specCond[ii]; + harmonicAvg += moleFrac[ii] / specCond[ii]; + } + harmonicAvg = 1.0 / harmonicAvg; + return 0.5 * (weightedAvg + harmonicAvg); +} + + // Functions for sutherland class -double sutherland::Viscosity(const double &t) const { +double sutherland::SpeciesViscosity(const double &t, const int &ii) const { + MSG_ASSERT(ii < this->NumSpecies(), "Accessing index out of range"); // Dimensionalize temperature const auto temp = t * tRef_; - // Calculate viscosity - const auto mu = (cOne_ * pow(temp, 1.5)) / (temp + S_); - + const auto mu = (viscC1_[ii] * pow(temp, 1.5)) / (temp + viscS_[ii]); // Nondimensionalize viscosity - return (mu / muRef_); + return mu / muMixRef_; +} + +double sutherland::SpeciesConductivity(const double &t, const int &ii) const { + MSG_ASSERT(ii < this->NumSpecies(), "Accessing index out of range"); + // Dimensionalize temperature + const auto temp = t * tRef_; + // Calculate conductivity + const auto k = (condC1_[ii] * pow(temp, 1.5)) / (temp + condS_[ii]); + // Nondimensionalize conductivity + return k / kNonDim_; +} + + +vector sutherland::MoleFractions(const vector &mf) const { + MSG_ASSERT(static_cast(mf.size()) == this->NumSpecies(), + "mismatch in species size"); + + vector moleFrac(this->NumSpecies()); + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + moleFrac[ii] = mf[ii] / molarMass_[ii]; + } + auto moleFracSum = std::accumulate(moleFrac.begin(), moleFrac.end(), 0.0); + std::for_each(moleFrac.begin(), moleFrac.end(), + [&moleFracSum](auto &val) { val /= moleFracSum; }); + return moleFrac; } -double sutherland::EffectiveViscosity(const double &t) const { +// member function to use Wilke's method to calculate mixture viscosity +double sutherland::Viscosity(const double &t, const vector &mf) const { + MSG_ASSERT(static_cast(mf.size()) == this->NumSpecies(), + "mismatch in species size"); + + if (this->NumSpecies() == 1) { + return this->SpeciesViscosity(t, 0); + } else { + // calculate species viscosity and mole fractions + vector specVisc(this->NumSpecies()); + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + specVisc[ii] = this->SpeciesViscosity(t, ii); + } + return this->WilkesVisc(specVisc, mf); + } +} + +double sutherland::EffectiveViscosity(const double &t, + const vector &mf) const { // Get viscosity and scale - return this->Viscosity(t) * this->NondimScaling(); + return this->Viscosity(t, mf) * this->NondimScaling(); } double sutherland::Lambda(const double &mu) const { // Calculate lambda (2nd coeff of viscosity) return bulkVisc_ - (2.0 / 3.0) * mu; } + +// member function to use Wilke's method to calculate mixture conductivity +double sutherland::Conductivity(const double &t, + const vector &mf) const { + if (this->NumSpecies() == 1) { + return this->SpeciesConductivity(t, 0); + } else { + // calculate species conductivity and mole fractions + vector specCond(this->NumSpecies()); + for (auto ii = 0; ii < this->NumSpecies(); ++ii) { + specCond[ii] = this->SpeciesConductivity(t, ii); + } + return this->WilkesCond(specCond, mf); + } +} + +double sutherland::EffectiveConductivity(const double &t, + const vector &mf) const { + // Get viscosity and scale + return this->Conductivity(t, mf) * this->NondimScaling(); +} diff --git a/src/turbulence.cpp b/src/turbulence.cpp index 99df74d..e6214e2 100644 --- a/src/turbulence.cpp +++ b/src/turbulence.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +18,8 @@ #include // cout #include // max #include "turbulence.hpp" -#include "primVars.hpp" // primVars +#include "primitive.hpp" // primitive +#include "arrayView.hpp" // primitiveView #include "transport.hpp" // transport model #include "matrix.hpp" // squareMatrix @@ -34,8 +35,7 @@ using std::min; // member function to return the eddy viscosity calculated without the stress // limiter -double turbModel::EddyViscNoLim(const primVars &state) const { - // state -- primative variables +double turbModel::EddyViscosityNoLim(const primitiveView &state) const { return state.Rho() * state.Tke() / state.Omega(); } @@ -55,15 +55,14 @@ tensor turbModel::MeanStrainRate(const tensor &vGrad) const { operators on a tensor that take the trace and transpose respectively. */ tensor turbModel::BoussinesqReynoldsStress( - const primVars &state, const tensor &velGrad, + const primitiveView &state, const tensor &velGrad, const unique_ptr &trans, const double &mut) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient tensor // trans -- viscous transport model // mut -- turbulent eddy viscosity const auto lambda = trans->Lambda(mut); // 2nd eddy viscosity - tensor I; I.Identity(); return lambda * velGrad.Trace() * I + mut * (velGrad + velGrad.Transpose()) @@ -72,102 +71,53 @@ tensor turbModel::BoussinesqReynoldsStress( // Member function for calculation of tke production // P = tau_ij * velGrad_ij -double turbModel::ReynoldsStressDDotVelGrad(const primVars &state, +double turbModel::ReynoldsStressDDotVelGrad(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans, const double &mut) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // trans -- viscous transport model // mut -- turbulent eddy viscosity - const auto tau = this->BoussinesqReynoldsStress(state, velGrad, trans, mut); return tau.DoubleDotTrans(velGrad); } // member function for destruction of tke // Dk = rho * k * w -double turbModel::TkeDestruction(const primVars &state, +double turbModel::TkeDestruction(const primitiveView &state, const double &phi) const { - // state -- primative variables + // state -- primitive variables return state.Rho() * state.Tke() * state.Omega() * phi; } // member function for destruction of omega // Dw = rho * w * w -double turbModel::OmegaDestruction(const primVars &state) const { - // state -- primative variables +double turbModel::OmegaDestruction(const primitiveView &state) const { + // state -- primitive variables return state.Rho() * state.Omega() * state.Omega(); } // member function for cross diffusion term without coefficient // CD = rho / w * kGrad (dot) wGrad // In the above equation kGrad and wGrad are the tke and omega gradients. -double turbModel::CrossDiffusion(const primVars &state, +double turbModel::CrossDiffusion(const primitiveView &state, const vector3d &kGrad, const vector3d &wGrad) const { - // state -- primative variables + // state -- primitive variables // kGrad -- tke gradient // wGrad -- omega gradient return state.Rho() / state.Omega() * kGrad.DotProd(wGrad); } -// member function to calculate the spectral radius of the turbulence equations -double turbModel::CellSpectralRadius( - const primVars &state, const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR, const double &mu, - const unique_ptr &trans, const double &vol, const double &mut, - const double &f1, const bool &addSrc) const { - // state -- primative variables - // fAreaL -- area at left face - // fAreaR -- area at right face - // mu -- laminar viscosity - // trans -- viscous transport model - // vol -- cell volume - // mut -- turbulent viscosity - // f1 -- first blending coefficient - // addSrc -- flag to determine if source jacobian spectral radius should be - // included - - auto specRad = this->InviscidCellSpecRad(state, fAreaL, fAreaR); - // factor of 2 because viscous spectral radius is not halved (Blazek 6.53) - specRad += 2.0 * this->ViscCellSpecRad(state, fAreaL, fAreaR, mu, trans, vol, - mut, f1); - if (addSrc) { - // minus sign because source terms are on RHS - specRad -= this->SrcSpecRad(state, trans, vol); - } - - return specRad; -} - -double turbModel::FaceSpectralRadius( - const primVars &state, const unitVec3dMag &fArea, const double &mu, - const unique_ptr &trans, const double &dist, const double &mut, - const double &f1, const bool &positive) const { - // state -- primative variables - // fArea -- face area - // mu -- laminar viscosity - // trans -- viscous transport model - // dist -- distance from cell center to cell center - // mut -- turbulent viscosity - // f1 -- first blending coefficient - // positive -- flag to add or subtract inviscid dissipation - - auto specRad = this->InviscidFaceSpecRad(state, fArea, positive); - specRad += this->ViscFaceSpecRad(state, fArea, mu, trans, dist, mut, f1); - return specRad; -} - - // member function to calculate inviscid flux jacobian // v = vel (dot) area // df_dq = [v +/- |v| 0 ] // [ 0 v +/- |v|] -squareMatrix turbModel::InviscidJacobian(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const { - // state -- primative variables at face +squareMatrix turbModel::InvJac(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const { + // state -- primitive variables at face // fArea -- face area // positive -- flag to determine whether to add/subtract dissipation @@ -177,9 +127,10 @@ squareMatrix turbModel::InviscidJacobian(const primVars &state, this->InviscidDissJacobian(state, fArea)); } -squareMatrix turbModel::InviscidConvJacobian( - const primVars &state, const unitVec3dMag &fArea) const { - // state -- primative variables at face +// function to calculate convective portion of inviscid flux jacobian +squareMatrix turbModel::InviscidConvectiveJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const { + // state -- primitive variables at face // fArea -- face area const auto velNorm = state.Velocity().DotProd(fArea.UnitVector()); @@ -190,9 +141,10 @@ squareMatrix turbModel::InviscidConvJacobian( return jacobian; } -squareMatrix turbModel::InviscidDissJacobian( - const primVars &state, const unitVec3dMag &fArea) const { - // state -- primative variables at face +// function to calculate dissipative portion of inviscid flux jacobian +squareMatrix turbModel::InviscidDissipationJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const { + // state -- primitive variables at face // fArea -- face area const auto velNorm = state.Velocity().DotProd(fArea.UnitVector()); @@ -207,43 +159,41 @@ squareMatrix turbModel::InviscidDissJacobian( // member function to calculate inviscid spectral radius // df_dq = [vel (dot) area 0 // 0 vel (dot) area] -double turbModel::InviscidCellSpecRad(const primVars &state, - const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR) const { - // state -- primative variables +double turbModel::InviscidCellSpectralRadius( + const primitiveView &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR) const { + // state -- primitive variables // fAreaL -- face area for left face // fAreaR -- face area for right face - - auto normAvg = (0.5 * (fAreaL.UnitVector() + - fAreaR.UnitVector())).Normalize(); + auto normAvg = + (0.5 * (fAreaL.UnitVector() + fAreaR.UnitVector())).Normalize(); auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); return fabs(state.Velocity().DotProd(normAvg)) * fMag; } -double turbModel::InviscidFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const { - // state -- primative variables +double turbModel::InviscidFaceSpectralRadius(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const { + // state -- primitive variables // fArea -- face area // positive -- add or subtract dissipation term const auto velNorm = state.Velocity().DotProd(fArea.UnitVector()); - // returning absolute value because it is expected that spectral radius is - // positive + // returning absolute value because it is expected that spec rad is positive return positive ? 0.5 * fArea.Mag() * fabs(velNorm + fabs(velNorm)) : 0.5 * fArea.Mag() * fabs(velNorm - fabs(velNorm)); + return InviscidFaceSpectralRadius(state, fArea, positive); } // member function to calculate viscous flux jacobian for models with no // viscous contribution -squareMatrix turbModel::ViscousJacobian(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, - const double &mut, - const double &f1) const { - // state -- primative variables +squareMatrix turbModel::ViscJac(const primitiveView &state, + const unitVec3dMag &fArea, + const double &mu, + const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const { + // state -- primitive variables // fAreaL -- face area for left face // mu -- laminar viscosity // trans -- unique_ptr's law for viscosity @@ -256,20 +206,22 @@ squareMatrix turbModel::ViscousJacobian(const primVars &state, // member function to calculate turbulence source terms squareMatrix turbModel::CalcTurbSrc( - const primVars &state, const tensor &velGrad, + const primitiveView &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, const unique_ptr &trans, const double &vol, const double &turbVisc, const double &f1, const double &f2, - const double &width, double &ksrc, double &wsrc) const { - // set k and omega source terms to zero - ksrc = 0.0; - wsrc = 0.0; + const double &width, vector &turbSrc) const { + // set source terms to zero + for (auto &val : turbSrc) { + val = 0.0; + } // return source jacobian spectral radius return this->TurbSrcJac(state, 0.0, trans, vol); } -squareMatrix turbModel::TurbSrcJac(const primVars &state, const double &beta, +squareMatrix turbModel::TurbSrcJac(const primitiveView &state, + const double &beta, const unique_ptr &trans, const double &vol, const double &phi) const { @@ -284,27 +236,27 @@ void turbNone::Print() const { cout << "No Turbulence Model" << endl; } -squareMatrix turbNone::InviscidJacobian(const primVars &state, - const unitVec3dMag &fArea, - const bool &positive) const { - // state -- primative variables at face +squareMatrix turbNone::InvJac(const primitiveView &state, + const unitVec3dMag &fArea, + const bool &positive) const { + // state -- primitive variables at face // fArea -- face area // positive -- flag to determine whether to add/subtract spectral radius return squareMatrix(); } -squareMatrix turbNone::InviscidConvJacobian( - const primVars &state, const unitVec3dMag &fArea) const { - // state -- primative variables at face +squareMatrix turbNone::InviscidConvectiveJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const { + // state -- primitive variables at face // fArea -- face area return squareMatrix(); } -squareMatrix turbNone::InviscidDissJacobian( - const primVars &state, const unitVec3dMag &fArea) const { - // state -- primative variables at face +squareMatrix turbNone::InviscidDissipationJacobian( + const primitiveView &state, const unitVec3dMag &fArea) const { + // state -- primitive variables at face // fArea -- face area return squareMatrix(); @@ -315,11 +267,11 @@ squareMatrix turbNone::InviscidDissJacobian( // member function to return the eddy viscosity calculated with the stress // limiter -double turbKWWilcox::EddyVisc(const primVars &state, +double turbKWWilcox::EddyVisc(const primitive &state, const tensor &vGrad, const unique_ptr &trans, const double &f2, const double &length) const { - // state -- primative variables + // state -- primitive variables // vGrad -- velocity gradient // trans -- viscous transport model // f2 -- SST blending coefficient (not used in Wilcox K-W) @@ -332,29 +284,24 @@ double turbKWWilcox::SigmaD(const vector3d &kGrad, const vector3d &wGrad) const { // kGrad -- tke gradient // wGrad -- omega gradient - - if (kGrad.DotProd(wGrad) <= 0.0) { - return 0.0; - } else { - return sigmaD0_; - } + return kGrad.DotProd(wGrad) <= 0.0 ? 0.0 : sigmaD0_; } // member function to calculate coefficient for omega destruction -double turbKWWilcox::Beta(const primVars &state, +double turbKWWilcox::Beta(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // trans -- viscous transport model return beta0_ * this->FBeta(state, velGrad, trans); } // member function to calculate coefficient used in beta calculation -double turbKWWilcox::FBeta(const primVars &state, +double turbKWWilcox::FBeta(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // trans -- viscous transport model auto xw = this->Xw(state, velGrad, trans); @@ -363,13 +310,12 @@ double turbKWWilcox::FBeta(const primVars &state, // member function to calculate vortex stretching coefficient // used in fbeta calculation -double turbKWWilcox::Xw(const primVars &state, +double turbKWWilcox::Xw(const primitiveView &state, const tensor &velGrad, const unique_ptr &trans) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // trans -- viscous transport model - const auto vorticity = 0.5 * (velGrad - velGrad.Transpose()); // using DoubleDotTrans for speed @@ -390,10 +336,10 @@ tensor turbKWWilcox::StrainKI(const tensor &velGrad) const { } // member function to calculate adjusted omega used in eddy viscosity limiter -double turbKWWilcox::OmegaTilda(const primVars &state, +double turbKWWilcox::OmegaTilda(const primitive &state, const tensor &velGrad, const unique_ptr &trans) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // trans -- viscous transport model @@ -410,7 +356,7 @@ double turbKWWilcox::OmegaTilda(const primVars &state, // member function to calculate turbulence source terms and return source // jacobian -squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, +squareMatrix turbKWWilcox::CalcTurbSrc(const primitiveView &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, @@ -418,8 +364,8 @@ squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, const double &vol, const double &mut, const double &f1, const double &f2, const double &width, - double &ksrc, double &wsrc) const { - // state -- primative variables + vector &turbSrc) const { + // state -- primitive variables // velGrad -- velocity gradient // kGrad -- tke gradient // wGrad -- omega gradient @@ -427,8 +373,9 @@ squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, // vol -- cell volume // mut -- turbulent viscosity // f1 -- first blending coefficient - // ksrc -- source term for tke equation - // wsrc -- source term for omega equation + // turbSrc -- source terms + + MSG_ASSERT(turbSrc.size() == 2, "turbulence source vector is wrong size"); // calculate tke destruction const auto tkeDest = trans->InvNondimScaling() * betaStar_ * @@ -453,8 +400,8 @@ squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, this->CrossDiffusion(state, kGrad, wGrad); // assign source term values - ksrc = tkeProd - tkeDest; - wsrc = omgProd - omgDest + omgCd; + turbSrc[0] = tkeProd - tkeDest; + turbSrc[1] = omgProd - omgDest + omgCd; // return source jacobian return this->TurbSrcJac(state, beta, trans, vol); @@ -462,7 +409,7 @@ squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, // member function to calculate the eddy viscosity, and the blending // coefficients. -void turbKWWilcox::EddyViscAndBlending(const primVars &state, +void turbKWWilcox::EddyViscAndBlending(const primitive &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, @@ -472,7 +419,7 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, const double &length, double &mut, double &f1, double &f2) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // kGrad -- tke gradient // wGrad -- omega gradient @@ -501,10 +448,10 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, This is a diagonal matrix so eigenvalues are trivial. Since betaStar is always larger than beta, this eigenvalue is used */ -double turbKWWilcox::SrcSpecRad(const primVars &state, +double turbKWWilcox::SrcSpecRad(const primitiveView &state, const unique_ptr &trans, const double &vol, const double &phi) const { - // state -- primative variables + // state -- primitive variables // trans -- viscous transport model // vol -- cell volume @@ -512,12 +459,12 @@ double turbKWWilcox::SrcSpecRad(const primVars &state, return -2.0 * betaStar_ * state.Omega() * vol * trans->InvNondimScaling(); } -squareMatrix turbKWWilcox::TurbSrcJac(const primVars &state, +squareMatrix turbKWWilcox::TurbSrcJac(const primitiveView &state, const double &beta, const unique_ptr &trans, const double &vol, const double &phi) const { - // state -- primative variables + // state -- primitive variables // beta -- destruction coefficient for omega equation // trans -- viscous transport model // vol -- cell volume @@ -535,42 +482,38 @@ squareMatrix turbKWWilcox::TurbSrcJac(const primVars &state, // member function to calculate viscous flux jacobian // dfv_dq = [ (nu + sigmaStar * nut) / dist 0 ] // [ 0 (nu + sigma * nut) / dist] -squareMatrix turbKWWilcox::ViscousJacobian(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, - const double &mut, - const double &f1) const { - // state -- primative variables +squareMatrix turbKWWilcox::ViscJac(const primitiveView &state, + const unitVec3dMag &fArea, + const double &mu, + const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const { + // state -- primitive variables // fAreaL -- face area for left face // mu -- laminar viscosity // trans -- viscous transport model // dist -- distance from cell center to cell center across face // mut -- turbulent viscosity // f1 -- first blending coefficient - + auto length = fArea.Mag() / dist; squareMatrix jacobian(2); // Wilcox method uses unlimited eddy viscosity - jacobian(0, 0) = fArea.Mag() * trans->NondimScaling() / (dist * state.Rho()) * - (mu + this->SigmaK(f1) * this->EddyViscNoLim(state)); - jacobian(1, 1) = fArea.Mag() * trans->NondimScaling() / (dist * state.Rho()) * - (mu + this->SigmaW(f1) * this->EddyViscNoLim(state)); - + jacobian(0, 0) = trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * this->EddyViscosityNoLim(state)); + jacobian(1, 1) = trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaW(f1) * this->EddyViscosityNoLim(state)); return jacobian; } // member function to calculate viscous spectral radius // dfv_dq = [ (area / vol) * (nu + sigmaStar * nut) 0 // 0 (area / vol) * (nu + sigma * nut)] -double turbKWWilcox::ViscCellSpecRad(const primVars &state, - const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR, - const double &mu, - const unique_ptr &trans, - const double &vol, const double &mut, - const double &f1) const { - // state -- primative variables +double turbKWWilcox::ViscousCellSpectralRadius( + const primitiveView &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, const double &mu, + const unique_ptr &trans, const double &vol, const double &mut, + const double &f1) const { + // state -- primitive variables // fAreaL -- face area for left face // fAreaR -- face area for right face // mu -- laminar viscosity @@ -580,19 +523,17 @@ double turbKWWilcox::ViscCellSpecRad(const primVars &state, // f1 -- first blending coefficient const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); - + const auto length = fMag * fMag / vol; // Wilcox method uses unlimited eddy viscosity - return trans->NondimScaling() * fMag * fMag / (vol * state.Rho()) * - (mu + this->SigmaK(f1) * this->EddyViscNoLim(state)); + return trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * this->EddyViscosityNoLim(state)); } -double turbKWWilcox::ViscFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, const double &mut, - const double &f1) const { - // state -- primative variables +double turbKWWilcox::ViscousFaceSpectralRadius( + const primitiveView &state, const unitVec3dMag &fArea, + const double &mu, const unique_ptr &trans, const double &dist, + const double &mut, const double &f1) const { + // state -- primitive variables // fArea -- face area // mu -- laminar viscosity // trans -- viscous transport model @@ -600,12 +541,13 @@ double turbKWWilcox::ViscFaceSpecRad(const primVars &state, // mut -- turbulent viscosity // f1 -- first blending coefficient + const auto length = fArea.Mag() / dist; // Wilcox method uses unlimited eddy viscosity - return trans->NondimScaling() * fArea.Mag() / (dist * state.Rho()) * - (mu + this->SigmaK(f1) * this->EddyViscNoLim(state)); + return trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * this->EddyViscosityNoLim(state)); } -double turbKWWilcox::TurbLengthScale(const primVars &state, +double turbKWWilcox::TurbLengthScale(const primitiveView &state, const unique_ptr &trans) const { return sqrt(state.Tke()) / (betaStar_ * state.Omega()) * trans->NondimScaling(); @@ -628,10 +570,10 @@ void turbKWWilcox::Print() const { // K-Omega SST member functions // member function for eddy viscosity with limiter -double turbKWSst::EddyVisc(const primVars &state, const tensor &vGrad, +double turbKWSst::EddyVisc(const primitive &state, const tensor &vGrad, const unique_ptr &trans, const double &f2, const double &length) const { - // state -- primative variables + // state -- primitive variables // vGrad -- velocity gradient // trans -- viscous transport model // f2 -- SST blending coefficient @@ -646,13 +588,6 @@ double turbKWSst::EddyVisc(const primVars &state, const tensor &vGrad, max(a1_ * state.Omega(), trans->NondimScaling() * meanStrainRate * f2); } -// member function to calculate cross diffusion term -double turbKWSst::CDkw(const primVars &state, const vector3d &kGrad, - const vector3d &wGrad) const { - return max(2.0 * state.Rho() * sigmaW2_ / state.Omega() * - kGrad.DotProd(wGrad), 1.0e-10); -} - // member function to calculate blending function double turbKWSst::F1(const double &alpha1, const double &alpha2, const double &alpha3) const { @@ -672,12 +607,11 @@ double turbKWSst::BlendedCoeff(const double &coeff1, const double &coeff2, // coeff1 -- coefficient from set 1 // coeff2 -- coefficient from set 2 // f1 -- blending term - return f1 * coeff1 + (1.0 - f1) * coeff2; } // member function to calculate blending term -double turbKWSst::Alpha1(const primVars &state, +double turbKWSst::Alpha1(const primitive &state, const unique_ptr &trans, const double &wallDist) const { return trans->NondimScaling() * sqrt(state.Tke()) / @@ -685,7 +619,7 @@ double turbKWSst::Alpha1(const primVars &state, } // member function to calculate blending term -double turbKWSst::Alpha2(const primVars &state, +double turbKWSst::Alpha2(const primitive &state, const unique_ptr &trans, const double &mu, const double &wallDist) const { return trans->NondimScaling() * trans->NondimScaling() * 500.0 * mu / @@ -693,20 +627,20 @@ double turbKWSst::Alpha2(const primVars &state, } // member function to calculate blending term -double turbKWSst::Alpha3(const primVars &state, const double &wallDist, +double turbKWSst::Alpha3(const primitive &state, const double &wallDist, const double &cdkw) const { return 4.0 * state.Rho() * sigmaW2_ * state.Tke() / - (cdkw * (wallDist + EPS) * (wallDist + EPS)); + (cdkw * (wallDist + EPS) * (wallDist + EPS)); } // member function to calculate turbulence source terms and source jacobian squareMatrix turbKWSst::CalcTurbSrc( - const primVars &state, const tensor &velGrad, + const primitiveView &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, const unique_ptr &trans, const double &vol, const double &mut, - const double &f1, const double &f2, const double &width, double &ksrc, - double &wsrc) const { - // state -- primative variables + const double &f1, const double &f2, const double &width, + vector &turbSrc) const { + // state -- primitive variables // velGrad -- velocity gradient // kGrad -- tke gradient // wGrad -- omega gradient @@ -714,8 +648,9 @@ squareMatrix turbKWSst::CalcTurbSrc( // vol -- cell volume // mut -- turbulent viscosity // f1 -- first blending coefficient - // ksrc -- source term for tke equation - // wsrc -- source term for omega equation + // turbSrc -- source terms + + MSG_ASSERT(turbSrc.size() == 2, "turbulence source vector is wrong size"); // calculate cross diffusion coefficient const auto cdkw = this->CDkw(state, kGrad, wGrad); @@ -748,8 +683,8 @@ squareMatrix turbKWSst::CalcTurbSrc( const auto omgCd = trans->NondimScaling() * (1.0 - f1) * cdkw; // assign source term values - ksrc = tkeProd - tkeDest; - wsrc = omgProd - omgDest + omgCd; + turbSrc[0] = tkeProd - tkeDest; + turbSrc[1] = omgProd - omgDest + omgCd; // return spectral radius of source jacobian return this->TurbSrcJac(state, beta, trans, vol); @@ -757,7 +692,7 @@ squareMatrix turbKWSst::CalcTurbSrc( // member function to calculate the eddy viscosity, and the blending // coefficients. -void turbKWSst::EddyViscAndBlending(const primVars &state, +void turbKWSst::EddyViscAndBlending(const primitive &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, @@ -767,7 +702,7 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, const double &length, double &mut, double &f1, double &f2) const { - // state -- primative variables + // state -- primitive variables // velGrad -- velocity gradient // kGrad -- tke gradient // wGrad -- omega gradient @@ -801,22 +736,22 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, This is a diagonal matrix so eigenvalues are trivial. Since betaStar is always larger than beta, this eigenvalue is used */ -double turbKWSst::SrcSpecRad(const primVars &state, +double turbKWSst::SrcSpecRad(const primitiveView &state, const unique_ptr &trans, const double &vol, const double &phi) const { - // state -- primative variables + // state -- primitive variables // trans -- unique_ptr's law for viscosity // return spectral radius scaled for nondimensional equations return -2.0 * betaStar_ * state.Omega() * vol * trans->InvNondimScaling(); } -squareMatrix turbKWSst::TurbSrcJac(const primVars &state, +squareMatrix turbKWSst::TurbSrcJac(const primitiveView &state, const double &beta, const unique_ptr &trans, const double &vol, const double &phi) const { - // state -- primative variables + // state -- primitive variables // beta -- destruction coefficient for omega equation // trans -- viscous transport model // vol -- cell volume @@ -834,40 +769,37 @@ squareMatrix turbKWSst::TurbSrcJac(const primVars &state, // member function to calculate viscous flux jacobian // dfv_dq = [ (nu + sigmaStar * nut) / dist 0 ] // [ 0 (nu + sigma * nut) / dist] -squareMatrix turbKWSst::ViscousJacobian(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, const double &mut, - const double &f1) const { - // state -- primative variables +squareMatrix turbKWSst::ViscJac(const primitiveView &state, + const unitVec3dMag &fArea, + const double &mu, + const unique_ptr &trans, + const double &dist, const double &mut, + const double &f1) const { + // state -- primitive variables // fArea -- face area // mu -- laminar viscosity // trans -- viscous transport model // dist -- distance from cell center to cell center across face // mut -- turbulent viscosity // f1 -- first blending coefficient - + auto length = fArea.Mag() / dist; squareMatrix jacobian(2); - jacobian(0, 0) = fArea.Mag() * trans->NondimScaling() / (dist * state.Rho()) * - (mu + this->SigmaK(f1) * mut); - jacobian(1, 1) = fArea.Mag() * trans->NondimScaling() / (dist * state.Rho()) * - (mu + this->SigmaW(f1) * mut); - + jacobian(0, 0) = trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * mut); + jacobian(1, 1) = trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaW(f1) * mut); return jacobian; } // member function to calculate viscous spectral radius // dfv_dq = [ (area / vol) * (nu + sigmaStar * nut) 0 // 0 (area / vol) * (nu + sigma * nut)] -double turbKWSst::ViscCellSpecRad(const primVars &state, - const unitVec3dMag &fAreaL, - const unitVec3dMag &fAreaR, - const double &mu, - const unique_ptr &trans, - const double &vol, const double &mut, - const double &f1) const { - // state -- primative variables +double turbKWSst::ViscousCellSpectralRadius( + const primitiveView &state, const unitVec3dMag &fAreaL, + const unitVec3dMag &fAreaR, const double &mu, + const unique_ptr &trans, const double &vol, const double &mut, + const double &f1) const { + // state -- primitive variables // fAreaL -- face area for left face // fAreaR -- face area for right face // mu -- laminar viscosity @@ -877,30 +809,28 @@ double turbKWSst::ViscCellSpecRad(const primVars &state, // f1 -- first blending coefficient const auto fMag = 0.5 * (fAreaL.Mag() + fAreaR.Mag()); - - return trans->NondimScaling() * fMag * fMag / (vol * state.Rho()) * - (mu + this->SigmaK(f1) * mut); + const auto length = fMag * fMag / vol; + return trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * mut); } -double turbKWSst::ViscFaceSpecRad(const primVars &state, - const unitVec3dMag &fArea, - const double &mu, - const unique_ptr &trans, - const double &dist, const double &mut, - const double &f1) const { - // state -- primative variables +double turbKWSst::ViscousFaceSpectralRadius( + const primitiveView &state, const unitVec3dMag &fArea, + const double &mu, const unique_ptr &trans, const double &dist, + const double &mut, const double &f1) const { + // state -- primitive variables // fArea -- face area // mu -- laminar viscosity // trans -- viscous transport model // dist -- distance from cell center to cell center // mut -- turbulent viscosity // f1 -- first blending coefficient - - return trans->NondimScaling() * fArea.Mag() / (dist * state.Rho()) * - (mu + this->SigmaK(f1) * mut); + const auto length = fArea.Mag() / dist; + return trans->NondimScaling() * length / state.Rho() * + (mu + this->SigmaK(f1) * mut); } -double turbKWSst::TurbLengthScale(const primVars &state, +double turbKWSst::TurbLengthScale(const primitiveView &state, const unique_ptr &trans) const { return sqrt(state.Tke()) / (betaStar_ * state.Omega()) * trans->NondimScaling(); @@ -925,21 +855,21 @@ void turbKWSst::Print() const { cout << "Gamma2: " << gamma2_ << endl; } -double turbSstDes::Phi(const primVars &state, const double &cdes, +double turbSstDes::Phi(const primitiveView &state, const double &cdes, const double &width, const double &f2, const unique_ptr &trans) const { - return std::max((1.0 - f2) * this->TurbLengthScale(state, trans) / - (cdes * width), 1.0); + return std::max( + (1.0 - f2) * this->TurbLengthScale(state, trans) / (cdes * width), 1.0); } // member function to calculate turbulence source terms and source jacobian squareMatrix turbSstDes::CalcTurbSrc( - const primVars &state, const tensor &velGrad, + const primitiveView &state, const tensor &velGrad, const vector3d &kGrad, const vector3d &wGrad, const unique_ptr &trans, const double &vol, const double &mut, - const double &f1, const double &f2, const double &width, double &ksrc, - double &wsrc) const { - // state -- primative variables + const double &f1, const double &f2, const double &width, + vector &turbSrc) const { + // state -- primitive variables // velGrad -- velocity gradient // kGrad -- tke gradient // wGrad -- omega gradient @@ -947,8 +877,9 @@ squareMatrix turbSstDes::CalcTurbSrc( // vol -- cell volume // mut -- turbulent viscosity // f1 -- first blending coefficient - // ksrc -- source term for tke equation - // wsrc -- source term for omega equation + // turbSrc -- source terms + + MSG_ASSERT(turbSrc.size() == 2, "turbulence source vector is wrong size"); // calculate cross diffusion coefficient const auto cdkw = this->CDkw(state, kGrad, wGrad); @@ -983,18 +914,18 @@ squareMatrix turbSstDes::CalcTurbSrc( const auto omgCd = trans->NondimScaling() * (1.0 - f1) * cdkw; // assign source term values - ksrc = tkeProd - tkeDest; - wsrc = omgProd - omgDest + omgCd; + turbSrc[0] = tkeProd - tkeDest; + turbSrc[1] = omgProd - omgDest + omgCd; // return spectral radius of source jacobian return this->TurbSrcJac(state, beta, trans, vol, phi); } -double turbSstDes::SrcSpecRad(const primVars &state, +double turbSstDes::SrcSpecRad(const primitiveView &state, const unique_ptr &trans, const double &vol, const double &phi) const { - // state -- primative variables + // state -- primitive variables // trans -- viscous transport model // return spectral radius scaled for nondimensional equations @@ -1033,10 +964,10 @@ void turbWale::Print() const { } // member function to determine eddy viscosity -double turbWale::EddyVisc(const primVars &state, const tensor &vGrad, +double turbWale::EddyVisc(const primitive &state, const tensor &vGrad, const unique_ptr &trans, const double &f2, const double &length) const { - // state -- primative variables + // state -- primitive variables // vGrad -- velocity gradient // trans -- viscous transport model // f2 -- SST blending coefficient (not used in WALE) diff --git a/src/uncoupledScalar.cpp b/src/uncoupledScalar.cpp index d18a76e..637d2a5 100644 --- a/src/uncoupledScalar.cpp +++ b/src/uncoupledScalar.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,27 +15,11 @@ along with this program. If not, see . */ #include "uncoupledScalar.hpp" -#include "genArray.hpp" // genArray using std::cout; using std::endl; using std::cerr; -// member functions -// member function to multiply the scalars with a genArray -genArray uncoupledScalar::ArrayMult(genArray arr) const { - arr[0] *= flowVar_; - arr[1] *= flowVar_; - arr[2] *= flowVar_; - arr[3] *= flowVar_; - arr[4] *= flowVar_; - - arr[5] *= turbVar_; - arr[6] *= turbVar_; - - return arr; -} - // non-member functions // ---------------------------------------------------------------------------- // operator overload for << - allows use of cout, cerr, etc. diff --git a/src/utility.cpp b/src/utility.cpp index fbca9d0..8938fb7 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,16 +23,16 @@ #include "utility.hpp" #include "procBlock.hpp" #include "eos.hpp" // equation of state -#include "transport.hpp" // transport model -#include "thermodynamic.hpp" // thermodynamic model +#include "physicsModels.hpp" // physics models #include "input.hpp" // inputVars -#include "genArray.hpp" +#include "varArray.hpp" #include "turbulence.hpp" #include "slices.hpp" -#include "fluxJacobian.hpp" +#include "matMultiArray3d.hpp" #include "kdtree.hpp" #include "resid.hpp" -#include "primVars.hpp" +#include "primitive.hpp" +#include "macros.hpp" using std::cout; using std::endl; @@ -261,24 +261,17 @@ calculation. This function operates on the entire grid and uses connection boundaries to pass the correct data between grid blocks. */ void GetBoundaryConditions(vector &states, const input &inp, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - vector &connections, const int &rank, - const MPI_Datatype &MPI_cellData) { + const physics &phys, vector &connections, + const int &rank) { // states -- vector of all procBlocks in the solution domain // inp -- all input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model + // phys -- physics models // connections -- vector of connection boundary types // rank -- processor rank - // MPI_cellData -- data type to pass primVars, genArray // loop over all blocks and assign inviscid ghost cells for (auto &state : states) { - state.AssignInviscidGhostCells(inp, eqnState, thermo, trans, turb); + state.AssignInviscidGhostCells(inp, phys); } // loop over connections and swap ghost cells where needed @@ -289,10 +282,10 @@ void GetBoundaryConditions(vector &states, const input &inp, conn, states[conn.LocalBlockSecond()]); } else if (conn.RankFirst() == rank) { // rank matches rank of first side of connection, swap over mpi - states[conn.LocalBlockFirst()].SwapStateSliceMPI(conn, rank, MPI_cellData); + states[conn.LocalBlockFirst()].SwapStateSliceMPI(conn, rank); } else if (conn.RankSecond() == rank) { // rank matches rank of second side of connection, swap over mpi - states[conn.LocalBlockSecond()].SwapStateSliceMPI(conn, rank, MPI_cellData); + states[conn.LocalBlockSecond()].SwapStateSliceMPI(conn, rank); } // if rank doesn't match either side of connection, then do nothing and // move on to the next connection @@ -300,7 +293,7 @@ void GetBoundaryConditions(vector &states, const input &inp, // loop over all blocks and get ghost cell edge data for (auto &state : states) { - state.AssignInviscidGhostCellsEdge(inp, eqnState, thermo, trans, turb); + state.AssignInviscidGhostCellsEdge(inp, phys); } } @@ -374,11 +367,9 @@ void CalcWallDistance(vector &localBlocks, const kdtree &tree) { } } -void AssignSolToTimeN(vector &blocks, - const unique_ptr &eqnState, - const unique_ptr &thermo) { +void AssignSolToTimeN(vector &blocks, const physics &phys) { for (auto &block : blocks) { - block.AssignSolToTimeN(eqnState, thermo); + block.AssignSolToTimeN(phys); } } @@ -389,36 +380,25 @@ void AssignSolToTimeNm1(vector &blocks) { } void ExplicitUpdate(vector &blocks, const input &inp, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, const int &mm, - genArray &residL2, resid &residLinf) { + const physics &phys, const int &mm, residual &residL2, + resid &residLinf) { // create dummy update (not used in explicit update) - multiArray3d du(1, 1, 1, 0); + blkMultiArray3d du; // loop over all blocks and update for (auto &block : blocks) { - block.UpdateBlock(inp, eqnState, thermo, trans, du, turb, mm, residL2, - residLinf); + block.UpdateBlock(inp, phys, du, mm, residL2, residLinf); } } double ImplicitUpdate(vector &blocks, - vector> &mainDiagonal, - const input &inp, const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, const int &mm, - genArray &residL2, resid &residLinf, - const vector &connections, const int &rank, - const MPI_Datatype &MPI_cellData) { + vector &mainDiagonal, const input &inp, + const physics &phys, const int &mm, residual &residL2, + resid &residLinf, const vector &connections, + const int &rank) { // blocks -- vector of procBlocks on current processor // mainDiagonal -- main diagonal of A matrix for all blocks on processor // inp -- input variables - // eqnState -- equation of state - // thermo -- thermodynamic model - // trans -- viscous transport model - // turb -- turbulence model + // phys -- physics models // mm -- nonlinear iteration // residL2 -- L2 residual // residLinf -- L infinity residual @@ -434,10 +414,9 @@ double ImplicitUpdate(vector &blocks, } // initialize matrix update - vector> du(blocks.size()); + vector> du(blocks.size()); for (auto bb = 0U; bb < blocks.size(); bb++) { - du[bb] = blocks[bb].InitializeMatrixUpdate(inp, eqnState, thermo, - mainDiagonal[bb]); + du[bb] = blocks[bb].InitializeMatrixUpdate(inp, phys, mainDiagonal[bb]); } // Solve Ax=b with supported solver @@ -452,33 +431,31 @@ double ImplicitUpdate(vector &blocks, // start sweeps through domain for (auto ii = 0; ii < inp.MatrixSweeps(); ii++) { // swap updates for ghost cells - SwapImplicitUpdate(du, connections, rank, MPI_cellData, numG); + SwapImplicitUpdate(du, connections, rank, numG); // forward lu-sgs sweep for (auto bb = 0U; bb < blocks.size(); bb++) { - blocks[bb].LUSGS_Forward(reorder[bb], du[bb], eqnState, inp, thermo, - trans, turb, mainDiagonal[bb], ii); + blocks[bb].LUSGS_Forward(reorder[bb], du[bb], phys, inp, + mainDiagonal[bb], ii); } // swap updates for ghost cells - SwapImplicitUpdate(du, connections, rank, MPI_cellData, numG); + SwapImplicitUpdate(du, connections, rank, numG); // backward lu-sgs sweep for (auto bb = 0U; bb < blocks.size(); bb++) { - matrixError += blocks[bb].LUSGS_Backward(reorder[bb], du[bb], eqnState, - inp, thermo, trans, turb, + matrixError += blocks[bb].LUSGS_Backward(reorder[bb], du[bb], phys, inp, mainDiagonal[bb], ii); } } } else if (inp.MatrixSolver() == "dplur" || inp.MatrixSolver() == "bdplur") { for (auto ii = 0; ii < inp.MatrixSweeps(); ii++) { // swap updates for ghost cells - SwapImplicitUpdate(du, connections, rank, MPI_cellData, numG); + SwapImplicitUpdate(du, connections, rank, numG); for (auto bb = 0U; bb < blocks.size(); bb++) { // Calculate correction (du) - matrixError += blocks[bb].DPLUR(du[bb], eqnState, inp, thermo, trans, - turb, mainDiagonal[bb]); + matrixError += blocks[bb].DPLUR(du[bb], phys, inp, mainDiagonal[bb]); } } } else { @@ -491,8 +468,7 @@ double ImplicitUpdate(vector &blocks, // Update blocks and reset main diagonal for (auto bb = 0U; bb < blocks.size(); bb++) { // Update solution - blocks[bb].UpdateBlock(inp, eqnState, thermo, trans, du[bb], turb, mm, - residL2, residLinf); + blocks[bb].UpdateBlock(inp, phys, du[bb], mm, residL2, residLinf); // Assign time n to time n-1 at end of nonlinear iterations if (inp.IsMultilevelInTime() && mm == inp.NonlinearIterations() - 1) { @@ -506,14 +482,12 @@ double ImplicitUpdate(vector &blocks, return matrixError; } -void SwapImplicitUpdate(vector> &du, +void SwapImplicitUpdate(vector> &du, const vector &connections, const int &rank, - const MPI_Datatype &MPI_cellData, const int &numGhosts) { // du -- implicit update in conservative variables // conn -- connection boundary conditions // rank -- processor rank - // MPI_cellData -- datatype to pass primVars or genArray // numGhosts -- number of ghost cells // loop over all connections and swap connection updates when necessary @@ -523,10 +497,10 @@ void SwapImplicitUpdate(vector> &du, du[conn.LocalBlockFirst()].SwapSlice(conn, du[conn.LocalBlockSecond()]); } else if (conn.RankFirst() == rank) { // rank matches rank of first side of connection, swap over mpi - du[conn.LocalBlockFirst()].SwapSliceMPI(conn, rank, MPI_cellData); + du[conn.LocalBlockFirst()].SwapSliceMPI(conn, rank, MPI_DOUBLE); } else if (conn.RankSecond() == rank) { // rank matches rank of second side of connection, swap over mpi - du[conn.LocalBlockSecond()].SwapSliceMPI(conn, rank, MPI_cellData); + du[conn.LocalBlockSecond()].SwapSliceMPI(conn, rank, MPI_DOUBLE); } // if rank doesn't match either side of connection, then do nothing and // move on to the next connection @@ -620,21 +594,14 @@ void SwapWallDist(vector &states, } void CalcResidual(vector &states, - vector> &mainDiagonal, - const unique_ptr &trans, - const unique_ptr &thermo, - const unique_ptr &eqnState, const input &inp, - const unique_ptr &turb, - const vector &connections, const int &rank, - const MPI_Datatype &MPI_tensorDouble, + vector &mainDiagonal, const physics &phys, + const input &inp, const vector &connections, + const int &rank, const MPI_Datatype &MPI_tensorDouble, const MPI_Datatype &MPI_vec3d) { // states -- vector of all procBlocks on processor // mainDiagonal -- main diagonal of A matrix for implicit solve - // trans -- viscous transport model - // thermo -- thermodynamic model - // eqnState -- equation of state + // phys -- physics models // inp -- input variables - // turb -- turbulence model // connections -- connection boundary conditions // rank -- processor rank // MPI_tensorDouble -- MPI datatype for tensor @@ -642,8 +609,7 @@ void CalcResidual(vector &states, for (auto bb = 0U; bb < states.size(); bb++) { // calculate residual - states[bb].CalcResidualNoSource(trans, thermo, eqnState, inp, turb, - mainDiagonal[bb]); + states[bb].CalcResidualNoSource(phys, inp, mainDiagonal[bb]); } // swap mut & gradients calculated during residual calculation SwapEddyViscAndGradients(states, connections, rank, MPI_tensorDouble, @@ -655,7 +621,7 @@ void CalcResidual(vector &states, for (auto bb = 0U; bb < states.size(); bb++) { // calculate source terms for residual - states[bb].CalcSrcTerms(trans, turb, inp, mainDiagonal[bb]); + states[bb].CalcSrcTerms(phys, inp, mainDiagonal[bb]); } } } @@ -690,7 +656,7 @@ vector> HyperplaneReorder(const int &imax, const int &jmax, for (auto ii = 0; ii < imax; ii++) { if (ii + jj + kk == pp) { // if sum of ii, jj, and kk equals pp than // point is on hyperplane pp - reorder.push_back(vector3d(ii, jj, kk)); + reorder.emplace_back(ii, jj, kk); } } } @@ -701,14 +667,14 @@ vector> HyperplaneReorder(const int &imax, const int &jmax, } void ResizeArrays(const vector &states, const input &inp, - vector> &jac) { + vector &jac) { // states -- all states on processor // sol -- vector of solutions to be resized // jac -- vector of flux jacobians to be resized const auto fluxJac = inp.IsBlockMatrix() ? fluxJacobian(inp.NumFlowEquations(), inp.NumTurbEquations()) : - fluxJacobian(1, 1); + fluxJacobian(1, std::min(1, inp.NumTurbEquations())); for (auto bb = 0U; bb < states.size(); bb++) { jac[bb].ClearResize(states[bb].NumI(), states[bb].NumJ(), states[bb].NumK(), @@ -775,63 +741,13 @@ vector LagrangeCoeff(const vector &cellWidth, return coeffs; } -template -double StencilWidth(const T &cellWidth, const int &start, const int &end) { - auto width = 0.0; - if (end > start) { - width = std::accumulate(std::begin(cellWidth) + start, - std::begin(cellWidth) + end, 0.0); - } else if (start > end) { // width is negative - width = -1.0 * std::accumulate(std::begin(cellWidth) + end, - std::begin(cellWidth) + start, 0.0); - } - return width; -} - -primVars BetaIntegral(const primVars &deriv1, const primVars &deriv2, - const double &dx, const double &x) { - return (deriv1.Squared() * x + deriv1 * deriv2 * x * x + - deriv2.Squared() * pow(x, 3.0) / 3.0) * dx + - deriv2.Squared() * x * pow(dx, 3.0); -} - -primVars BetaIntegral(const primVars &deriv1, const primVars &deriv2, - const double &dx, const double &xl, const double &xh) { - return BetaIntegral(deriv1, deriv2, dx, xh) - - BetaIntegral(deriv1, deriv2, dx, xl); -} - -primVars Beta0(const double &x_0, const double &x_1, const double &x_2, - const primVars &y_0, const primVars &y_1, const primVars &y_2) { - const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); - const auto deriv1st = (y_2 - y_1) / (0.5 * (x_2 + x_1)) + 0.5 * x_2 * deriv2nd; - - return BetaIntegral(deriv1st, deriv2nd, x_2, -0.5 * x_2, 0.5 * x_2); -} - -primVars Beta1(const double &x_0, const double &x_1, const double &x_2, - const primVars &y_0, const primVars &y_1, const primVars &y_2) { - const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); - const auto deriv1st = (y_2 - y_1) / (0.5 * (x_2 + x_1)) - 0.5 * x_1 * deriv2nd; - - return BetaIntegral(deriv1st, deriv2nd, x_1, -0.5 * x_1, 0.5 * x_1); -} - -primVars Beta2(const double &x_0, const double &x_1, const double &x_2, - const primVars &y_0, const primVars &y_1, const primVars &y_2) { - const auto deriv2nd = Derivative2nd(x_0, x_1, x_2, y_0, y_1, y_2); - const auto deriv1st = (y_1 - y_0) / (0.5 * (x_1 + x_0)) - 0.5 * x_0 * deriv2nd; - - return BetaIntegral(deriv1st, deriv2nd, x_0, -0.5 * x_0, 0.5 * x_0); -} - // function to calculate the velocity gradients at a cell face using the Thin // Shear Layer approximation -tensor CalcVelGradTSL(const primVars &left, const primVars &right, +tensor CalcVelGradTSL(const primitive &left, const primitive &right, const vector3d &normArea, const double &dist) { - // left -- left state (primative) - // right -- right state (primative) + // left -- left state (primitive) + // right -- right state (primitive) // normArea -- unit area vector of face // dist -- distance between centroid of left cell and right cell @@ -863,11 +779,12 @@ tensor CalcVelGradTSL(const primVars &left, const primVars &right, // kdtree CalcTreeFromCloud(const string &fname, const input &inp, const unique_ptr &trans, - vector &states) { + vector &states, vector &species) { // fname -- name of file to open // inp -- input variables // trans -- transport model // states -- vector of states read from file + // species -- species present in file // open file ifstream inFile(fname, ios::in); @@ -878,8 +795,8 @@ kdtree CalcTreeFromCloud(const string &fname, const input &inp, } vector> points; - vector species; auto count = 0; + std::map speciesMap; string line = ""; while (getline(inFile, line)) { // remove leading and trailing whitespace and ignore comments @@ -891,14 +808,14 @@ kdtree CalcTreeFromCloud(const string &fname, const input &inp, if (count == 0) { // first line has number of points auto numPts = std::stoi(tokens[0]); points.resize(numPts); - states.resize(numPts); + states.resize(numPts, {inp.NumEquations(), inp.NumSpecies()}); } else if (count == 1) { // second line has species species = tokens; - if (species.size() != 1) { - cerr << "ERROR in CalcTreeFromCloud(), only single species currently " - "supported" - << endl; - exit(EXIT_FAILURE); + // check that species are defined + inp.CheckSpecies(species); + // create map from species order in file to order in simulation + for (auto ii = 0U; ii < species.size(); ++ii) { + speciesMap.insert(std::make_pair(ii, inp.SpeciesIndex(species[ii]))); } } else if (tokens.size() != 10 + species.size()) { cerr << "ERROR in CalcTreeFromCloud(). Expecting " @@ -921,10 +838,21 @@ kdtree CalcTreeFromCloud(const string &fname, const input &inp, auto omega = std::stod(tokens[9]) * trans->MuRef() / (inp.RRef() * inp.ARef() * inp.ARef()); vector massFractions(species.size(), 0.0); - for (auto ii = 0; ii < massFractions.size(); ++ii) { + for (auto ii = 0U; ii < massFractions.size(); ++ii) { massFractions[ii] = std::stod(tokens[ii + 10]); } - primVars state(rho, uVel, vVel, wVel, pressure, tke, omega); + primitive state(inp.NumEquations(), species.size()); + for (auto ii = 0U; ii < massFractions.size(); ++ii) { + state[speciesMap[ii]] = rho * massFractions[ii]; + } + state[state.MomentumXIndex()] = uVel; + state[state.MomentumYIndex()] = vVel; + state[state.MomentumZIndex()] = wVel; + state[state.EnergyIndex()] = pressure; + if (state.HasTurbulenceData()) { + state[state.TurbulenceIndex()] = tke; + state[state.TurbulenceIndex() + 1] = omega; + } states[count - 2] = state; } } @@ -933,4 +861,23 @@ kdtree CalcTreeFromCloud(const string &fname, const input &inp, // create kd tree return kdtree(points); +} + +void AssertWithMessage(const char *exprStr, bool expr, const char *file, + int line, const char *msg) { + if (!expr) { + cerr << "Assert failed: " << msg << endl; + cerr << "Condition: " << exprStr << endl; + cerr << "At: " << file << ":" << line << endl; + exit(EXIT_FAILURE); + } +} + +string GetEnvironmentVariable(const string &var) { + auto val = getenv(var.c_str()); + return val == NULL ? "" : string(val); +} + +double Kronecker(const int &ii, const int &jj) { + return (ii == jj) ? 1.0 : 0.0; } \ No newline at end of file diff --git a/src/varArray.cpp b/src/varArray.cpp new file mode 100644 index 0000000..b65a22b --- /dev/null +++ b/src/varArray.cpp @@ -0,0 +1,53 @@ +/* This file is part of aither. + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) + + Aither is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Aither is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include // exit() +#include // cout +#include +#include "varArray.hpp" +#include "mpi.h" +#include "arrayView.hpp" + +using std::cout; +using std::endl; +using std::cerr; + +// ------------------------------------------------------------------ +// functions for varArray class +varArray varArray::Squared() const { + auto sq = (*this); + return sq *= sq; +} + +arrayView varArray::GetView() const { + return {this->begin(), this->end(), this->NumSpecies()}; +} + +// member function to sum the residuals from all processors +void residual::GlobalReduceMPI(const int &rank) { + // Get residuals from all processors + if (rank == ROOTP) { + MPI_Reduce(MPI_IN_PLACE, &(*this)[0], this->Size(), MPI_DOUBLE, MPI_SUM, + ROOTP, MPI_COMM_WORLD); + } else { + MPI_Reduce(&(*this)[0], &(*this)[0], this->Size(), MPI_DOUBLE, MPI_SUM, ROOTP, + MPI_COMM_WORLD); + } +} + +arrayView residual::GetView() const { + return {this->begin(), this->end(), this->NumSpecies()}; +} \ No newline at end of file diff --git a/src/viscousFlux.cpp b/src/viscousFlux.cpp index 29d66a2..18a92b3 100644 --- a/src/viscousFlux.cpp +++ b/src/viscousFlux.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,11 +18,8 @@ #include #include #include "viscousFlux.hpp" -#include "eos.hpp" // equation of state -#include "transport.hpp" // transport model -#include "thermodynamic.hpp" // thermodynamic model -#include "primVars.hpp" // primVars -#include "turbulence.hpp" // turbModel +#include "physicsModels.hpp" +#include "primitive.hpp" // primitive #include "matrix.hpp" // squareMatrix #include "utility.hpp" // TauNormal #include "wallData.hpp" // wallVars @@ -36,7 +33,9 @@ using std::unique_ptr; // constructor -- initialize flux from velocity gradient /* Viscous flux normal to face: -F = [ 0, +F = [ D_0 mixGrad_0 (dot) area, + ... + D_n mixGrad_n (dot) area, taux, tauy, tauz, @@ -56,121 +55,157 @@ In the above equation lambda is the bulk viscosity, velGradTrace is the trace of the velocity gradient, area is the normalized face area, mu is the dynamic viscosity, and velGrad is the velocity gradient tensor. */ -void viscousFlux::CalcFlux( - const tensor &velGrad, const unique_ptr &trans, - const unique_ptr &thermo, const unique_ptr &eqnState, - const vector3d &tGrad, const vector3d &normArea, - const vector3d &tkeGrad, const vector3d &omegaGrad, - const unique_ptr &turb, const primVars &state, - const double &lamVisc, const double &turbVisc, const double &f1) { +void viscousFlux::CalcFlux(const tensor &velGrad, const physics &phys, + const vector3d &tGrad, + const vector3d &normArea, + const vector3d &tkeGrad, + const vector3d &omegaGrad, + const vector> &mixGrad, + const primitive &state, const double &lamVisc, + const double &turbVisc, const double &f1) { // velGrad -- velocity gradient tensor - // trans -- viscous transport model - // thermo -- thermodynamic model - // eqnState -- equation of state + // phys -- physics models // tGrad -- temperature gradient // normArea -- unit area vector of face // tkeGrad -- tke gradient // omegaGrad -- omega gradient - // turb -- turbulence model - // state -- primative variables at face + // state -- primitive variables at face // lamVisc -- laminar viscosity // turbVisc -- turbulent viscosity // f1 -- first blending coefficient // get viscosity with nondimensional normalization - const auto mu = trans->NondimScaling() * lamVisc; - const auto mut = trans->NondimScaling() * turbVisc; + const auto mu = phys.Transport()->NondimScaling() * lamVisc; + const auto mut = phys.Transport()->NondimScaling() * turbVisc; + + auto speciesEnthalpyTerm = 0.0; + const auto isMultiSpecies = state.NumSpecies() > 1; + if (isMultiSpecies) { + auto posDiff = 0.0; + auto negDiff = 0.0; + for (auto ss = 0; ss < state.NumSpecies(); ++ss) { + (*this)[ss] = + phys.Diffusion()->DiffCoeff(mu, mut) * mixGrad[ss].DotProd(normArea); + negDiff -= std::min((*this)[ss], 0.0); + posDiff += std::max((*this)[ss], 0.0); + } + // enforce zero mass flux + // scale diffusion flux so that positive flux equals negative flux + auto posDiffFac = (posDiff > negDiff) ? negDiff / posDiff : 1.0; + auto negDiffFac = (negDiff > posDiff) ? posDiff / negDiff : 1.0; + for (auto ss = 0; ss < state.NumSpecies(); ++ss) { + (*this)[ss] *= (*this)[ss] > 0.0 ? posDiffFac : negDiffFac; + const auto hs = state.SpeciesEnthalpy(phys, ss); + speciesEnthalpyTerm += (*this)[ss] * hs; + } + } // wall shear stress - const auto tau = TauNormal(velGrad, normArea, mu, mut, trans); - - const auto t = state.Temperature(eqnState); - - data_[0] = tau.X(); - data_[1] = tau.Y(); - data_[2] = tau.Z(); - data_[3] = tau.DotProd(state.Velocity()) + - (trans->Conductivity(mu, t, thermo) + - trans->TurbConductivity(mut, turb->TurbPrandtlNumber(), t, thermo)) * - tGrad.DotProd(normArea); + const auto tau = TauNormal(velGrad, normArea, mu, mut, phys.Transport()); + (*this)[this->MomentumXIndex()] = tau.X(); + (*this)[this->MomentumYIndex()] = tau.Y(); + (*this)[this->MomentumZIndex()] = tau.Z(); + + const auto t = state.Temperature(phys.EoS()); + const auto mf = state.MassFractions(); + const auto k = phys.Transport()->EffectiveConductivity(t, mf); + const auto kt = phys.Transport()->TurbConductivity( + mut, phys.Turbulence()->TurbPrandtlNumber(), t, phys.Thermodynamic(), mf); + (*this)[this->EnergyIndex()] = tau.DotProd(state.Velocity()) + + (k + kt) * tGrad.DotProd(normArea) + + speciesEnthalpyTerm; // turbulence viscous flux - // get molecular diffusion coefficients for turbulence equations - const auto tkeCoeff = turb->SigmaK(f1); - const auto omgCoeff = turb->SigmaW(f1); - - // some turbulence models use the unlimited eddy viscosity for the - // turbulence viscous flux instead of the limited eddy viscosity - const auto mutt = turb->UseUnlimitedEddyVisc() ? - trans->NondimScaling() * turb->EddyViscNoLim(state) : mut; - data_[4] = (mu + tkeCoeff * mutt) * tkeGrad.DotProd(normArea); - data_[5] = (mu + omgCoeff * mutt) * omegaGrad.DotProd(normArea); + if (this->HasTurbulenceData()) { + // get molecular diffusion coefficients for turbulence equations + const auto tkeCoeff = phys.Turbulence()->SigmaK(f1); + const auto omgCoeff = phys.Turbulence()->SigmaW(f1); + + // some turbulence models use the unlimited eddy viscosity for the + // turbulence viscous flux instead of the limited eddy viscosity + const auto mutt = phys.Turbulence()->UseUnlimitedEddyVisc() + ? phys.Transport()->NondimScaling() * + phys.Turbulence()->EddyViscNoLim(state) + : mut; + (*this)[this->TurbulenceIndex()] = + (mu + tkeCoeff * mutt) * tkeGrad.DotProd(normArea); + (*this)[this->TurbulenceIndex() + 1] = + (mu + omgCoeff * mutt) * omegaGrad.DotProd(normArea); + } } wallVars viscousFlux::CalcWallFlux( - const tensor &velGrad, const unique_ptr &trans, - const unique_ptr &thermo, const unique_ptr &eqnState, + const tensor &velGrad, const physics &phys, const vector3d &tGrad, const vector3d &normArea, const vector3d &tkeGrad, const vector3d &omegaGrad, - const unique_ptr &turb, const primVars &state, - const double &lamVisc, const double &turbVisc, const double &f1) { + const primitive &state, const double &lamVisc, const double &turbVisc, + const double &f1) { // velGrad -- velocity gradient tensor - // trans -- viscous transport model - // thermo -- thermodynamic model - // eqnState -- equation of state + // phys -- physics models // tGrad -- temperature gradient // normArea -- unit area vector of face // tkeGrad -- tke gradient // omegaGrad -- omega gradient - // turb -- turbulence model - // state -- primative variables at face + // state -- primitive variables at face // lamVisc -- laminar viscosity // turbVisc -- turbulent viscosity // f1 -- first blending coefficient - wallVars wVars; + // no diffusion on wall boundary, therfore no contribution to energy flux + + wallVars wVars(state.NumSpecies()); // get viscosity with nondimensional normalization - wVars.viscosity_ = trans->NondimScaling() * lamVisc; - wVars.turbEddyVisc_ = trans->NondimScaling() * turbVisc; + wVars.viscosity_ = phys.Transport()->NondimScaling() * lamVisc; + wVars.turbEddyVisc_ = phys.Transport()->NondimScaling() * turbVisc; // wall shear stress - wVars.shearStress_ = - TauNormal(velGrad, normArea, wVars.viscosity_, wVars.turbEddyVisc_, trans); + wVars.shearStress_ = TauNormal(velGrad, normArea, wVars.viscosity_, + wVars.turbEddyVisc_, phys.Transport()); + + (*this)[this->MomentumXIndex()] = wVars.shearStress_.X(); + (*this)[this->MomentumYIndex()] = wVars.shearStress_.Y(); + (*this)[this->MomentumZIndex()] = wVars.shearStress_.Z(); - const auto t = state.Temperature(eqnState); + const auto t = state.Temperature(phys.EoS()); + const auto mf = state.MassFractions(); + const auto k = phys.Transport()->EffectiveConductivity(t, mf); + const auto kt = phys.Transport()->TurbConductivity( + wVars.turbEddyVisc_, phys.Turbulence()->TurbPrandtlNumber(), t, + phys.Thermodynamic(), mf); // wall heat flux - wVars.heatFlux_ = - (trans->Conductivity(wVars.viscosity_, t, thermo) + - trans->TurbConductivity(wVars.turbEddyVisc_, turb->TurbPrandtlNumber(), - t, thermo)) * - tGrad.DotProd(normArea); + wVars.heatFlux_ = (k + kt) * tGrad.DotProd(normArea); - data_[0] = wVars.shearStress_.X(); - data_[1] = wVars.shearStress_.Y(); - data_[2] = wVars.shearStress_.Z(); - data_[3] = wVars.shearStress_.DotProd(state.Velocity()) + wVars.heatFlux_; + (*this)[this->EnergyIndex()] = + wVars.shearStress_.DotProd(state.Velocity()) + wVars.heatFlux_; // calculate other wall data wVars.density_ = state.Rho(); wVars.temperature_ = t; - wVars.tke_ = state.Tke(); - wVars.sdr_ = state.Omega(); + wVars.mf_ = mf; wVars.frictionVelocity_ = sqrt(wVars.shearStress_.Mag() / wVars.density_); // turbulence viscous flux - // get molecular diffusion coefficients for turbulence equations - const auto tkeCoeff = turb->SigmaK(f1); - const auto omgCoeff = turb->SigmaW(f1); - - // some turbulence models use the unlimited eddy viscosity for the - // turbulence viscous flux instead of the limited eddy viscosity - const auto mutt = turb->UseUnlimitedEddyVisc() - ? trans->NondimScaling() * turb->EddyViscNoLim(state) - : wVars.turbEddyVisc_; - data_[4] = (wVars.viscosity_ + tkeCoeff * mutt) * tkeGrad.DotProd(normArea); - data_[5] = (wVars.viscosity_ + omgCoeff * mutt) * omegaGrad.DotProd(normArea); + if (this->HasTurbulenceData()) { + wVars.tke_ = state.Tke(); + wVars.sdr_ = state.Omega(); + + // get molecular diffusion coefficients for turbulence equations + const auto tkeCoeff = phys.Turbulence()->SigmaK(f1); + const auto omgCoeff = phys.Turbulence()->SigmaW(f1); + + // some turbulence models use the unlimited eddy viscosity for the + // turbulence viscous flux instead of the limited eddy viscosity + const auto mutt = phys.Turbulence()->UseUnlimitedEddyVisc() + ? phys.Transport()->NondimScaling() * + phys.Turbulence()->EddyViscNoLim(state) + : wVars.turbEddyVisc_; + (*this)[this->TurbulenceIndex()] = + (wVars.viscosity_ + tkeCoeff * mutt) * tkeGrad.DotProd(normArea); + (*this)[this->TurbulenceIndex() + 1] = + (wVars.viscosity_ + omgCoeff * mutt) * omegaGrad.DotProd(normArea); + } return wVars; } @@ -189,34 +224,35 @@ void viscousFlux::CalcWallLawFlux( // omegaGrad -- omega gradient // turb -- turbulence model - data_[0] = tauWall.X(); - data_[1] = tauWall.Y(); - data_[2] = tauWall.Z(); - data_[3] = tauWall.DotProd(velWall) + qWall; + // no diffusion on wall boundary, therefore no contribution to energy flux + + (*this)[this->MomentumXIndex()] = tauWall.X(); + (*this)[this->MomentumYIndex()] = tauWall.Y(); + (*this)[this->MomentumZIndex()] = tauWall.Z(); + (*this)[this->EnergyIndex()] = tauWall.DotProd(velWall) + qWall; // turbulence viscous flux - // get molecular diffusion coefficients for turbulence equations - const auto tkeCoeff = turb->WallSigmaK(); - const auto omgCoeff = turb->WallSigmaW(); - - // some turbulence models use the unlimited eddy viscosity for the - // turbulence viscous flux instead of the limited eddy viscosity - // for wall laws, eddy viscosity is prescribed - data_[4] = (muWall + tkeCoeff * mutWall) * tkeGrad.DotProd(normArea); - data_[5] = (muWall + omgCoeff * mutWall) * omegaGrad.DotProd(normArea); + if (this->HasTurbulenceData()) { + // get molecular diffusion coefficients for turbulence equations + const auto tkeCoeff = turb->WallSigmaK(); + const auto omgCoeff = turb->WallSigmaW(); + + // some turbulence models use the unlimited eddy viscosity for the + // turbulence viscous flux instead of the limited eddy viscosity + // for wall laws, eddy viscosity is prescribed + (*this)[this->TurbulenceIndex()] = + (muWall + tkeCoeff * mutWall) * tkeGrad.DotProd(normArea); + (*this)[this->TurbulenceIndex() + 1] = + (muWall + omgCoeff * mutWall) * omegaGrad.DotProd(normArea); + } } - // non-member functions // ---------------------------------------------------------------------------- // operator overload for << - allows use of cout, cerr, etc. ostream &operator<<(ostream &os, viscousFlux &flux) { - os << "0.0" << endl; - os << flux.MomX() << endl; - os << flux.MomY() << endl; - os << flux.MomZ() << endl; - os << flux.Engy() << endl; - os << flux.MomK() << endl; - os << flux.MomO() << endl; + for (auto rr = 0; rr < flux.Size(); rr++) { + os << flux[rr] << endl; + } return os; } diff --git a/src/wallData.cpp b/src/wallData.cpp index 77f977d..2a187d9 100644 --- a/src/wallData.cpp +++ b/src/wallData.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +18,91 @@ #include "vector3d.hpp" #include "input.hpp" #include "eos.hpp" -#include "primVars.hpp" +#include "primitive.hpp" + +// wallVars functions +void wallVars::Pack(char *(&sendBuffer), const int &sendBufSize, int &position, + const MPI_Datatype &MPI_vec3d) const { + // sendBuffer -- buffer to pack data into + // sendBufSize -- size of buffer + // position -- location within buffer + // MPI_vec3d -- datatype for vector3d + + // pack wall shear stress + MPI_Pack(&shearStress_, 1, MPI_vec3d, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + // pack wall scalars + MPI_Pack(&heatFlux_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&yplus_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&temperature_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&turbEddyVisc_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&viscosity_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&density_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&frictionVelocity_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, + &position, MPI_COMM_WORLD); + MPI_Pack(&tke_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&sdr_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(mf_)), mf_.size(), MPI_DOUBLE, sendBuffer, sendBufSize, + &position, MPI_COMM_WORLD); +} + +void wallVars::PackSize(int &sendBufSize, const MPI_Datatype &MPI_vec3d) const { + auto tempSize = 0; + // add size for shear stress + MPI_Pack_size(1, MPI_vec3d, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; + // 9 because 9 scalar varialbes + MPI_Pack_size(9, MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; + // add size for mf + MPI_Pack_size(mf_.size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; +} + +void wallVars::Unpack(char *(&recvBuffer), const int &recvBufSize, + int &position, const MPI_Datatype &MPI_vec3d, + const int &numSpecies) { + // recvBuffer -- buffer to unpack data from + // recvBufSize -- size of buffer + // position -- location within buffer + + // unpack shear stress + MPI_Unpack(recvBuffer, recvBufSize, &position, &shearStress_, 1, MPI_vec3d, + MPI_COMM_WORLD); + // unpack wall scalars + MPI_Unpack(recvBuffer, recvBufSize, &position, &heatFlux_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &yplus_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &temperature_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &turbEddyVisc_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &viscosity_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &density_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &frictionVelocity_, 1, + MPI_DOUBLE, MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &tke_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &sdr_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + // unpack mass fractions + mf_.clear(); + mf_.resize(numSpecies); + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(mf_)), + numSpecies, MPI_DOUBLE, MPI_COMM_WORLD); +} + // member functions vector3d wallData::WallShearStress(const int &ii, const int &jj, @@ -55,7 +139,7 @@ double wallData::WallEddyViscosity(const int &ii, const int &jj, double wallData::WallPressure(const int &ii, const int &jj, const int &kk, const unique_ptr &eqnState) const { - return eqnState->PressureRT(this->WallDensity(ii, jj, kk), + return eqnState->PressureRT(this->WallDensityVec(ii, jj, kk), this->WallTemperature(ii, jj, kk)); } @@ -69,6 +153,20 @@ double wallData::WallDensity(const int &ii, const int &jj, return (*this)(ii, jj, kk).density_; } +vector wallData::WallMassFractions(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).mf_; +} + +vector wallData::WallDensityVec(const int &ii, const int &jj, + const int &kk) const { + const auto rho = this->WallDensity(ii, jj, kk); + auto rhoVec = this->WallMassFractions(ii, jj, kk); + std::for_each(rhoVec.begin(), rhoVec.end(), + [&rho](double &val) { val *= rho; }); + return rhoVec; +} + double wallData::WallFrictionVelocity(const int &ii, const int &jj, const int &kk) const { return (*this)(ii, jj, kk).frictionVelocity_; @@ -76,7 +174,7 @@ double wallData::WallFrictionVelocity(const int &ii, const int &jj, void wallData::PackWallData(char *(&sendBuffer), const int &sendBufSize, int &position, - const MPI_Datatype &MPI_wallData) const { + const MPI_Datatype &MPI_vec3d) const { // sendBuffer -- buffer to pack data into // sendBufSize -- size of buffer // position -- location within buffer @@ -87,22 +185,29 @@ void wallData::PackWallData(char *(&sendBuffer), const int &sendBufSize, MPI_Pack(&viscousForce_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + // pack number of species counter + MPI_Pack(&numSpecies_, 1, MPI_INT, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + // pointer to bc data - remote processor can get data from input class // pack boundarySurface surf_.PackBoundarySurface(sendBuffer, sendBufSize, position); // pack wall variables - MPI_Pack(&(*std::begin(data_)), data_.Size(), MPI_wallData, sendBuffer, - sendBufSize, &position, MPI_COMM_WORLD); + for (auto &wv : data_) { + wv.Pack(sendBuffer, sendBufSize, position, MPI_vec3d); + } } -void wallData::PackSize(int &sendBufSize, - const MPI_Datatype &MPI_wallData) const { +void wallData::PackSize(int &sendBufSize, const MPI_Datatype &MPI_vec3d) const { auto tempSize = 0; // add sizes for force data MPI_Pack_size(2, MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); sendBufSize += tempSize; + // add sizes for number of species + MPI_Pack_size(1, MPI_INT, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; // 8 because iMin, iMax, jMin, jMax, kMin, kMax, tags, string sizes MPI_Pack_size(8, MPI_INT, MPI_COMM_WORLD, &tempSize); sendBufSize += tempSize; @@ -111,12 +216,13 @@ void wallData::PackSize(int &sendBufSize, sendBufSize += tempSize; // add array of wallData - MPI_Pack_size(data_.Size(), MPI_wallData, MPI_COMM_WORLD, &tempSize); - sendBufSize += tempSize; + for (auto &wv : data_) { + wv.PackSize(sendBufSize, MPI_vec3d); + } } void wallData::UnpackWallData(char *(&recvBuffer), const int &recvBufSize, - int &position, const MPI_Datatype &MPI_wallData, + int &position, const MPI_Datatype &MPI_vec3d, const input &inp) { // recvBuffer -- buffer to unpack data from // recvBufSize -- size of buffer @@ -128,6 +234,10 @@ void wallData::UnpackWallData(char *(&recvBuffer), const int &recvBufSize, MPI_Unpack(recvBuffer, recvBufSize, &position, &viscousForce_, 1, MPI_DOUBLE, MPI_COMM_WORLD); + // unpack number of species + MPI_Unpack(recvBuffer, recvBufSize, &position, &numSpecies_, 1, MPI_INT, + MPI_COMM_WORLD); + // unpack BC surface surf_.UnpackBoundarySurface(recvBuffer, recvBufSize, position); @@ -135,9 +245,11 @@ void wallData::UnpackWallData(char *(&recvBuffer), const int &recvBufSize, bcData_ = inp.BCData(surf_.Tag()); // unpack wall variables - data_.ClearResize(surf_.NumI(), surf_.NumJ(), surf_.NumK(), 0); - MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(data_)), - data_.Size(), MPI_wallData, MPI_COMM_WORLD); + data_.ClearResize(surf_.NumI(), surf_.NumJ(), surf_.NumK(), 0, 1, + wallVars(numSpecies_)); + for (auto &wv : data_) { + wv.Unpack(recvBuffer, recvBufSize, position, MPI_vec3d, numSpecies_); + } } // Split wallData at given direction and index @@ -173,7 +285,8 @@ void wallData::Join(const wallData &upper, const string &dir, bool &joined) { inviscidForce_ += upper.inviscidForce_; viscousForce_ += upper.viscousForce_; - multiArray3d newVars(surf_.NumI(), surf_.NumJ(), surf_.NumK(), 0); + multiArray3d newVars(surf_.NumI(), surf_.NumJ(), surf_.NumK(), 0, + 1, wallVars(numSpecies_)); newVars.Insert(dir, {data_.Start(dir), data_.PhysEnd(dir)}, data_.Slice(dir, {data_.Start(dir), data_.PhysEnd(dir)})); newVars.Insert(dir, {data_.PhysEnd(dir), newVars.End(dir)}, @@ -183,16 +296,26 @@ void wallData::Join(const wallData &upper, const string &dir, bool &joined) { } } - primVars wallData::WallState(const int &ii, const int &jj, const int &kk, - const unique_ptr &eqnState) const { - return primVars(this->WallDensity(ii, jj, kk), this->WallVelocity(), - this->WallPressure(ii, jj, kk, eqnState), - this->WallTke(ii, jj, kk), this->WallSdr(ii, jj, kk)); + void wallData::WallState(const int &ii, const int &jj, const int &kk, + const unique_ptr &eqnState, primitive &wState) const { + auto rhoVec = this->WallDensityVec(ii, jj, kk); + for (auto ii = 0; ii < wState.NumSpecies(); ++ii) { + wState[ii] = rhoVec[ii]; + } + wState[wState.MomentumXIndex()] = this->WallVelocity().X(); + wState[wState.MomentumYIndex()] = this->WallVelocity().Y(); + wState[wState.MomentumZIndex()] = this->WallVelocity().Z(); + wState[wState.EnergyIndex()] = this->WallPressure(ii, jj, kk, eqnState); + for (auto ii = 0; ii < wState.NumTurbulence(); ++ii) { + wState[wState.TurbulenceIndex() + ii] = + (ii == 0) ? this->WallTke(ii, jj, kk) : this->WallSdr(ii, jj, kk); + } } void wallData::Print(ostream &os) const { os << "Inviscid Force: " << inviscidForce_ << endl; os << "Viscous Force: " << viscousForce_ << endl; + os << "Number of Species: " << numSpecies_ << endl; os << "BC Data: "; bcData_->Print(os); os << endl; diff --git a/src/wallLaw.cpp b/src/wallLaw.cpp index e4e2e9e..ebca839 100644 --- a/src/wallLaw.cpp +++ b/src/wallLaw.cpp @@ -1,5 +1,5 @@ /* This file is part of aither. - Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) + Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) Aither is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,12 +18,9 @@ #include // cout #include #include "wallLaw.hpp" -#include "primVars.hpp" // primVars -#include "eos.hpp" // equation of state -#include "transport.hpp" // transport model -#include "thermodynamic.hpp" // thermodynamic model +#include "primitive.hpp" // primitive +#include "physicsModels.hpp" #include "utility.hpp" // find root -#include "turbulence.hpp" #include "wallData.hpp" using std::cout; @@ -33,14 +30,12 @@ using std::cerr; // ------------------------------------------------------------------------- wallVars wallLaw::AdiabaticBCs(const vector3d &area, const vector3d &velWall, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const bool &isLower) { + const vector &wallMf, + const physics &phys, const bool &isLower) { // initialize wallVars wallVars wVars; wVars.heatFlux_ = 0.0; + wVars.mf_ = wallMf; // get tangential velocity const auto vel = state_.Velocity() - velWall; @@ -48,18 +43,19 @@ wallVars wallLaw::AdiabaticBCs(const vector3d &area, const auto velTanMag = velTan.Mag(); // get wall temperature from crocco-busemann equation - auto t = state_.Temperature(eqnState); - this->CalcRecoveryFactor(thermo, t); + auto t = state_.Temperature(phys.EoS()); + this->CalcRecoveryFactor(phys.Thermodynamic(), t); // this is correct form of crocco-busemann, typo in Nichols & Nelson (2004) - auto tW = t + 0.5 * recoveryFactor_ * velTanMag * velTanMag / thermo->Cp(t); + auto tW = t + 0.5 * recoveryFactor_ * velTanMag * velTanMag / + phys.Thermodynamic()->Cp(t, state_.MassFractions()); // set wall properties - this->SetWallVars(tW, eqnState, thermo, trans); + this->SetWallVars(tW, phys); auto func = [&](const double &yplus) { // calculate u* and u+ from y+ this->CalcVelocities(yplus, velTanMag); // calculate constants - this->UpdateGamma(thermo, tW); + this->UpdateGamma(phys.Thermodynamic(), tW); this->UpdateConstants(wVars.heatFlux_); // calculate y+ from White & Christoph this->CalcYplusWhite(); @@ -75,7 +71,7 @@ wallVars wallLaw::AdiabaticBCs(const vector3d &area, // use compressible form of equation (Nichols & Nelson 2004) // calculate turbulence variables from eddy viscosity if (isRANS_) { - this->CalcTurbVars(turb, eqnState, trans, wVars.tke_, wVars.sdr_); + this->CalcTurbVars(phys, wVars.tke_, wVars.sdr_); } wVars.density_ = rhoW_; @@ -92,14 +88,12 @@ wallVars wallLaw::AdiabaticBCs(const vector3d &area, wallVars wallLaw::HeatFluxBCs(const vector3d &area, const vector3d &velWall, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, + const vector &wallMf, const physics &phys, const double &heatFluxW, const bool &isLower) { // initialize wallVars wallVars wVars; wVars.heatFlux_ = heatFluxW; + wVars.mf_ = wallMf; // get tangential velocity const auto vel = state_.Velocity() - velWall; @@ -107,20 +101,20 @@ wallVars wallLaw::HeatFluxBCs(const vector3d &area, const auto velTanMag = velTan.Mag(); // get wall temperature from crocco-busemann equation - wVars.temperature_ = state_.Temperature(eqnState); - this->CalcRecoveryFactor(thermo, wVars.temperature_); + wVars.temperature_ = state_.Temperature(phys.EoS()); + this->CalcRecoveryFactor(phys.Thermodynamic(), wVars.temperature_); // set wall properties - guess wall temperature equals interior temperature - this->SetWallVars(wVars.temperature_, eqnState, thermo, trans); + this->SetWallVars(wVars.temperature_, phys); auto func = [&](const double &yplus) { // calculate u* and u+ from y+ this->CalcVelocities(yplus, velTanMag); // calculate wall temperature from croco-busemann wVars.temperature_ = - this->CalcWallTemperature(eqnState, thermo, wVars.heatFlux_); - this->SetWallVars(wVars.temperature_, eqnState, thermo, trans); - this->UpdateGamma(thermo, wVars.temperature_); + this->CalcWallTemperature(phys, wVars.heatFlux_); + this->SetWallVars(wVars.temperature_, phys); + this->UpdateGamma(phys.Thermodynamic(), wVars.temperature_); this->UpdateConstants(wVars.heatFlux_); // calculate y+ from White & Christoph this->CalcYplusWhite(); @@ -136,7 +130,7 @@ wallVars wallLaw::HeatFluxBCs(const vector3d &area, // use compressible form of equation (Nichols & Nelson 2004) // calculate turbulence variables from eddy viscosity if (isRANS_) { - this->CalcTurbVars(turb, eqnState, trans, wVars.tke_, wVars.sdr_); + this->CalcTurbVars(phys, wVars.tke_, wVars.sdr_); } wVars.density_ = rhoW_; @@ -152,14 +146,13 @@ wallVars wallLaw::HeatFluxBCs(const vector3d &area, wallVars wallLaw::IsothermalBCs(const vector3d &area, const vector3d &velWall, - const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans, - const unique_ptr &turb, - const double &tW, const bool &isLower) { + const vector &wallMf, + const physics &phys, const double &tW, + const bool &isLower) { // initialize wallVars wallVars wVars; wVars.temperature_ = tW; + wVars.mf_ = wallMf; // get tangential velocity const auto vel = state_.Velocity() - velWall; @@ -167,15 +160,15 @@ wallVars wallLaw::IsothermalBCs(const vector3d &area, const auto velTanMag = velTan.Mag(); // get wall properties - this->CalcRecoveryFactor(thermo, tW); - this->SetWallVars(wVars.temperature_, eqnState, thermo, trans); + this->CalcRecoveryFactor(phys.Thermodynamic(), tW); + this->SetWallVars(wVars.temperature_, phys); auto func = [&](const double &yplus) { // calculate u* and u+ from y+ this->CalcVelocities(yplus, velTanMag); // calculate wall heat flux from croco-busemann equation - this->UpdateGamma(thermo, tW); - wVars.heatFlux_ = this->CalcHeatFlux(eqnState); + this->UpdateGamma(phys.Thermodynamic(), tW); + wVars.heatFlux_ = this->CalcHeatFlux(phys.EoS()); // calculate constants this->UpdateConstants(wVars.heatFlux_); // calculate y+ from White & Christoph @@ -192,7 +185,7 @@ wallVars wallLaw::IsothermalBCs(const vector3d &area, // use compressible form of equation (Nichols & Nelson 2004) // calculate turbulence variables from eddy viscosity if (isRANS_) { - this->CalcTurbVars(turb, eqnState, trans, wVars.tke_, wVars.sdr_); + this->CalcTurbVars(phys, wVars.tke_, wVars.sdr_); } wVars.density_ = rhoW_; @@ -209,7 +202,8 @@ wallVars wallLaw::IsothermalBCs(const vector3d &area, void wallLaw::UpdateGamma(const unique_ptr &thermo, const double &t) { // calculate constants - gamma_ = recoveryFactor_ * uStar_ * uStar_ / (2.0 * thermo->Cp(t) * tW_); + gamma_ = recoveryFactor_ * uStar_ * uStar_ / + (2.0 * thermo->Cp(t, state_.MassFractions()) * tW_); } void wallLaw::UpdateConstants(const double &heatFluxW) { @@ -234,24 +228,21 @@ double wallLaw::CalcHeatFlux(const unique_ptr &eqnState) const { return tmp * (rhoW_ * tW_ * kW_ * uStar_) / muW_; } -double wallLaw::CalcWallTemperature(const unique_ptr &eqnState, - const unique_ptr &thermo, +double wallLaw::CalcWallTemperature(const physics &phys, const double &heatFluxW) const { - const auto t = state_.Temperature(eqnState); - return t + - recoveryFactor_ * uStar_ * uStar_ * uplus_ * uplus_ / - (2.0 * thermo->Cp(t) + heatFluxW * muW_ / (rhoW_ * kW_ * uStar_)); + const auto t = state_.Temperature(phys.EoS()); + return t + recoveryFactor_ * uStar_ * uStar_ * uplus_ * uplus_ / + (2.0 * phys.Thermodynamic()->Cp(t, state_.MassFractions()) + + heatFluxW * muW_ / (rhoW_ * kW_ * uStar_)); } -void wallLaw::SetWallVars(const double &tW, const unique_ptr &eqnState, - const unique_ptr &thermo, - const unique_ptr &trans) { +void wallLaw::SetWallVars(const double &tW, const physics &phys) { tW_ = tW; - rhoW_ = eqnState->DensityTP(tW_, state_.P()); + rhoW_ = phys.EoS()->DensityTP(tW_, state_.P(), state_.MassFractions()); // get wall viscosity, conductivity from wall temperature - muW_ = trans->EffectiveViscosity(tW_); - kW_ = trans->Conductivity(muW_, tW_, thermo); + muW_ = phys.Transport()->EffectiveViscosity(tW_, state_.MassFractions()); + kW_ = phys.Transport()->EffectiveConductivity(tW_, state_.MassFractions()); } double wallLaw::CalcYplusRoot(const double &yplus) const { @@ -261,8 +252,7 @@ double wallLaw::CalcYplusRoot(const double &yplus) const { yplus0_ * (1.0 + ku + 0.5 * ku * ku + sixth * pow(ku, 3.0))); } -void wallLaw::EddyVisc(const unique_ptr &eqnState, - const unique_ptr &trans) { +void wallLaw::EddyVisc(const physics &phys) { const auto dYplusWhite = 2.0 * yplusWhite_ * vonKarmen_ * sqrt(gamma_) / q_ * sqrt(std::max(1.0 - pow(2.0 * gamma_ * uplus_ - beta_, 2.0) / (q_ * q_), @@ -270,7 +260,8 @@ void wallLaw::EddyVisc(const unique_ptr &eqnState, const auto ku = vonKarmen_ * uplus_; mutW_ = muW_ * (1.0 + dYplusWhite - vonKarmen_ * yplus0_ * (1.0 + ku + 0.5 * ku * ku)) - - trans->EffectiveViscosity(state_.Temperature(eqnState)); + phys.Transport()->EffectiveViscosity(state_.Temperature(phys.EoS()), + state_.MassFractions()); mutW_ = std::max(mutW_, 0.0); } @@ -280,21 +271,20 @@ void wallLaw::CalcVelocities(const double &yplus, const double &u) { uStar_ = u / uplus_; } -void wallLaw::CalcTurbVars(const unique_ptr &turb, - const unique_ptr &eqnState, - const unique_ptr &trans, double &kWall, - double &wWall) { - this->EddyVisc(eqnState, trans); +void wallLaw::CalcTurbVars(const physics &phys, double &kWall, double &wWall) { + this->EddyVisc(phys); // calculate turbulence variables from eddy viscosity - auto wi = 6.0 * muW_ / (turb->WallBeta() * rhoW_ * wallDist_ * wallDist_); - wi *= trans->NondimScaling(); - auto wo = uStar_ / (sqrt(turb->BetaStar()) * vonKarmen_ * wallDist_); - wo *= trans->NondimScaling(); + auto wi = 6.0 * muW_ / + (phys.Turbulence()->WallBeta() * rhoW_ * wallDist_ * wallDist_); + wi *= phys.Transport()->NondimScaling(); + auto wo = + uStar_ / (sqrt(phys.Turbulence()->BetaStar()) * vonKarmen_ * wallDist_); + wo *= phys.Transport()->NondimScaling(); wWall = sqrt(wi * wi + wo * wo); - kWall = wWall * mutW_ / state_.Rho() * trans->InvNondimScaling(); + kWall = wWall * mutW_ / state_.Rho() * phys.Transport()->InvNondimScaling(); } void wallLaw::CalcRecoveryFactor(const unique_ptr &thermo, const double &t) { - recoveryFactor_ = pow(thermo->Prandtl(t), 1.0 / 3.0); + recoveryFactor_ = pow(thermo->Prandtl(t, state_.MassFractions()), 1.0 / 3.0); } \ No newline at end of file diff --git a/testCases/convectingVortex/convectingVortex.inp b/testCases/convectingVortex/convectingVortex.inp new file mode 100755 index 0000000..4c02896 --- /dev/null +++ b/testCases/convectingVortex/convectingVortex.inp @@ -0,0 +1,55 @@ +# grid name +gridName: convectingVortex + +# solver parameters +decompositionMethod: cubic +equationSet: navierStokes +timeIntegration: bdf2 +timeStep: 6.5e-07 +dualTimeCFL: 1000 + +faceReconstruction: thirdOrder +inviscidFlux: roe +inviscidFluxJacobian: rusanov +viscousFaceReconstruction: central +limiter: none + +iterations: 200 +nonlinearIterations: 10 +outputFrequency: 1 +outputVariables: +restartFrequency: 100 + +# reference conditions +referenceDensity: 1.185 +referenceTemperature: 288 +referenceLength: 1 + +fluids: +thermodynamicModel: caloricallyPerfect + +initialConditions: + +matrixSolver: lusgs +matrixSweeps: 1 +matrixRelaxation: 1 + +turbulenceModel: none + +boundaryStates: + +#------------------------------------------------------------- +boundaryConditions: 1 +# Block 0 -- Dimensions: 40 x 40 x 2 +2 2 2 +# i-surfaces + periodic 0 0 0 39 0 1 5 + periodic 39 39 0 39 0 1 4 +# j-surfaces + inlet 0 39 0 0 0 1 2 + pressureOutlet 0 39 39 39 0 1 3 +# k-surfaces + slipWall 0 39 0 39 0 0 1 + slipWall 0 39 0 39 1 1 1 diff --git a/testCases/convectingVortex/convectingVortex.xyz b/testCases/convectingVortex/convectingVortex.xyz new file mode 100755 index 0000000..e813751 Binary files /dev/null and b/testCases/convectingVortex/convectingVortex.xyz differ diff --git a/testCases/convectingVortex/vortex.dat b/testCases/convectingVortex/vortex.dat new file mode 100644 index 0000000..d64e913 --- /dev/null +++ b/testCases/convectingVortex/vortex.dat @@ -0,0 +1,1523 @@ +1521 +N2 +-0.00633333 -0.00633333 0.0 1.18509471399 100.0 -2.029721224e-08 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.005999996842 0.0 1.18509471399 100.0000001 -6.849682069e-08 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.005666663684 0.0 1.18509471399 100.0000002 -2.164468374e-07 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.005333330526 0.0 1.18509471399 100.0000005 -6.404406429e-07 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.004999997368 0.0 1.18509471399 100.0000014 -1.774407379e-06 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.004666664211 0.0 1.18509471399 100.0000034 -4.60335634e-06 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.004333331053 0.0 1.18509471399 100.0000077 -1.118259673e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.003999997895 0.0 1.18509471399 100.0000161 -2.54365111e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.003666664737 0.0 1.18509471399 100.0000314 -5.417753375e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.003333331579 0.0 1.18509471399 100.0000569 -0.0001080507361 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.002999998421 0.0 1.18509471399 100.0000956 -0.0002017822859 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.002666665263 0.0 1.18509471399 100.0001486 -0.000352845965 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.002333332105 0.0 1.18509471399 100.0002129 -0.0005777421893 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.001999998947 0.0 1.18509471399 100.0002797 -0.0008857880559 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.001666665789 0.0 1.18509471399 100.0003346 -0.00127166397 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.001333332632 0.0 1.18509471399 100.0003599 -0.001709470942 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.0009999994737 0.0 1.18509471399 100.0003398 -0.002151780112 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.0006666663158 0.0 1.18509471399 100.000267 -0.002536184623 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 -0.0003333331579 0.0 1.18509471399 100.0001473 -0.002799049962 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.0 0.0 1.18509471399 100.0 -0.002892592432 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.0003333331579 0.0 1.18509471399 99.99985268 -0.002799049962 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.0006666663158 0.0 1.18509471399 99.99973303 -0.002536184623 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.0009999994737 0.0 1.18509471399 99.99966025 -0.002151780112 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.001333332632 0.0 1.18509471399 99.99964011 -0.001709470942 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.001666665789 0.0 1.18509471399 99.99966535 -0.00127166397 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.001999998947 0.0 1.18509471399 99.99972028 -0.0008857880559 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.002333332105 0.0 1.18509471399 99.99978715 -0.0005777421893 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.002666665263 0.0 1.18509471399 99.99985143 -0.000352845965 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.002999998421 0.0 1.18509471399 99.99990442 -0.0002017822859 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.003333331579 0.0 1.18509471399 99.99994313 -0.0001080507361 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.003666664737 0.0 1.18509471399 99.99996863 -5.417753375e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.003999997895 0.0 1.18509471399 99.99998393 -2.54365111e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.004333331053 0.0 1.18509471399 99.99999235 -1.118259673e-05 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.004666664211 0.0 1.18509471399 99.99999661 -4.60335634e-06 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.004999997368 0.0 1.18509471399 99.9999986 -1.774407379e-06 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.005333330526 0.0 1.18509471399 99.99999946 -6.404406429e-07 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.005666663684 0.0 1.18509471399 99.99999981 -2.164468374e-07 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.005999996842 0.0 1.18509471399 99.99999994 -6.849682069e-08 0.0 101300.0 0.0 0.0 1.0 +-0.00633333 0.00633333 0.0 1.18509471399 99.99999998 -2.029721224e-08 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.00633333 0.0 1.18509471399 100.0000001 -6.489172486e-08 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.005999996842 0.0 1.18509471399 100.0000002 -2.189895237e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.005666663684 0.0 1.18509471399 100.0000007 -6.919969329e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.005333330526 0.0 1.18509471399 100.0000018 -2.047537243e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.004999997368 0.0 1.18509471399 100.0000047 -5.672914784e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.004666664211 0.0 1.18509471399 100.0000114 -1.471727888e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.004333331053 0.0 1.18509471399 100.0000258 -3.575160873e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.003999997895 0.0 1.18509471399 100.0000542 -8.132245254e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.003666664737 0.0 1.18509471399 100.0001059 -0.0001732096788 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.003333331579 0.0 1.18509471399 100.0001919 -0.000345446387 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.002999998421 0.0 1.18509471399 100.0003226 -0.0006451132512 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.002666665263 0.0 1.18509471399 100.0005014 -0.001128075275 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.002333332105 0.0 1.18509471399 100.0007183 -0.001847085538 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.001999998947 0.0 1.18509471399 100.000944 -0.002831931505 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.001666665789 0.0 1.18509471399 100.0011293 -0.004065606029 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.001333332632 0.0 1.18509471399 100.0012145 -0.005465308079 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.0009999994737 0.0 1.18509471399 100.0011466 -0.006879403995 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.0006666663158 0.0 1.18509471399 100.0009009 -0.00810837433 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 -0.0003333331579 0.0 1.18509471399 100.0004972 -0.008948774728 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.0 0.0 1.18509471399 100.0 -0.009247837092 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.0003333331579 0.0 1.18509471399 99.99950285 -0.008948774728 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.0006666663158 0.0 1.18509471399 99.99909907 -0.00810837433 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.0009999994737 0.0 1.18509471399 99.99885343 -0.006879403995 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.001333332632 0.0 1.18509471399 99.99878549 -0.005465308079 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.001666665789 0.0 1.18509471399 99.99887066 -0.004065606029 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.001999998947 0.0 1.18509471399 99.99905602 -0.002831931505 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.002333332105 0.0 1.18509471399 99.99928169 -0.001847085538 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.002666665263 0.0 1.18509471399 99.99949863 -0.001128075275 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.002999998421 0.0 1.18509471399 99.99967744 -0.0006451132512 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.003333331579 0.0 1.18509471399 99.99980809 -0.000345446387 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.003666664737 0.0 1.18509471399 99.99989415 -0.0001732096788 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.003999997895 0.0 1.18509471399 99.99994579 -8.132245254e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.004333331053 0.0 1.18509471399 99.99997418 -3.575160873e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.004666664211 0.0 1.18509471399 99.99998855 -1.471727888e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.004999997368 0.0 1.18509471399 99.99999527 -5.672914784e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.005333330526 0.0 1.18509471399 99.99999818 -2.047537243e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.005666663684 0.0 1.18509471399 99.99999935 -6.919969329e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.005999996842 0.0 1.18509471399 99.99999978 -2.189895237e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005999996842 0.00633333 0.0 1.18509471399 99.99999993 -6.489172486e-08 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.00633333 0.0 1.18509471399 100.0000002 -1.936629598e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.005999996842 0.0 1.18509471399 100.0000007 -6.535526589e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.005666663684 0.0 1.18509471399 100.0000021 -2.065196672e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.005333330526 0.0 1.18509471399 100.0000058 -6.110673179e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.004999997368 0.0 1.18509471399 100.0000149 -1.693025528e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.004666664211 0.0 1.18509471399 100.0000362 -4.392226888e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.004333331053 0.0 1.18509471399 100.0000816 -0.0001066971541 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.003999997895 0.0 1.18509471399 100.0001713 -0.0002426988478 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.003666664737 0.0 1.18509471399 100.0003345 -0.000516927222 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.003333331579 0.0 1.18509471399 100.0006064 -0.001030950709 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.002999998421 0.0 1.18509471399 100.0010193 -0.001925276942 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.002666665263 0.0 1.18509471399 100.0015843 -0.003366629521 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.002333332105 0.0 1.18509471399 100.0022698 -0.005512444814 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.001999998947 0.0 1.18509471399 100.0029829 -0.008451620577 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.001666665789 0.0 1.18509471399 100.0035686 -0.01213340065 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.001333332632 0.0 1.18509471399 100.0038378 -0.01631067353 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.0009999994737 0.0 1.18509471399 100.0036231 -0.02053090347 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.0006666663158 0.0 1.1850947144 100.0028469 -0.02419864436 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 -0.0003333331579 0.0 1.1850947144 100.001571 -0.02670673655 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.0 0.0 1.1850947144 100.0 -0.02759925871 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.0003333331579 0.0 1.1850947144 99.99842902 -0.02670673655 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.0006666663158 0.0 1.1850947144 99.9971531 -0.02419864436 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.0009999994737 0.0 1.18509471399 99.9963769 -0.02053090347 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.001333332632 0.0 1.18509471399 99.99616219 -0.01631067353 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.001666665789 0.0 1.18509471399 99.99643135 -0.01213340065 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.001999998947 0.0 1.18509471399 99.99701708 -0.008451620577 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.002333332105 0.0 1.18509471399 99.99773017 -0.005512444814 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.002666665263 0.0 1.18509471399 99.9984157 -0.003366629521 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.002999998421 0.0 1.18509471399 99.99898074 -0.001925276942 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.003333331579 0.0 1.18509471399 99.99939356 -0.001030950709 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.003666664737 0.0 1.18509471399 99.99966552 -0.000516927222 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.003999997895 0.0 1.18509471399 99.99982868 -0.0002426988478 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.004333331053 0.0 1.18509471399 99.99991841 -0.0001066971541 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.004666664211 0.0 1.18509471399 99.99996383 -4.392226888e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.004999997368 0.0 1.18509471399 99.99998506 -1.693025528e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.005333330526 0.0 1.18509471399 99.99999425 -6.110673179e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.005666663684 0.0 1.18509471399 99.99999793 -2.065196672e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.005999996842 0.0 1.18509471399 99.99999931 -6.535526589e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005666663684 0.00633333 0.0 1.18509471399 99.99999978 -1.936629598e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.00633333 0.0 1.18509471399 100.0000006 -5.393184361e-07 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.005999996842 0.0 1.18509471399 100.000002 -1.820033104e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.005666663684 0.0 1.18509471399 100.0000061 -5.751221816e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.005333330526 0.0 1.18509471399 100.000017 -1.701718649e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.004999997368 0.0 1.18509471399 100.0000442 -4.71478842e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.004666664211 0.0 1.18509471399 100.000107 -0.0001223160556 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.004333331053 0.0 1.18509471399 100.0002414 -0.0002971334442 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.003999997895 0.0 1.18509471399 100.0005069 -0.0006758750522 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.003666664737 0.0 1.18509471399 100.0009897 -0.001439554478 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.003333331579 0.0 1.18509471399 100.0017944 -0.002871022547 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.002999998421 0.0 1.18509471399 100.0030159 -0.005361569145 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.002666665263 0.0 1.18509471399 100.0046877 -0.009375491164 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.002333332105 0.0 1.18509471399 100.0067162 -0.01535122214 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.001999998947 0.0 1.1850947144 100.0088261 -0.02353632722 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.001666665789 0.0 1.1850947144 100.0105592 -0.03378945913 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 -0.001333332632 0.0 1.18509471364 100.0113556 -0.04542245429 0.0 101299.9999 0.0 0.0 1.0 +-0.005333330526 -0.0009999994737 0.0 1.18509471405 100.0107203 -0.05717507759 0.0 101299.9999 0.0 0.0 1.0 +-0.005333330526 -0.0006666663158 0.0 1.1850947137 100.0084236 -0.06738911275 0.0 101299.9998 0.0 0.0 1.0 +-0.005333330526 -0.0003333331579 0.0 1.18509471412 100.0046484 -0.07437372334 0.0 101299.9998 0.0 0.0 1.0 +-0.005333330526 0.0 0.0 1.18509471412 100.0 -0.0768592459 0.0 101299.9998 0.0 0.0 1.0 +-0.005333330526 0.0003333331579 0.0 1.18509471412 99.99535164 -0.07437372334 0.0 101299.9998 0.0 0.0 1.0 +-0.005333330526 0.0006666663158 0.0 1.1850947137 99.99157636 -0.06738911275 0.0 101299.9998 0.0 0.0 1.0 +-0.005333330526 0.0009999994737 0.0 1.18509471405 99.98927967 -0.05717507759 0.0 101299.9999 0.0 0.0 1.0 +-0.005333330526 0.001333332632 0.0 1.18509471364 99.98864439 -0.04542245429 0.0 101299.9999 0.0 0.0 1.0 +-0.005333330526 0.001666665789 0.0 1.1850947144 99.98944079 -0.03378945913 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.001999998947 0.0 1.1850947144 99.99117388 -0.02353632722 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.002333332105 0.0 1.18509471399 99.99328384 -0.01535122214 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.002666665263 0.0 1.18509471399 99.99531225 -0.009375491164 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.002999998421 0.0 1.18509471399 99.99698412 -0.005361569145 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.003333331579 0.0 1.18509471399 99.99820561 -0.002871022547 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.003666664737 0.0 1.18509471399 99.99901031 -0.001439554478 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.003999997895 0.0 1.18509471399 99.99949309 -0.0006758750522 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.004333331053 0.0 1.18509471399 99.99975858 -0.0002971334442 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.004666664211 0.0 1.18509471399 99.99989297 -0.0001223160556 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.004999997368 0.0 1.18509471399 99.9999558 -4.71478842e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.005333330526 0.0 1.18509471399 99.99998298 -1.701718649e-05 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.005666663684 0.0 1.18509471399 99.99999389 -5.751221816e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.005999996842 0.0 1.18509471399 99.99999795 -1.820033104e-06 0.0 101300.0 0.0 0.0 1.0 +-0.005333330526 0.00633333 0.0 1.18509471399 99.99999936 -5.393184361e-07 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.00633333 0.0 1.18509471399 100.0000018 -1.40084793e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.005999996842 0.0 1.18509471399 100.0000057 -4.727428986e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.005666663684 0.0 1.18509471399 100.0000169 -1.493846054e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.005333330526 0.0 1.18509471399 100.0000471 -4.420114144e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.004999997368 0.0 1.18509471399 100.0001225 -0.0001224638573 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.004666664211 0.0 1.18509471399 100.0002965 -0.0003177087634 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.004333331053 0.0 1.18509471399 100.0006689 -0.0007717866525 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.003999997895 0.0 1.18509471399 100.0014044 -0.001755545712 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.003666664737 0.0 1.18509471399 100.002742 -0.003739158123 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.003333331579 0.0 1.18509471399 100.0049715 -0.007457312274 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.002999998421 0.0 1.18509471399 100.0083558 -0.01392636064 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.002666665263 0.0 1.1850947144 100.0129879 -0.0243522871 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 -0.002333332105 0.0 1.18509471364 100.0186078 -0.03987389699 0.0 101299.9999 0.0 0.0 1.0 +-0.004999997368 -0.001999998947 0.0 1.18509471446 100.0244537 -0.06113422622 0.0 101299.9999 0.0 0.0 1.0 +-0.004999997368 -0.001666665789 0.0 1.18509471418 100.0292554 -0.08776613356 0.0 101299.9997 0.0 0.0 1.0 +-0.004999997368 -0.001333332632 0.0 1.18509471355 100.0314619 -0.1179821546 0.0 101299.9994 0.0 0.0 1.0 +-0.004999997368 -0.0009999994737 0.0 1.18509471374 100.0297018 -0.1485089026 0.0 101299.9991 0.0 0.0 1.0 +-0.004999997368 -0.0006666663158 0.0 1.18509471435 100.0233386 -0.1750392585 0.0 101299.9988 0.0 0.0 1.0 +-0.004999997368 -0.0003333331579 0.0 1.18509471372 100.0128788 -0.1931813738 0.0 101299.9985 0.0 0.0 1.0 +-0.004999997368 0.0 0.0 1.18509471379 100.0 -0.1996373725 0.0 101299.9984 0.0 0.0 1.0 +-0.004999997368 0.0003333331579 0.0 1.18509471372 99.98712124 -0.1931813738 0.0 101299.9985 0.0 0.0 1.0 +-0.004999997368 0.0006666663158 0.0 1.18509471435 99.97666143 -0.1750392585 0.0 101299.9988 0.0 0.0 1.0 +-0.004999997368 0.0009999994737 0.0 1.18509471374 99.97029822 -0.1485089026 0.0 101299.9991 0.0 0.0 1.0 +-0.004999997368 0.001333332632 0.0 1.18509471355 99.96853809 -0.1179821546 0.0 101299.9994 0.0 0.0 1.0 +-0.004999997368 0.001666665789 0.0 1.18509471418 99.97074462 -0.08776613356 0.0 101299.9997 0.0 0.0 1.0 +-0.004999997368 0.001999998947 0.0 1.18509471446 99.97554631 -0.06113422622 0.0 101299.9999 0.0 0.0 1.0 +-0.004999997368 0.002333332105 0.0 1.18509471364 99.98139218 -0.03987389699 0.0 101299.9999 0.0 0.0 1.0 +-0.004999997368 0.002666665263 0.0 1.1850947144 99.98701211 -0.0243522871 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.002999998421 0.0 1.18509471399 99.99164418 -0.01392636064 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.003333331579 0.0 1.18509471399 99.99502846 -0.007457312274 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.003666664737 0.0 1.18509471399 99.99725795 -0.003739158123 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.003999997895 0.0 1.18509471399 99.99859556 -0.001755545712 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.004333331053 0.0 1.18509471399 99.99933112 -0.0007717866525 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.004666664211 0.0 1.18509471399 99.99970347 -0.0003177087634 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.004999997368 0.0 1.18509471399 99.99987754 -0.0001224638573 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.005333330526 0.0 1.18509471399 99.99995285 -4.420114144e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.005666663684 0.0 1.18509471399 99.99998307 -1.493846054e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.005999996842 0.0 1.18509471399 99.99999433 -4.727428986e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004999997368 0.00633333 0.0 1.18509471399 99.99999823 -1.40084793e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.00633333 0.0 1.18509471399 100.0000046 -3.391946777e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.005999996842 0.0 1.18509471399 100.0000147 -1.144677246e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.005666663684 0.0 1.18509471399 100.0000439 -3.617128026e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.005333330526 0.0 1.18509471399 100.0001223 -0.0001070265487 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.004999997368 0.0 1.18509471399 100.0003177 -0.0002965281792 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.004666664211 0.0 1.18509471399 100.0007693 -0.0007692849398 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.004333331053 0.0 1.18509471399 100.0017353 -0.001868767617 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.003999997895 0.0 1.18509471399 100.0036435 -0.004250795173 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.003666664737 0.0 1.18509471399 100.0071137 -0.009053820237 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.003333331579 0.0 1.18509471399 100.0128977 -0.01805678245 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 -0.002999998421 0.0 1.18509471323 100.0216775 -0.03372062952 0.0 101299.9999 0.0 0.0 1.0 +-0.004666664211 -0.002666665263 0.0 1.1850947137 100.0336946 -0.05896547365 0.0 101299.9998 0.0 0.0 1.0 +-0.004666664211 -0.002333332105 0.0 1.18509471424 100.0482744 -0.0965487641 0.0 101299.9996 0.0 0.0 1.0 +-0.004666664211 -0.001999998947 0.0 1.18509471422 100.0634404 -0.1480275175 0.0 101299.999 0.0 0.0 1.0 +-0.004666664211 -0.001666665789 0.0 1.1850947137 100.0758974 -0.2125127556 0.0 101299.9979 0.0 0.0 1.0 +-0.004666664211 -0.001333332632 0.0 1.18509471356 100.0816218 -0.2856763965 0.0 101299.9962 0.0 0.0 1.0 +-0.004666664211 -0.0009999994737 0.0 1.1850947145 100.0770555 -0.3595924173 0.0 101299.9941 0.0 0.0 1.0 +-0.004666664211 -0.0006666663158 0.0 1.18509471359 100.0605474 -0.4238317633 0.0 101299.9917 0.0 0.0 1.0 +-0.004666664211 -0.0003333331579 0.0 1.18509471351 100.0334114 -0.4677602215 0.0 101299.9899 0.0 0.0 1.0 +-0.004666664211 0.0 0.0 1.18509471431 100.0 -0.4833924708 0.0 101299.9893 0.0 0.0 1.0 +-0.004666664211 0.0003333331579 0.0 1.18509471351 99.96658856 -0.4677602215 0.0 101299.9899 0.0 0.0 1.0 +-0.004666664211 0.0006666663158 0.0 1.18509471359 99.93945261 -0.4238317633 0.0 101299.9917 0.0 0.0 1.0 +-0.004666664211 0.0009999994737 0.0 1.1850947145 99.92294448 -0.3595924173 0.0 101299.9941 0.0 0.0 1.0 +-0.004666664211 0.001333332632 0.0 1.18509471356 99.91837817 -0.2856763965 0.0 101299.9962 0.0 0.0 1.0 +-0.004666664211 0.001666665789 0.0 1.1850947137 99.92410259 -0.2125127556 0.0 101299.9979 0.0 0.0 1.0 +-0.004666664211 0.001999998947 0.0 1.18509471422 99.93655964 -0.1480275175 0.0 101299.999 0.0 0.0 1.0 +-0.004666664211 0.002333332105 0.0 1.18509471424 99.95172562 -0.0965487641 0.0 101299.9996 0.0 0.0 1.0 +-0.004666664211 0.002666665263 0.0 1.1850947137 99.96630544 -0.05896547365 0.0 101299.9998 0.0 0.0 1.0 +-0.004666664211 0.002999998421 0.0 1.18509471323 99.97832245 -0.03372062952 0.0 101299.9999 0.0 0.0 1.0 +-0.004666664211 0.003333331579 0.0 1.18509471399 99.9871023 -0.01805678245 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.003666664737 0.0 1.18509471399 99.99288628 -0.009053820237 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.003999997895 0.0 1.18509471399 99.99635646 -0.004250795173 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.004333331053 0.0 1.18509471399 99.99826472 -0.001868767617 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.004666664211 0.0 1.18509471399 99.99923072 -0.0007692849398 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.004999997368 0.0 1.18509471399 99.99968229 -0.0002965281792 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.005333330526 0.0 1.18509471399 99.99987768 -0.0001070265487 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.005666663684 0.0 1.18509471399 99.99995608 -3.617128026e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.005999996842 0.0 1.18509471399 99.99998528 -1.144677246e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004666664211 0.00633333 0.0 1.18509471399 99.9999954 -3.391946777e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.00633333 0.0 1.18509471399 100.0000112 -7.651250397e-06 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.005999996842 0.0 1.18509471399 100.0000358 -2.582060631e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.005666663684 0.0 1.18509471399 100.0001067 -8.159194133e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.005333330526 0.0 1.18509471399 100.0002971 -0.0002414209234 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.004999997368 0.0 1.18509471399 100.0007718 -0.0006688817655 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.004666664211 0.0 1.18509471399 100.0018688 -0.001735284215 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.004333331053 0.0 1.18509471399 100.0042154 -0.004215398976 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.003999997895 0.0 1.18509471399 100.008851 -0.009588563852 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.003666664737 0.0 1.1850947144 100.0172808 -0.02042279854 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 -0.003333331579 0.0 1.18509471405 100.0313314 -0.0407308761 0.0 101299.9999 0.0 0.0 1.0 +-0.004333331053 -0.002999998421 0.0 1.18509471418 100.0526597 -0.07606398242 0.0 101299.9997 0.0 0.0 1.0 +-0.004333331053 -0.002666665263 0.0 1.18509471457 100.0818517 -0.1330090457 0.0 101299.9991 0.0 0.0 1.0 +-0.004333331053 -0.002333332105 0.0 1.18509471437 100.1172694 -0.2177860734 0.0 101299.9975 0.0 0.0 1.0 +-0.004333331053 -0.001999998947 0.0 1.1850947145 100.154111 -0.3339072446 0.0 101299.9941 0.0 0.0 1.0 +-0.004333331053 -0.001666665789 0.0 1.18509471329 100.184372 -0.4793672815 0.0 101299.9877 0.0 0.0 1.0 +-0.004333331053 -0.001333332632 0.0 1.18509471468 100.1982779 -0.6444032841 0.0 101299.9779 0.0 0.0 1.0 +-0.004333331053 -0.0009999994737 0.0 1.18509471402 100.1871853 -0.8111364378 0.0 101299.9649 0.0 0.0 1.0 +-0.004333331053 -0.0006666663158 0.0 1.18509471458 100.1470834 -0.9560418134 0.0 101299.9513 0.0 0.0 1.0 +-0.004333331053 -0.0003333331579 0.0 1.18509471367 100.081164 -1.055131703 0.0 101299.9406 0.0 0.0 1.0 +-0.004333331053 0.0 0.0 1.1850947142 100.0 -1.090393534 0.0 101299.9366 0.0 0.0 1.0 +-0.004333331053 0.0003333331579 0.0 1.18509471367 99.91883602 -1.055131703 0.0 101299.9406 0.0 0.0 1.0 +-0.004333331053 0.0006666663158 0.0 1.18509471458 99.85291664 -0.9560418134 0.0 101299.9513 0.0 0.0 1.0 +-0.004333331053 0.0009999994737 0.0 1.18509471402 99.81281467 -0.8111364378 0.0 101299.9649 0.0 0.0 1.0 +-0.004333331053 0.001333332632 0.0 1.18509471468 99.80172207 -0.6444032841 0.0 101299.9779 0.0 0.0 1.0 +-0.004333331053 0.001666665789 0.0 1.18509471329 99.81562797 -0.4793672815 0.0 101299.9877 0.0 0.0 1.0 +-0.004333331053 0.001999998947 0.0 1.1850947145 99.84588896 -0.3339072446 0.0 101299.9941 0.0 0.0 1.0 +-0.004333331053 0.002333332105 0.0 1.18509471437 99.88273058 -0.2177860734 0.0 101299.9975 0.0 0.0 1.0 +-0.004333331053 0.002666665263 0.0 1.18509471457 99.91814828 -0.1330090457 0.0 101299.9991 0.0 0.0 1.0 +-0.004333331053 0.002999998421 0.0 1.18509471418 99.94734032 -0.07606398242 0.0 101299.9997 0.0 0.0 1.0 +-0.004333331053 0.003333331579 0.0 1.18509471405 99.96866856 -0.0407308761 0.0 101299.9999 0.0 0.0 1.0 +-0.004333331053 0.003666664737 0.0 1.1850947144 99.98271917 -0.02042279854 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.003999997895 0.0 1.18509471399 99.99114902 -0.009588563852 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.004333331053 0.0 1.18509471399 99.9957846 -0.004215398976 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.004666664211 0.0 1.18509471399 99.99813123 -0.001735284215 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.004999997368 0.0 1.18509471399 99.99922821 -0.0006688817655 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.005333330526 0.0 1.18509471399 99.99970287 -0.0002414209234 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.005666663684 0.0 1.18509471399 99.9998933 -8.159194133e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.005999996842 0.0 1.18509471399 99.99996425 -2.582060631e-05 0.0 101300.0 0.0 0.0 1.0 +-0.004333331053 0.00633333 0.0 1.18509471399 99.99998882 -7.651250397e-06 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.00633333 0.0 1.18509471399 100.0000254 -1.60651649e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.005999996842 0.0 1.18509471399 100.0000813 -5.421496836e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.005666663684 0.0 1.18509471399 100.0002427 -0.0001713168338 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.005333330526 0.0 1.18509471399 100.0006759 -0.0005069062891 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.004999997368 0.0 1.18509471399 100.0017555 -0.00140443657 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.004666664211 0.0 1.18509471399 100.0042508 -0.003643538719 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.004333331053 0.0 1.18509471399 100.0095886 -0.008850982017 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.003999997895 0.0 1.1850947144 100.0201329 -0.02013290004 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 -0.003666664737 0.0 1.18509471405 100.0393079 -0.04288130819 0.0 101299.9999 0.0 0.0 1.0 +-0.003999997895 -0.003333331579 0.0 1.18509471349 100.0712681 -0.08552173923 0.0 101299.9995 0.0 0.0 1.0 +-0.003999997895 -0.002999998421 0.0 1.18509471379 100.1197824 -0.159709898 0.0 101299.9984 0.0 0.0 1.0 +-0.003999997895 -0.002666665263 0.0 1.18509471386 100.1861841 -0.2792762151 0.0 101299.9951 0.0 0.0 1.0 +-0.003999997895 -0.002333332105 0.0 1.18509471381 100.2667471 -0.4572807059 0.0 101299.9869 0.0 0.0 1.0 +-0.003999997895 -0.001999998947 0.0 1.18509471372 100.3505489 -0.7010978166 0.0 101299.9692 0.0 0.0 1.0 +-0.003999997895 -0.001666665789 0.0 1.1850947142 100.4193821 -1.006517109 0.0 101299.9366 0.0 0.0 1.0 +-0.003999997895 -0.001333332632 0.0 1.18509471394 100.4510132 -1.353039632 0.0 101299.8854 0.0 0.0 1.0 +-0.003999997895 -0.0009999994737 0.0 1.18509471435 100.4257814 -1.703125627 0.0 101299.8185 0.0 0.0 1.0 +-0.003999997895 -0.0006666663158 0.0 1.18509471393 100.3345634 -2.007380309 0.0 101299.7478 0.0 0.0 1.0 +-0.003999997895 -0.0003333331579 0.0 1.18509471406 100.1846198 -2.215437207 0.0 101299.6928 0.0 0.0 1.0 +-0.003999997895 0.0 0.0 1.18509471357 100.0 -2.28947571 0.0 101299.6719 0.0 0.0 1.0 +-0.003999997895 0.0003333331579 0.0 1.18509471406 99.81538023 -2.215437207 0.0 101299.6928 0.0 0.0 1.0 +-0.003999997895 0.0006666663158 0.0 1.18509471393 99.66543662 -2.007380309 0.0 101299.7478 0.0 0.0 1.0 +-0.003999997895 0.0009999994737 0.0 1.18509471435 99.57421859 -1.703125627 0.0 101299.8185 0.0 0.0 1.0 +-0.003999997895 0.001333332632 0.0 1.18509471394 99.54898679 -1.353039632 0.0 101299.8854 0.0 0.0 1.0 +-0.003999997895 0.001666665789 0.0 1.1850947142 99.58061787 -1.006517109 0.0 101299.9366 0.0 0.0 1.0 +-0.003999997895 0.001999998947 0.0 1.18509471372 99.64945109 -0.7010978166 0.0 101299.9692 0.0 0.0 1.0 +-0.003999997895 0.002333332105 0.0 1.18509471381 99.73325292 -0.4572807059 0.0 101299.9869 0.0 0.0 1.0 +-0.003999997895 0.002666665263 0.0 1.18509471386 99.81381586 -0.2792762151 0.0 101299.9951 0.0 0.0 1.0 +-0.003999997895 0.002999998421 0.0 1.18509471379 99.88021758 -0.159709898 0.0 101299.9984 0.0 0.0 1.0 +-0.003999997895 0.003333331579 0.0 1.18509471349 99.92873188 -0.08552173923 0.0 101299.9995 0.0 0.0 1.0 +-0.003999997895 0.003666664737 0.0 1.18509471405 99.96069213 -0.04288130819 0.0 101299.9999 0.0 0.0 1.0 +-0.003999997895 0.003999997895 0.0 1.1850947144 99.9798671 -0.02013290004 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.004333331053 0.0 1.18509471399 99.99041144 -0.008850982017 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.004666664211 0.0 1.18509471399 99.9957492 -0.003643538719 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.004999997368 0.0 1.18509471399 99.99824445 -0.00140443657 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.005333330526 0.0 1.18509471399 99.99932412 -0.0005069062891 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.005666663684 0.0 1.18509471399 99.9997573 -0.0001713168338 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.005999996842 0.0 1.18509471399 99.99991868 -5.421496836e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003999997895 0.00633333 0.0 1.18509471399 99.99997456 -1.60651649e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.00633333 0.0 1.18509471399 100.0000542 -3.136594059e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.005999996842 0.0 1.18509471399 100.0001732 -0.0001058503593 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.005666663684 0.0 1.18509471399 100.0005169 -0.0003344823201 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.005333330526 0.0 1.18509471399 100.0014396 -0.0009896937036 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.004999997368 0.0 1.18509471399 100.0037392 -0.00274204929 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.004666664211 0.0 1.18509471399 100.0090538 -0.007113715901 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.004333331053 0.0 1.1850947144 100.0204228 -0.01728082953 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 -0.003999997895 0.0 1.18509471405 100.0428813 -0.03930786584 0.0 101299.9999 0.0 0.0 1.0 +-0.003666664737 -0.003666664737 0.0 1.18509471431 100.0837223 -0.08372230061 0.0 101299.9995 0.0 0.0 1.0 +-0.003666664737 -0.003333331579 0.0 1.1850947137 100.1517948 -0.166974308 0.0 101299.9979 0.0 0.0 1.0 +-0.003666664737 -0.002999998421 0.0 1.18509471452 100.255126 -0.311820713 0.0 101299.9928 0.0 0.0 1.0 +-0.003666664737 -0.002666665263 0.0 1.18509471468 100.3965559 -0.5452643173 0.0 101299.9779 0.0 0.0 1.0 +-0.003666664737 -0.002333332105 0.0 1.18509471367 100.5681478 -0.8928037491 0.0 101299.9406 0.0 0.0 1.0 +-0.003666664737 -0.001999998947 0.0 1.18509471362 100.7466384 -1.368837021 0.0 101299.8604 0.0 0.0 1.0 +-0.003666664737 -0.001666665789 0.0 1.18509471457 100.8932471 -1.96514359 0.0 101299.7124 0.0 0.0 1.0 +-0.003666664737 -0.001333332632 0.0 1.18509471394 100.9606185 -2.641700909 0.0 101299.4802 0.0 0.0 1.0 +-0.003666664737 -0.0009999994737 0.0 1.18509471387 100.906877 -3.325215618 0.0 101299.1764 0.0 0.0 1.0 +-0.003666664737 -0.0006666663158 0.0 1.1850947143 100.7125906 -3.91924838 0.0 101298.8559 0.0 0.0 1.0 +-0.003666664737 -0.0003333331579 0.0 1.18509471373 100.3932239 -4.325462717 0.0 101298.6064 0.0 0.0 1.0 +-0.003666664737 0.0 0.0 1.185094714 100.0 -4.470016931 0.0 101298.5117 0.0 0.0 1.0 +-0.003666664737 0.0003333331579 0.0 1.18509471373 99.60677612 -4.325462717 0.0 101298.6064 0.0 0.0 1.0 +-0.003666664737 0.0006666663158 0.0 1.1850947143 99.28740939 -3.91924838 0.0 101298.8559 0.0 0.0 1.0 +-0.003666664737 0.0009999994737 0.0 1.18509471387 99.09312301 -3.325215618 0.0 101299.1764 0.0 0.0 1.0 +-0.003666664737 0.001333332632 0.0 1.18509471394 99.03938149 -2.641700909 0.0 101299.4802 0.0 0.0 1.0 +-0.003666664737 0.001666665789 0.0 1.18509471457 99.10675291 -1.96514359 0.0 101299.7124 0.0 0.0 1.0 +-0.003666664737 0.001999998947 0.0 1.18509471362 99.25336163 -1.368837021 0.0 101299.8604 0.0 0.0 1.0 +-0.003666664737 0.002333332105 0.0 1.18509471367 99.43185216 -0.8928037491 0.0 101299.9406 0.0 0.0 1.0 +-0.003666664737 0.002666665263 0.0 1.18509471468 99.60344413 -0.5452643173 0.0 101299.9779 0.0 0.0 1.0 +-0.003666664737 0.002999998421 0.0 1.18509471452 99.74487396 -0.311820713 0.0 101299.9928 0.0 0.0 1.0 +-0.003666664737 0.003333331579 0.0 1.1850947137 99.84820517 -0.166974308 0.0 101299.9979 0.0 0.0 1.0 +-0.003666664737 0.003666664737 0.0 1.18509471431 99.9162777 -0.08372230061 0.0 101299.9995 0.0 0.0 1.0 +-0.003666664737 0.003999997895 0.0 1.18509471405 99.95711869 -0.03930786584 0.0 101299.9999 0.0 0.0 1.0 +-0.003666664737 0.004333331053 0.0 1.1850947144 99.9795772 -0.01728082953 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.004666664211 0.0 1.18509471399 99.99094618 -0.007113715901 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.004999997368 0.0 1.18509471399 99.99626084 -0.00274204929 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.005333330526 0.0 1.18509471399 99.99856045 -0.0009896937036 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.005666663684 0.0 1.18509471399 99.99948307 -0.0003344823201 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.005999996842 0.0 1.18509471399 99.99982679 -0.0001058503593 0.0 101300.0 0.0 0.0 1.0 +-0.003666664737 0.00633333 0.0 1.18509471399 99.99994582 -3.136594059e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.00633333 0.0 1.18509471399 100.0001081 -5.686880845e-05 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.005999996842 0.0 1.18509471399 100.0003454 -0.0001919146594 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.005666663684 0.0 1.18509471399 100.001031 -0.0006064415935 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.005333330526 0.0 1.18509471399 100.002871 -0.001794389092 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.004999997368 0.0 1.18509471399 100.0074573 -0.004971541516 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.004666664211 0.0 1.18509471399 100.0180568 -0.01289770175 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 -0.004333331053 0.0 1.18509471405 100.0407309 -0.03133144316 0.0 101299.9999 0.0 0.0 1.0 +-0.003333331579 -0.003999997895 0.0 1.18509471349 100.0855217 -0.07126811602 0.0 101299.9995 0.0 0.0 1.0 +-0.003333331579 -0.003666664737 0.0 1.1850947137 100.1669743 -0.1517948254 0.0 101299.9979 0.0 0.0 1.0 +-0.003333331579 -0.003333331579 0.0 1.18509471359 100.302737 -0.3027369738 0.0 101299.9917 0.0 0.0 1.0 +-0.003333331579 -0.002999998421 0.0 1.18509471407 100.508819 -0.5653543959 0.0 101299.9712 0.0 0.0 1.0 +-0.003333331579 -0.002666665263 0.0 1.18509471369 100.7908842 -0.9886052014 0.0 101299.9119 0.0 0.0 1.0 +-0.003333331579 -0.002333332105 0.0 1.18509471347 101.1331042 -1.61872032 0.0 101299.7638 0.0 0.0 1.0 +-0.003333331579 -0.001999998947 0.0 1.1850947141 101.4890827 -2.481804431 0.0 101299.4449 0.0 0.0 1.0 +-0.003333331579 -0.001666665789 0.0 1.1850947143 101.7814765 -3.562953072 0.0 101298.8559 0.0 0.0 1.0 +-0.003333331579 -0.001333332632 0.0 1.18509471445 101.9158409 -4.789602356 0.0 101297.9325 0.0 0.0 1.0 +-0.003333331579 -0.0009999994737 0.0 1.18509471468 101.8086598 -6.028865913 0.0 101296.7242 0.0 0.0 1.0 +-0.003333331579 -0.0006666663158 0.0 1.18509471436 101.4211784 -7.10589197 0.0 101295.4492 0.0 0.0 1.0 +-0.003333331579 -0.0003333331579 0.0 1.18509471334 100.7842389 -7.842389102 0.0 101294.4569 0.0 0.0 1.0 +-0.003333331579 0.0 0.0 1.18509471462 100.0 -8.104476761 0.0 101294.0803 0.0 0.0 1.0 +-0.003333331579 0.0003333331579 0.0 1.18509471334 99.21576109 -7.842389102 0.0 101294.4569 0.0 0.0 1.0 +-0.003333331579 0.0006666663158 0.0 1.18509471436 98.57882161 -7.10589197 0.0 101295.4492 0.0 0.0 1.0 +-0.003333331579 0.0009999994737 0.0 1.18509471468 98.19134023 -6.028865913 0.0 101296.7242 0.0 0.0 1.0 +-0.003333331579 0.001333332632 0.0 1.18509471445 98.08415906 -4.789602356 0.0 101297.9325 0.0 0.0 1.0 +-0.003333331579 0.001666665789 0.0 1.1850947143 98.21852346 -3.562953072 0.0 101298.8559 0.0 0.0 1.0 +-0.003333331579 0.001999998947 0.0 1.1850947141 98.51091734 -2.481804431 0.0 101299.4449 0.0 0.0 1.0 +-0.003333331579 0.002333332105 0.0 1.18509471347 98.86689578 -1.61872032 0.0 101299.7638 0.0 0.0 1.0 +-0.003333331579 0.002666665263 0.0 1.18509471369 99.20911584 -0.9886052014 0.0 101299.9119 0.0 0.0 1.0 +-0.003333331579 0.002999998421 0.0 1.18509471407 99.49118104 -0.5653543959 0.0 101299.9712 0.0 0.0 1.0 +-0.003333331579 0.003333331579 0.0 1.18509471359 99.69726303 -0.3027369738 0.0 101299.9917 0.0 0.0 1.0 +-0.003333331579 0.003666664737 0.0 1.1850947137 99.83302569 -0.1517948254 0.0 101299.9979 0.0 0.0 1.0 +-0.003333331579 0.003999997895 0.0 1.18509471349 99.91447826 -0.07126811602 0.0 101299.9995 0.0 0.0 1.0 +-0.003333331579 0.004333331053 0.0 1.18509471405 99.95926912 -0.03133144316 0.0 101299.9999 0.0 0.0 1.0 +-0.003333331579 0.004666664211 0.0 1.18509471399 99.98194322 -0.01289770175 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 0.004999997368 0.0 1.18509471399 99.99254269 -0.004971541516 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 0.005333330526 0.0 1.18509471399 99.99712898 -0.001794389092 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 0.005666663684 0.0 1.18509471399 99.99896905 -0.0006064415935 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 0.005999996842 0.0 1.18509471399 99.99965455 -0.0001919146594 0.0 101300.0 0.0 0.0 1.0 +-0.003333331579 0.00633333 0.0 1.18509471399 99.99989195 -5.686880845e-05 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.00633333 0.0 1.18509471399 100.0002018 -9.558108281e-05 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.005999996842 0.0 1.18509471399 100.0006451 -0.0003225566256 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.005666663684 0.0 1.18509471399 100.0019253 -0.001019264264 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.005333330526 0.0 1.18509471399 100.0053616 -0.003015882644 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.004999997368 0.0 1.18509471399 100.0139264 -0.008355816383 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 -0.004666664211 0.0 1.18509471323 100.0337206 -0.02167754755 0.0 101299.9999 0.0 0.0 1.0 +-0.002999998421 -0.004333331053 0.0 1.18509471418 100.076064 -0.05265968014 0.0 101299.9997 0.0 0.0 1.0 +-0.002999998421 -0.003999997895 0.0 1.18509471379 100.1597099 -0.1197824235 0.0 101299.9984 0.0 0.0 1.0 +-0.002999998421 -0.003666664737 0.0 1.18509471452 100.3118207 -0.2551260379 0.0 101299.9928 0.0 0.0 1.0 +-0.002999998421 -0.003333331579 0.0 1.18509471407 100.5653544 -0.5088189563 0.0 101299.9712 0.0 0.0 1.0 +-0.002999998421 -0.002999998421 0.0 1.18509471347 100.9502078 -0.9502077994 0.0 101299.8995 0.0 0.0 1.0 +-0.002999998421 -0.002666665263 0.0 1.18509471406 101.4769581 -1.661577905 0.0 101299.6928 0.0 0.0 1.0 +-0.002999998421 -0.002333332105 0.0 1.18509471387 102.1160463 -2.72063096 0.0 101299.1764 0.0 0.0 1.0 +-0.002999998421 -0.001999998947 0.0 1.18509471347 102.7808279 -4.171241868 0.0 101298.064 0.0 0.0 1.0 +-0.002999998421 -0.001666665789 0.0 1.18509471392 103.3268668 -5.988360262 0.0 101296.0099 0.0 0.0 1.0 +-0.002999998421 -0.001333332632 0.0 1.18509471457 103.5777893 -8.050025873 0.0 101292.7896 0.0 0.0 1.0 +-0.002999998421 -0.0009999994737 0.0 1.18509471427 103.3776309 -10.13289267 0.0 101288.5756 0.0 0.0 1.0 +-0.002999998421 -0.0006666663158 0.0 1.18509471353 102.6540182 -11.94308211 0.0 101284.1291 0.0 0.0 1.0 +-0.002999998421 -0.0003333331579 0.0 1.18509471329 101.4645483 -13.18093455 0.0 101280.6687 0.0 0.0 1.0 +-0.002999998421 0.0 0.0 1.18509471445 100.0 -13.62143301 0.0 101279.3551 0.0 0.0 1.0 +-0.002999998421 0.0003333331579 0.0 1.18509471329 98.53545172 -13.18093455 0.0 101280.6687 0.0 0.0 1.0 +-0.002999998421 0.0006666663158 0.0 1.18509471353 97.34598175 -11.94308211 0.0 101284.1291 0.0 0.0 1.0 +-0.002999998421 0.0009999994737 0.0 1.18509471427 96.62236911 -10.13289267 0.0 101288.5756 0.0 0.0 1.0 +-0.002999998421 0.001333332632 0.0 1.18509471457 96.42221072 -8.050025873 0.0 101292.7896 0.0 0.0 1.0 +-0.002999998421 0.001666665789 0.0 1.18509471392 96.67313319 -5.988360262 0.0 101296.0099 0.0 0.0 1.0 +-0.002999998421 0.001999998947 0.0 1.18509471347 97.21917209 -4.171241868 0.0 101298.064 0.0 0.0 1.0 +-0.002999998421 0.002333332105 0.0 1.18509471387 97.8839537 -2.72063096 0.0 101299.1764 0.0 0.0 1.0 +-0.002999998421 0.002666665263 0.0 1.18509471406 98.52304186 -1.661577905 0.0 101299.6928 0.0 0.0 1.0 +-0.002999998421 0.002999998421 0.0 1.18509471347 99.0497922 -0.9502077994 0.0 101299.8995 0.0 0.0 1.0 +-0.002999998421 0.003333331579 0.0 1.18509471407 99.4346456 -0.5088189563 0.0 101299.9712 0.0 0.0 1.0 +-0.002999998421 0.003666664737 0.0 1.18509471452 99.68817929 -0.2551260379 0.0 101299.9928 0.0 0.0 1.0 +-0.002999998421 0.003999997895 0.0 1.18509471379 99.8402901 -0.1197824235 0.0 101299.9984 0.0 0.0 1.0 +-0.002999998421 0.004333331053 0.0 1.18509471418 99.92393602 -0.05265968014 0.0 101299.9997 0.0 0.0 1.0 +-0.002999998421 0.004666664211 0.0 1.18509471323 99.96627937 -0.02167754755 0.0 101299.9999 0.0 0.0 1.0 +-0.002999998421 0.004999997368 0.0 1.18509471399 99.98607364 -0.008355816383 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 0.005333330526 0.0 1.18509471399 99.99463843 -0.003015882644 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 0.005666663684 0.0 1.18509471399 99.99807472 -0.001019264264 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 0.005999996842 0.0 1.18509471399 99.99935489 -0.0003225566256 0.0 101300.0 0.0 0.0 1.0 +-0.002999998421 0.00633333 0.0 1.18509471399 99.99979822 -9.558108281e-05 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.00633333 0.0 1.18509471399 100.0003528 -0.0001485667221 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.005999996842 0.0 1.18509471399 100.0011281 -0.0005013667888 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.005666663684 0.0 1.18509471399 100.0033666 -0.001584296245 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.005333330526 0.0 1.18509471399 100.0093755 -0.004687745582 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.004999997368 0.0 1.1850947144 100.0243523 -0.01298788645 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 -0.004666664211 0.0 1.1850947137 100.0589655 -0.03369455637 0.0 101299.9998 0.0 0.0 1.0 +-0.002666665263 -0.004333331053 0.0 1.18509471457 100.133009 -0.0818517204 0.0 101299.9991 0.0 0.0 1.0 +-0.002666665263 -0.003999997895 0.0 1.18509471386 100.2792762 -0.1861841434 0.0 101299.9951 0.0 0.0 1.0 +-0.002666665263 -0.003666664737 0.0 1.18509471468 100.5452643 -0.3965558671 0.0 101299.9779 0.0 0.0 1.0 +-0.002666665263 -0.003333331579 0.0 1.18509471369 100.9886052 -0.7908841611 0.0 101299.9119 0.0 0.0 1.0 +-0.002666665263 -0.002999998421 0.0 1.18509471406 101.6615779 -1.476958138 0.0 101299.6928 0.0 0.0 1.0 +-0.002666665263 -0.002666665263 0.0 1.18509471412 102.5826782 -2.582678242 0.0 101299.0607 0.0 0.0 1.0 +-0.002666665263 -0.002333332105 0.0 1.18509471428 103.7002178 -4.228820306 0.0 101297.4817 0.0 0.0 1.0 +-0.002666665263 -0.001999998947 0.0 1.18509471462 104.8626861 -6.483581409 0.0 101294.0803 0.0 0.0 1.0 +-0.002666665263 -0.001666665789 0.0 1.18509471371 105.8175153 -9.308024442 0.0 101287.7992 0.0 0.0 1.0 +-0.002666665263 -0.001333332632 0.0 1.18509471369 106.2562901 -12.51258012 0.0 101277.9521 0.0 0.0 1.0 +-0.002666665263 -0.0009999994737 0.0 1.18509471439 105.9062837 -15.75008992 0.0 101265.0668 0.0 0.0 1.0 +-0.002666665263 -0.0006666663158 0.0 1.18509471379 104.6409407 -18.56376292 0.0 101251.4706 0.0 0.0 1.0 +-0.002666665263 -0.0003333331579 0.0 1.18509471339 102.5609778 -20.48782231 0.0 101240.8895 0.0 0.0 1.0 +-0.002666665263 0.0 0.0 1.18509471453 100.0 -21.17251231 0.0 101236.8727 0.0 0.0 1.0 +-0.002666665263 0.0003333331579 0.0 1.18509471339 97.43902221 -20.48782231 0.0 101240.8895 0.0 0.0 1.0 +-0.002666665263 0.0006666663158 0.0 1.18509471379 95.35905927 -18.56376292 0.0 101251.4706 0.0 0.0 1.0 +-0.002666665263 0.0009999994737 0.0 1.18509471439 94.09371628 -15.75008992 0.0 101265.0668 0.0 0.0 1.0 +-0.002666665263 0.001333332632 0.0 1.18509471369 93.74370994 -12.51258012 0.0 101277.9521 0.0 0.0 1.0 +-0.002666665263 0.001666665789 0.0 1.18509471371 94.18248472 -9.308024442 0.0 101287.7992 0.0 0.0 1.0 +-0.002666665263 0.001999998947 0.0 1.18509471462 95.13731394 -6.483581409 0.0 101294.0803 0.0 0.0 1.0 +-0.002666665263 0.002333332105 0.0 1.18509471428 96.29978223 -4.228820306 0.0 101297.4817 0.0 0.0 1.0 +-0.002666665263 0.002666665263 0.0 1.18509471412 97.41732176 -2.582678242 0.0 101299.0607 0.0 0.0 1.0 +-0.002666665263 0.002999998421 0.0 1.18509471406 98.33842209 -1.476958138 0.0 101299.6928 0.0 0.0 1.0 +-0.002666665263 0.003333331579 0.0 1.18509471369 99.0113948 -0.7908841611 0.0 101299.9119 0.0 0.0 1.0 +-0.002666665263 0.003666664737 0.0 1.18509471468 99.45473568 -0.3965558671 0.0 101299.9779 0.0 0.0 1.0 +-0.002666665263 0.003999997895 0.0 1.18509471386 99.72072378 -0.1861841434 0.0 101299.9951 0.0 0.0 1.0 +-0.002666665263 0.004333331053 0.0 1.18509471457 99.86699095 -0.0818517204 0.0 101299.9991 0.0 0.0 1.0 +-0.002666665263 0.004666664211 0.0 1.1850947137 99.94103453 -0.03369455637 0.0 101299.9998 0.0 0.0 1.0 +-0.002666665263 0.004999997368 0.0 1.1850947144 99.97564771 -0.01298788645 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 0.005333330526 0.0 1.18509471399 99.99062451 -0.004687745582 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 0.005666663684 0.0 1.18509471399 99.99663337 -0.001584296245 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 0.005999996842 0.0 1.18509471399 99.99887192 -0.0005013667888 0.0 101300.0 0.0 0.0 1.0 +-0.002666665263 0.00633333 0.0 1.18509471399 99.99964715 -0.0001485667221 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 -0.00633333 0.0 1.18509471399 100.0005777 -0.0002128523855 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 -0.005999996842 0.0 1.18509471399 100.0018471 -0.0007183110424 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 -0.005666663684 0.0 1.18509471399 100.0055124 -0.002269830218 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 -0.005333330526 0.0 1.18509471399 100.0153512 -0.006716159687 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 -0.004999997368 0.0 1.18509471364 100.0398739 -0.0186078186 0.0 101299.9999 0.0 0.0 1.0 +-0.002333332105 -0.004666664211 0.0 1.18509471424 100.0965488 -0.04827438205 0.0 101299.9996 0.0 0.0 1.0 +-0.002333332105 -0.004333331053 0.0 1.18509471437 100.2177861 -0.1172694241 0.0 101299.9975 0.0 0.0 1.0 +-0.002333332105 -0.003999997895 0.0 1.18509471381 100.4572807 -0.2667470784 0.0 101299.9869 0.0 0.0 1.0 +-0.002333332105 -0.003666664737 0.0 1.18509471367 100.8928037 -0.5681478403 0.0 101299.9406 0.0 0.0 1.0 +-0.002333332105 -0.003333331579 0.0 1.18509471347 101.6187203 -1.133104224 0.0 101299.7638 0.0 0.0 1.0 +-0.002333332105 -0.002999998421 0.0 1.18509471387 102.720631 -2.116046303 0.0 101299.1764 0.0 0.0 1.0 +-0.002333332105 -0.002666665263 0.0 1.18509471428 104.2288203 -3.700217768 0.0 101297.4817 0.0 0.0 1.0 +-0.002333332105 -0.002333332105 0.0 1.18509471451 106.0586548 -6.058654841 0.0 101293.2484 0.0 0.0 1.0 +-0.002333332105 -0.001999998947 0.0 1.18509471353 107.9620547 -9.289063863 0.0 101284.1291 0.0 0.0 1.0 +-0.002333332105 -0.001666665789 0.0 1.18509471361 109.525471 -13.33565942 0.0 101267.2896 0.0 0.0 1.0 +-0.002333332105 -0.001333332632 0.0 1.18509471339 110.2439112 -17.92684452 0.0 101240.8895 0.0 0.0 1.0 +-0.002333332105 -0.0009999994737 0.0 1.18509471453 109.6708185 -22.56524317 0.0 101206.3438 0.0 0.0 1.0 +-0.002333332105 -0.0006666663158 0.0 1.1850947141 107.5989738 -26.59640844 0.0 101169.8924 0.0 0.0 1.0 +-0.002333332105 -0.0003333331579 0.0 1.18509471415 104.1932885 -29.35301924 0.0 101141.5245 0.0 0.0 1.0 +-0.002333332105 0.0 0.0 1.18509471433 100.0 -30.33397849 0.0 101130.7552 0.0 0.0 1.0 +-0.002333332105 0.0003333331579 0.0 1.18509471415 95.80671154 -29.35301924 0.0 101141.5245 0.0 0.0 1.0 +-0.002333332105 0.0006666663158 0.0 1.1850947141 92.40102616 -26.59640844 0.0 101169.8924 0.0 0.0 1.0 +-0.002333332105 0.0009999994737 0.0 1.18509471453 90.3291815 -22.56524317 0.0 101206.3438 0.0 0.0 1.0 +-0.002333332105 0.001333332632 0.0 1.18509471339 89.75608884 -17.92684452 0.0 101240.8895 0.0 0.0 1.0 +-0.002333332105 0.001666665789 0.0 1.18509471361 90.47452899 -13.33565942 0.0 101267.2896 0.0 0.0 1.0 +-0.002333332105 0.001999998947 0.0 1.18509471353 92.03794526 -9.289063863 0.0 101284.1291 0.0 0.0 1.0 +-0.002333332105 0.002333332105 0.0 1.18509471451 93.94134516 -6.058654841 0.0 101293.2484 0.0 0.0 1.0 +-0.002333332105 0.002666665263 0.0 1.18509471428 95.77117969 -3.700217768 0.0 101297.4817 0.0 0.0 1.0 +-0.002333332105 0.002999998421 0.0 1.18509471387 97.27936904 -2.116046303 0.0 101299.1764 0.0 0.0 1.0 +-0.002333332105 0.003333331579 0.0 1.18509471347 98.38127968 -1.133104224 0.0 101299.7638 0.0 0.0 1.0 +-0.002333332105 0.003666664737 0.0 1.18509471367 99.10719625 -0.5681478403 0.0 101299.9406 0.0 0.0 1.0 +-0.002333332105 0.003999997895 0.0 1.18509471381 99.54271929 -0.2667470784 0.0 101299.9869 0.0 0.0 1.0 +-0.002333332105 0.004333331053 0.0 1.18509471437 99.78221393 -0.1172694241 0.0 101299.9975 0.0 0.0 1.0 +-0.002333332105 0.004666664211 0.0 1.18509471424 99.90345124 -0.04827438205 0.0 101299.9996 0.0 0.0 1.0 +-0.002333332105 0.004999997368 0.0 1.18509471364 99.9601261 -0.0186078186 0.0 101299.9999 0.0 0.0 1.0 +-0.002333332105 0.005333330526 0.0 1.18509471399 99.98464878 -0.006716159687 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 0.005666663684 0.0 1.18509471399 99.99448756 -0.002269830218 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 0.005999996842 0.0 1.18509471399 99.99815291 -0.0007183110424 0.0 101300.0 0.0 0.0 1.0 +-0.002333332105 0.00633333 0.0 1.18509471399 99.99942226 -0.0002128523855 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 -0.00633333 0.0 1.18509471399 100.0008858 -0.000279722544 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 -0.005999996842 0.0 1.18509471399 100.0028319 -0.0009439771682 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 -0.005666663684 0.0 1.18509471399 100.0084516 -0.002982924909 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 -0.005333330526 0.0 1.1850947144 100.0235363 -0.008826122708 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 -0.004999997368 0.0 1.18509471446 100.0611342 -0.02445369049 0.0 101299.9999 0.0 0.0 1.0 +-0.001999998947 -0.004666664211 0.0 1.18509471422 100.1480275 -0.06344036465 0.0 101299.999 0.0 0.0 1.0 +-0.001999998947 -0.004333331053 0.0 1.1850947145 100.3339072 -0.154111036 0.0 101299.9941 0.0 0.0 1.0 +-0.001999998947 -0.003999997895 0.0 1.18509471372 100.7010978 -0.3505489083 0.0 101299.9692 0.0 0.0 1.0 +-0.001999998947 -0.003666664737 0.0 1.18509471362 101.368837 -0.746638375 0.0 101299.8604 0.0 0.0 1.0 +-0.001999998947 -0.003333331579 0.0 1.1850947141 102.4818044 -1.489082658 0.0 101299.4449 0.0 0.0 1.0 +-0.001999998947 -0.002999998421 0.0 1.18509471347 104.1712419 -2.780827912 0.0 101298.064 0.0 0.0 1.0 +-0.001999998947 -0.002666665263 0.0 1.18509471462 106.4835814 -4.862686057 0.0 101294.0803 0.0 0.0 1.0 +-0.001999998947 -0.002333332105 0.0 1.18509471353 109.2890639 -7.96205474 0.0 101284.1291 0.0 0.0 1.0 +-0.001999998947 -0.001999998947 0.0 1.18509471442 112.2073359 -12.20733594 0.0 101262.6929 0.0 0.0 1.0 +-0.001999998947 -0.001666665789 0.0 1.18509471367 114.6043488 -17.52521856 0.0 101223.1087 0.0 0.0 1.0 +-0.001999998947 -0.001333332632 0.0 1.18509471434 115.7058534 -23.55878015 0.0 101161.0509 0.0 0.0 1.0 +-0.001999998947 -0.0009999994737 0.0 1.18509471396 114.827194 -29.65438799 0.0 101079.8452 0.0 0.0 1.0 +-0.001999998947 -0.0006666663158 0.0 1.18509471393 111.6506642 -34.95199272 0.0 100994.1601 0.0 0.0 1.0 +-0.001999998947 -0.0003333331579 0.0 1.18509471404 106.4291044 -38.57462624 0.0 100927.4765 0.0 0.0 1.0 +-0.001999998947 0.0 0.0 1.1850947134 100.0 -39.86376573 0.0 100902.1614 0.0 0.0 1.0 +-0.001999998947 0.0003333331579 0.0 1.18509471404 93.57089563 -38.57462624 0.0 100927.4765 0.0 0.0 1.0 +-0.001999998947 0.0006666663158 0.0 1.18509471393 88.34933576 -34.95199272 0.0 100994.1601 0.0 0.0 1.0 +-0.001999998947 0.0009999994737 0.0 1.18509471396 85.172806 -29.65438799 0.0 101079.8452 0.0 0.0 1.0 +-0.001999998947 0.001333332632 0.0 1.18509471434 84.29414657 -23.55878015 0.0 101161.0509 0.0 0.0 1.0 +-0.001999998947 0.001666665789 0.0 1.18509471367 85.3956512 -17.52521856 0.0 101223.1087 0.0 0.0 1.0 +-0.001999998947 0.001999998947 0.0 1.18509471442 87.79266406 -12.20733594 0.0 101262.6929 0.0 0.0 1.0 +-0.001999998947 0.002333332105 0.0 1.18509471353 90.71093614 -7.96205474 0.0 101284.1291 0.0 0.0 1.0 +-0.001999998947 0.002666665263 0.0 1.18509471462 93.51641859 -4.862686057 0.0 101294.0803 0.0 0.0 1.0 +-0.001999998947 0.002999998421 0.0 1.18509471347 95.82875813 -2.780827912 0.0 101298.064 0.0 0.0 1.0 +-0.001999998947 0.003333331579 0.0 1.1850947141 97.51819557 -1.489082658 0.0 101299.4449 0.0 0.0 1.0 +-0.001999998947 0.003666664737 0.0 1.18509471362 98.63116298 -0.746638375 0.0 101299.8604 0.0 0.0 1.0 +-0.001999998947 0.003999997895 0.0 1.18509471372 99.29890218 -0.3505489083 0.0 101299.9692 0.0 0.0 1.0 +-0.001999998947 0.004333331053 0.0 1.1850947145 99.66609276 -0.154111036 0.0 101299.9941 0.0 0.0 1.0 +-0.001999998947 0.004666664211 0.0 1.18509471422 99.85197248 -0.06344036465 0.0 101299.999 0.0 0.0 1.0 +-0.001999998947 0.004999997368 0.0 1.18509471446 99.93886577 -0.02445369049 0.0 101299.9999 0.0 0.0 1.0 +-0.001999998947 0.005333330526 0.0 1.1850947144 99.97646367 -0.008826122708 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 0.005666663684 0.0 1.18509471399 99.99154838 -0.002982924909 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 0.005999996842 0.0 1.18509471399 99.99716807 -0.0009439771682 0.0 101300.0 0.0 0.0 1.0 +-0.001999998947 0.00633333 0.0 1.18509471399 99.99911421 -0.000279722544 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 -0.00633333 0.0 1.18509471399 100.0012717 -0.0003346484132 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 -0.005999996842 0.0 1.18509471399 100.0040656 -0.001129335008 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 -0.005666663684 0.0 1.18509471399 100.0121334 -0.003568647251 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 -0.005333330526 0.0 1.1850947144 100.0337895 -0.01055920598 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 -0.004999997368 0.0 1.18509471418 100.0877661 -0.02925537785 0.0 101299.9997 0.0 0.0 1.0 +-0.001666665789 -0.004666664211 0.0 1.1850947137 100.2125128 -0.07589741271 0.0 101299.9979 0.0 0.0 1.0 +-0.001666665789 -0.004333331053 0.0 1.18509471329 100.4793673 -0.1843720314 0.0 101299.9877 0.0 0.0 1.0 +-0.001666665789 -0.003999997895 0.0 1.1850947142 101.0065171 -0.4193821286 0.0 101299.9366 0.0 0.0 1.0 +-0.001666665789 -0.003666664737 0.0 1.18509471457 101.9651436 -0.8932470864 0.0 101299.7124 0.0 0.0 1.0 +-0.001666665789 -0.003333331579 0.0 1.1850947143 103.5629531 -1.781476536 0.0 101298.8559 0.0 0.0 1.0 +-0.001666665789 -0.002999998421 0.0 1.18509471392 105.9883603 -3.326866812 0.0 101296.0099 0.0 0.0 1.0 +-0.001666665789 -0.002666665263 0.0 1.18509471371 109.3080244 -5.817515276 0.0 101287.7992 0.0 0.0 1.0 +-0.001666665789 -0.002333332105 0.0 1.18509471361 113.3356594 -9.525471014 0.0 101267.2896 0.0 0.0 1.0 +-0.001666665789 -0.001999998947 0.0 1.18509471367 117.5252186 -14.6043488 0.0 101223.1087 0.0 0.0 1.0 +-0.001666665789 -0.001666665789 0.0 1.18509471415 120.9664423 -20.96644232 0.0 101141.5245 0.0 0.0 1.0 +-0.001666665789 -0.001333332632 0.0 1.18509471432 122.5477955 -28.18474436 0.0 101013.6212 0.0 0.0 1.0 +-0.001666665789 -0.0009999994737 0.0 1.18509471372 121.2863656 -35.47727596 0.0 100846.2535 0.0 0.0 1.0 +-0.001666665789 -0.0006666663158 0.0 1.18509471422 116.7260439 -41.81510984 0.0 100669.6537 0.0 0.0 1.0 +-0.001666665789 -0.0003333331579 0.0 1.18509471413 109.2298156 -46.14907786 0.0 100532.2165 0.0 0.0 1.0 +-0.001666665789 0.0 0.0 1.18509471369 100.0 -47.6913507 0.0 100480.0413 0.0 0.0 1.0 +-0.001666665789 0.0003333331579 0.0 1.18509471413 90.77018443 -46.14907786 0.0 100532.2165 0.0 0.0 1.0 +-0.001666665789 0.0006666663158 0.0 1.18509471422 83.27395606 -41.81510984 0.0 100669.6537 0.0 0.0 1.0 +-0.001666665789 0.0009999994737 0.0 1.18509471372 78.71363442 -35.47727596 0.0 100846.2535 0.0 0.0 1.0 +-0.001666665789 0.001333332632 0.0 1.18509471432 77.45220451 -28.18474436 0.0 101013.6212 0.0 0.0 1.0 +-0.001666665789 0.001666665789 0.0 1.18509471415 79.03355768 -20.96644232 0.0 101141.5245 0.0 0.0 1.0 +-0.001666665789 0.001999998947 0.0 1.18509471367 82.47478144 -14.6043488 0.0 101223.1087 0.0 0.0 1.0 +-0.001666665789 0.002333332105 0.0 1.18509471361 86.66434058 -9.525471014 0.0 101267.2896 0.0 0.0 1.0 +-0.001666665789 0.002666665263 0.0 1.18509471371 90.69197556 -5.817515276 0.0 101287.7992 0.0 0.0 1.0 +-0.001666665789 0.002999998421 0.0 1.18509471392 94.01163974 -3.326866812 0.0 101296.0099 0.0 0.0 1.0 +-0.001666665789 0.003333331579 0.0 1.1850947143 96.43704693 -1.781476536 0.0 101298.8559 0.0 0.0 1.0 +-0.001666665789 0.003666664737 0.0 1.18509471457 98.03485641 -0.8932470864 0.0 101299.7124 0.0 0.0 1.0 +-0.001666665789 0.003999997895 0.0 1.1850947142 98.99348289 -0.4193821286 0.0 101299.9366 0.0 0.0 1.0 +-0.001666665789 0.004333331053 0.0 1.18509471329 99.52063272 -0.1843720314 0.0 101299.9877 0.0 0.0 1.0 +-0.001666665789 0.004666664211 0.0 1.1850947137 99.78748724 -0.07589741271 0.0 101299.9979 0.0 0.0 1.0 +-0.001666665789 0.004999997368 0.0 1.18509471418 99.91223387 -0.02925537785 0.0 101299.9997 0.0 0.0 1.0 +-0.001666665789 0.005333330526 0.0 1.1850947144 99.96621054 -0.01055920598 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 0.005666663684 0.0 1.18509471399 99.9878666 -0.003568647251 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 0.005999996842 0.0 1.18509471399 99.99593439 -0.001129335008 0.0 101300.0 0.0 0.0 1.0 +-0.001666665789 0.00633333 0.0 1.18509471399 99.99872834 -0.0003346484132 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 -0.00633333 0.0 1.18509471399 100.0017095 -0.0003598886195 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 -0.005999996842 0.0 1.18509471399 100.0054653 -0.001214512906 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 -0.005666663684 0.0 1.18509471399 100.0163107 -0.003837805536 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 -0.005333330526 0.0 1.18509471364 100.0454225 -0.01135561357 0.0 101299.9999 0.0 0.0 1.0 +-0.001333332632 -0.004999997368 0.0 1.18509471355 100.1179822 -0.03146190788 0.0 101299.9994 0.0 0.0 1.0 +-0.001333332632 -0.004666664211 0.0 1.18509471356 100.2856764 -0.08162182758 0.0 101299.9962 0.0 0.0 1.0 +-0.001333332632 -0.004333331053 0.0 1.18509471468 100.6444033 -0.1982779336 0.0 101299.9779 0.0 0.0 1.0 +-0.001333332632 -0.003999997895 0.0 1.18509471394 101.3530396 -0.4510132107 0.0 101299.8854 0.0 0.0 1.0 +-0.001333332632 -0.003666664737 0.0 1.18509471394 102.6417009 -0.9606185122 0.0 101299.4802 0.0 0.0 1.0 +-0.001333332632 -0.003333331579 0.0 1.18509471445 104.7896024 -1.915840942 0.0 101297.9325 0.0 0.0 1.0 +-0.001333332632 -0.002999998421 0.0 1.18509471457 108.0500259 -3.577789277 0.0 101292.7896 0.0 0.0 1.0 +-0.001333332632 -0.002666665263 0.0 1.18509471369 112.5125801 -6.256290062 0.0 101277.9521 0.0 0.0 1.0 +-0.001333332632 -0.002333332105 0.0 1.18509471339 117.9268445 -10.24391116 0.0 101240.8895 0.0 0.0 1.0 +-0.001333332632 -0.001999998947 0.0 1.18509471434 123.5587801 -15.70585343 0.0 101161.0509 0.0 0.0 1.0 +-0.001333332632 -0.001666665789 0.0 1.18509471432 128.1847444 -22.54779549 0.0 101013.6212 0.0 0.0 1.0 +-0.001333332632 -0.001333332632 0.0 1.18509471356 130.3105239 -30.31052394 0.0 100782.4889 0.0 0.0 1.0 +-0.001333332632 -0.0009999994737 0.0 1.18509471369 128.6148104 -38.15308056 0.0 100480.0413 0.0 0.0 1.0 +-0.001333332632 -0.0006666663158 0.0 1.1850947139 122.4844666 -44.96893325 0.0 100160.9103 0.0 0.0 1.0 +-0.001333332632 -0.0003333331579 0.0 1.18509471399 112.4074456 -49.62978238 0.0 99912.54951 0.0 0.0 1.0 +-0.001333332632 0.0 0.0 1.18509471399 100.0 -51.28837816 0.0 99818.2645 0.0 0.0 1.0 +-0.001333332632 0.0003333331579 0.0 1.18509471399 87.59255441 -49.62978238 0.0 99912.54951 0.0 0.0 1.0 +-0.001333332632 0.0006666663158 0.0 1.1850947139 77.51553337 -44.96893325 0.0 100160.9103 0.0 0.0 1.0 +-0.001333332632 0.0009999994737 0.0 1.18509471369 71.38518958 -38.15308056 0.0 100480.0413 0.0 0.0 1.0 +-0.001333332632 0.001333332632 0.0 1.18509471356 69.68947606 -30.31052394 0.0 100782.4889 0.0 0.0 1.0 +-0.001333332632 0.001666665789 0.0 1.18509471432 71.81525564 -22.54779549 0.0 101013.6212 0.0 0.0 1.0 +-0.001333332632 0.001999998947 0.0 1.18509471434 76.44121985 -15.70585343 0.0 101161.0509 0.0 0.0 1.0 +-0.001333332632 0.002333332105 0.0 1.18509471339 82.07315548 -10.24391116 0.0 101240.8895 0.0 0.0 1.0 +-0.001333332632 0.002666665263 0.0 1.18509471369 87.48741988 -6.256290062 0.0 101277.9521 0.0 0.0 1.0 +-0.001333332632 0.002999998421 0.0 1.18509471457 91.94997413 -3.577789277 0.0 101292.7896 0.0 0.0 1.0 +-0.001333332632 0.003333331579 0.0 1.18509471445 95.21039764 -1.915840942 0.0 101297.9325 0.0 0.0 1.0 +-0.001333332632 0.003666664737 0.0 1.18509471394 97.35829909 -0.9606185122 0.0 101299.4802 0.0 0.0 1.0 +-0.001333332632 0.003999997895 0.0 1.18509471394 98.64696037 -0.4510132107 0.0 101299.8854 0.0 0.0 1.0 +-0.001333332632 0.004333331053 0.0 1.18509471468 99.35559672 -0.1982779336 0.0 101299.9779 0.0 0.0 1.0 +-0.001333332632 0.004666664211 0.0 1.18509471356 99.7143236 -0.08162182758 0.0 101299.9962 0.0 0.0 1.0 +-0.001333332632 0.004999997368 0.0 1.18509471355 99.88201785 -0.03146190788 0.0 101299.9994 0.0 0.0 1.0 +-0.001333332632 0.005333330526 0.0 1.18509471364 99.95457755 -0.01135561357 0.0 101299.9999 0.0 0.0 1.0 +-0.001333332632 0.005666663684 0.0 1.18509471399 99.98368933 -0.003837805536 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 0.005999996842 0.0 1.18509471399 99.99453469 -0.001214512906 0.0 101300.0 0.0 0.0 1.0 +-0.001333332632 0.00633333 0.0 1.18509471399 99.99829053 -0.0003598886195 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 -0.00633333 0.0 1.18509471399 100.0021518 -0.0003397547545 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 -0.005999996842 0.0 1.18509471399 100.0068794 -0.001146567332 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 -0.005666663684 0.0 1.18509471399 100.0205309 -0.003623100613 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 -0.005333330526 0.0 1.18509471405 100.0571751 -0.01072032705 0.0 101299.9999 0.0 0.0 1.0 +-0.0009999994737 -0.004999997368 0.0 1.18509471374 100.1485089 -0.02970178053 0.0 101299.9991 0.0 0.0 1.0 +-0.0009999994737 -0.004666664211 0.0 1.1850947145 100.3595924 -0.077055518 0.0 101299.9941 0.0 0.0 1.0 +-0.0009999994737 -0.004333331053 0.0 1.18509471402 100.8111364 -0.1871853318 0.0 101299.9649 0.0 0.0 1.0 +-0.0009999994737 -0.003999997895 0.0 1.18509471435 101.7031256 -0.4257814068 0.0 101299.8185 0.0 0.0 1.0 +-0.0009999994737 -0.003666664737 0.0 1.18509471387 103.3252156 -0.9068769868 0.0 101299.1764 0.0 0.0 1.0 +-0.0009999994737 -0.003333331579 0.0 1.18509471468 106.0288659 -1.808659774 0.0 101296.7242 0.0 0.0 1.0 +-0.0009999994737 -0.002999998421 0.0 1.18509471427 110.1328927 -3.377630889 0.0 101288.5756 0.0 0.0 1.0 +-0.0009999994737 -0.002666665263 0.0 1.18509471439 115.7500899 -5.90628372 0.0 101265.0668 0.0 0.0 1.0 +-0.0009999994737 -0.002333332105 0.0 1.18509471453 122.5652432 -9.670818502 0.0 101206.3438 0.0 0.0 1.0 +-0.0009999994737 -0.001999998947 0.0 1.18509471396 129.654388 -14.827194 0.0 101079.8452 0.0 0.0 1.0 +-0.0009999994737 -0.001666665789 0.0 1.18509471372 135.477276 -21.28636558 0.0 100846.2535 0.0 0.0 1.0 +-0.0009999994737 -0.001333332632 0.0 1.18509471369 138.1530806 -28.61481042 0.0 100480.0413 0.0 0.0 1.0 +-0.0009999994737 -0.0009999994737 0.0 1.18509471366 136.0186175 -36.01861748 0.0 100000.835 0.0 0.0 1.0 +-0.0009999994737 -0.0006666663158 0.0 1.1850947139 128.3021062 -42.45315926 0.0 99495.19512 0.0 0.0 1.0 +-0.0009999994737 -0.0003333331579 0.0 1.18509471376 115.6177528 -46.85325853 0.0 99101.68548 0.0 0.0 1.0 +-0.0009999994737 0.0 0.0 1.18509471379 100.0 -48.41906465 0.0 98952.29774 0.0 0.0 1.0 +-0.0009999994737 0.0003333331579 0.0 1.18509471376 84.38224716 -46.85325853 0.0 99101.68548 0.0 0.0 1.0 +-0.0009999994737 0.0006666663158 0.0 1.1850947139 71.69789383 -42.45315926 0.0 99495.19512 0.0 0.0 1.0 +-0.0009999994737 0.0009999994737 0.0 1.18509471366 63.98138252 -36.01861748 0.0 100000.835 0.0 0.0 1.0 +-0.0009999994737 0.001333332632 0.0 1.18509471369 61.84691944 -28.61481042 0.0 100480.0413 0.0 0.0 1.0 +-0.0009999994737 0.001666665789 0.0 1.18509471372 64.52272404 -21.28636558 0.0 100846.2535 0.0 0.0 1.0 +-0.0009999994737 0.001999998947 0.0 1.18509471396 70.34561201 -14.827194 0.0 101079.8452 0.0 0.0 1.0 +-0.0009999994737 0.002333332105 0.0 1.18509471453 77.43475683 -9.670818502 0.0 101206.3438 0.0 0.0 1.0 +-0.0009999994737 0.002666665263 0.0 1.18509471439 84.24991008 -5.90628372 0.0 101265.0668 0.0 0.0 1.0 +-0.0009999994737 0.002999998421 0.0 1.18509471427 89.86710733 -3.377630889 0.0 101288.5756 0.0 0.0 1.0 +-0.0009999994737 0.003333331579 0.0 1.18509471468 93.97113409 -1.808659774 0.0 101296.7242 0.0 0.0 1.0 +-0.0009999994737 0.003666664737 0.0 1.18509471387 96.67478438 -0.9068769868 0.0 101299.1764 0.0 0.0 1.0 +-0.0009999994737 0.003999997895 0.0 1.18509471435 98.29687437 -0.4257814068 0.0 101299.8185 0.0 0.0 1.0 +-0.0009999994737 0.004333331053 0.0 1.18509471402 99.18886356 -0.1871853318 0.0 101299.9649 0.0 0.0 1.0 +-0.0009999994737 0.004666664211 0.0 1.1850947145 99.64040758 -0.077055518 0.0 101299.9941 0.0 0.0 1.0 +-0.0009999994737 0.004999997368 0.0 1.18509471374 99.8514911 -0.02970178053 0.0 101299.9991 0.0 0.0 1.0 +-0.0009999994737 0.005333330526 0.0 1.18509471405 99.94282492 -0.01072032705 0.0 101299.9999 0.0 0.0 1.0 +-0.0009999994737 0.005666663684 0.0 1.18509471399 99.9794691 -0.003623100613 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 0.005999996842 0.0 1.18509471399 99.9931206 -0.001146567332 0.0 101300.0 0.0 0.0 1.0 +-0.0009999994737 0.00633333 0.0 1.18509471399 99.99784822 -0.0003397547545 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 -0.00633333 0.0 1.18509471399 100.0025362 -0.0002669668024 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 -0.005999996842 0.0 1.18509471399 100.0081084 -0.0009009304811 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 -0.005666663684 0.0 1.1850947144 100.0241986 -0.002846899336 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 -0.005333330526 0.0 1.1850947137 100.0673891 -0.008423639093 0.0 101299.9998 0.0 0.0 1.0 +-0.0006666663158 -0.004999997368 0.0 1.18509471435 100.1750393 -0.02333856779 0.0 101299.9988 0.0 0.0 1.0 +-0.0006666663158 -0.004666664211 0.0 1.18509471359 100.4238318 -0.06054739476 0.0 101299.9917 0.0 0.0 1.0 +-0.0006666663158 -0.004333331053 0.0 1.18509471458 100.9560418 -0.1470833559 0.0 101299.9513 0.0 0.0 1.0 +-0.0006666663158 -0.003999997895 0.0 1.18509471393 102.0073803 -0.3345633848 0.0 101299.7478 0.0 0.0 1.0 +-0.0006666663158 -0.003666664737 0.0 1.1850947143 103.9192484 -0.7125906145 0.0 101298.8559 0.0 0.0 1.0 +-0.0006666663158 -0.003333331579 0.0 1.18509471436 107.105892 -1.421178394 0.0 101295.4492 0.0 0.0 1.0 +-0.0006666663158 -0.002999998421 0.0 1.18509471353 111.9430821 -2.654018247 0.0 101284.1291 0.0 0.0 1.0 +-0.0006666663158 -0.002666665263 0.0 1.18509471379 118.5637629 -4.64094073 0.0 101251.4706 0.0 0.0 1.0 +-0.0006666663158 -0.002333332105 0.0 1.1850947141 126.5964084 -7.598973841 0.0 101169.8924 0.0 0.0 1.0 +-0.0006666663158 -0.001999998947 0.0 1.18509471393 134.9519927 -11.65066424 0.0 100994.1601 0.0 0.0 1.0 +-0.0006666663158 -0.001666665789 0.0 1.18509471422 141.8151098 -16.72604394 0.0 100669.6537 0.0 0.0 1.0 +-0.0006666663158 -0.001333332632 0.0 1.1850947139 144.9689333 -22.48446663 0.0 100160.9103 0.0 0.0 1.0 +-0.0006666663158 -0.0009999994737 0.0 1.1850947139 142.4531593 -28.30210617 0.0 99495.19512 0.0 0.0 1.0 +-0.0006666663158 -0.0006666663158 0.0 1.1850947138 133.3581327 -33.35813267 0.0 98792.75826 0.0 0.0 1.0 +-0.0006666663158 -0.0003333331579 0.0 1.18509471383 118.4077845 -36.815569 0.0 98246.0932 0.0 0.0 1.0 +-0.0006666663158 0.0 0.0 1.18509471406 100.0 -38.04592192 0.0 98038.56318 0.0 0.0 1.0 +-0.0006666663158 0.0003333331579 0.0 1.18509471383 81.5922155 -36.815569 0.0 98246.0932 0.0 0.0 1.0 +-0.0006666663158 0.0006666663158 0.0 1.1850947138 66.64186733 -33.35813267 0.0 98792.75826 0.0 0.0 1.0 +-0.0006666663158 0.0009999994737 0.0 1.1850947139 57.54684074 -28.30210617 0.0 99495.19512 0.0 0.0 1.0 +-0.0006666663158 0.001333332632 0.0 1.1850947139 55.03106675 -22.48446663 0.0 100160.9103 0.0 0.0 1.0 +-0.0006666663158 0.001666665789 0.0 1.18509471422 58.18489016 -16.72604394 0.0 100669.6537 0.0 0.0 1.0 +-0.0006666663158 0.001999998947 0.0 1.18509471393 65.04800728 -11.65066424 0.0 100994.1601 0.0 0.0 1.0 +-0.0006666663158 0.002333332105 0.0 1.1850947141 73.40359156 -7.598973841 0.0 101169.8924 0.0 0.0 1.0 +-0.0006666663158 0.002666665263 0.0 1.18509471379 81.43623708 -4.64094073 0.0 101251.4706 0.0 0.0 1.0 +-0.0006666663158 0.002999998421 0.0 1.18509471353 88.05691789 -2.654018247 0.0 101284.1291 0.0 0.0 1.0 +-0.0006666663158 0.003333331579 0.0 1.18509471436 92.89410803 -1.421178394 0.0 101295.4492 0.0 0.0 1.0 +-0.0006666663158 0.003666664737 0.0 1.1850947143 96.08075162 -0.7125906145 0.0 101298.8559 0.0 0.0 1.0 +-0.0006666663158 0.003999997895 0.0 1.18509471393 97.99261969 -0.3345633848 0.0 101299.7478 0.0 0.0 1.0 +-0.0006666663158 0.004333331053 0.0 1.18509471458 99.04395819 -0.1470833559 0.0 101299.9513 0.0 0.0 1.0 +-0.0006666663158 0.004666664211 0.0 1.18509471359 99.57616824 -0.06054739476 0.0 101299.9917 0.0 0.0 1.0 +-0.0006666663158 0.004999997368 0.0 1.18509471435 99.82496074 -0.02333856779 0.0 101299.9988 0.0 0.0 1.0 +-0.0006666663158 0.005333330526 0.0 1.1850947137 99.93261089 -0.008423639093 0.0 101299.9998 0.0 0.0 1.0 +-0.0006666663158 0.005666663684 0.0 1.1850947144 99.97580136 -0.002846899336 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 0.005999996842 0.0 1.18509471399 99.99189163 -0.0009009304811 0.0 101300.0 0.0 0.0 1.0 +-0.0006666663158 0.00633333 0.0 1.18509471399 99.99746382 -0.0002669668024 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 -0.00633333 0.0 1.18509471399 100.002799 -0.000147318419 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 -0.005999996842 0.0 1.18509471399 100.0089488 -0.0004971541516 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 -0.005666663684 0.0 1.1850947144 100.0267067 -0.001570984503 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 -0.005333330526 0.0 1.18509471412 100.0743737 -0.004648357709 0.0 101299.9998 0.0 0.0 1.0 +-0.0003333331579 -0.004999997368 0.0 1.18509471372 100.1931814 -0.01287875825 0.0 101299.9985 0.0 0.0 1.0 +-0.0003333331579 -0.004666664211 0.0 1.18509471351 100.4677602 -0.0334114444 0.0 101299.9899 0.0 0.0 1.0 +-0.0003333331579 -0.004333331053 0.0 1.18509471367 101.0551317 -0.08116397719 0.0 101299.9406 0.0 0.0 1.0 +-0.0003333331579 -0.003999997895 0.0 1.18509471406 102.2154372 -0.1846197673 0.0 101299.6928 0.0 0.0 1.0 +-0.0003333331579 -0.003666664737 0.0 1.18509471373 104.3254627 -0.3932238833 0.0 101298.6064 0.0 0.0 1.0 +-0.0003333331579 -0.003333331579 0.0 1.18509471334 107.8423891 -0.7842389102 0.0 101294.4569 0.0 0.0 1.0 +-0.0003333331579 -0.002999998421 0.0 1.18509471329 113.1809346 -1.464548284 0.0 101280.6687 0.0 0.0 1.0 +-0.0003333331579 -0.002666665263 0.0 1.18509471339 120.4878223 -2.560977789 0.0 101240.8895 0.0 0.0 1.0 +-0.0003333331579 -0.002333332105 0.0 1.18509471415 129.3530192 -4.193288463 0.0 101141.5245 0.0 0.0 1.0 +-0.0003333331579 -0.001999998947 0.0 1.18509471404 138.5746262 -6.429104373 0.0 100927.4765 0.0 0.0 1.0 +-0.0003333331579 -0.001666665789 0.0 1.18509471413 146.1490779 -9.229815571 0.0 100532.2165 0.0 0.0 1.0 +-0.0003333331579 -0.001333332632 0.0 1.18509471399 149.6297824 -12.40744559 0.0 99912.54951 0.0 0.0 1.0 +-0.0003333331579 -0.0009999994737 0.0 1.18509471376 146.8532585 -15.61775284 0.0 99101.68548 0.0 0.0 1.0 +-0.0003333331579 -0.0006666663158 0.0 1.18509471383 136.815569 -18.4077845 0.0 98246.0932 0.0 0.0 1.0 +-0.0003333331579 -0.0003333331579 0.0 1.18509471388 120.3156774 -20.31567735 0.0 97580.23631 0.0 0.0 1.0 +-0.0003333331579 0.0 0.0 1.18509471387 100.0 -20.99461438 0.0 97327.4576 0.0 0.0 1.0 +-0.0003333331579 0.0003333331579 0.0 1.18509471388 79.68432265 -20.31567735 0.0 97580.23631 0.0 0.0 1.0 +-0.0003333331579 0.0006666663158 0.0 1.18509471383 63.184431 -18.4077845 0.0 98246.0932 0.0 0.0 1.0 +-0.0003333331579 0.0009999994737 0.0 1.18509471376 53.14674147 -15.61775284 0.0 99101.68548 0.0 0.0 1.0 +-0.0003333331579 0.001333332632 0.0 1.18509471399 50.37021762 -12.40744559 0.0 99912.54951 0.0 0.0 1.0 +-0.0003333331579 0.001666665789 0.0 1.18509471413 53.85092214 -9.229815571 0.0 100532.2165 0.0 0.0 1.0 +-0.0003333331579 0.001999998947 0.0 1.18509471404 61.42537376 -6.429104373 0.0 100927.4765 0.0 0.0 1.0 +-0.0003333331579 0.002333332105 0.0 1.18509471415 70.64698076 -4.193288463 0.0 101141.5245 0.0 0.0 1.0 +-0.0003333331579 0.002666665263 0.0 1.18509471339 79.51217769 -2.560977789 0.0 101240.8895 0.0 0.0 1.0 +-0.0003333331579 0.002999998421 0.0 1.18509471329 86.81906545 -1.464548284 0.0 101280.6687 0.0 0.0 1.0 +-0.0003333331579 0.003333331579 0.0 1.18509471334 92.1576109 -0.7842389102 0.0 101294.4569 0.0 0.0 1.0 +-0.0003333331579 0.003666664737 0.0 1.18509471373 95.67453728 -0.3932238833 0.0 101298.6064 0.0 0.0 1.0 +-0.0003333331579 0.003999997895 0.0 1.18509471406 97.78456279 -0.1846197673 0.0 101299.6928 0.0 0.0 1.0 +-0.0003333331579 0.004333331053 0.0 1.18509471367 98.9448683 -0.08116397719 0.0 101299.9406 0.0 0.0 1.0 +-0.0003333331579 0.004666664211 0.0 1.18509471351 99.53223978 -0.0334114444 0.0 101299.9899 0.0 0.0 1.0 +-0.0003333331579 0.004999997368 0.0 1.18509471372 99.80681863 -0.01287875825 0.0 101299.9985 0.0 0.0 1.0 +-0.0003333331579 0.005333330526 0.0 1.18509471412 99.92562628 -0.004648357709 0.0 101299.9998 0.0 0.0 1.0 +-0.0003333331579 0.005666663684 0.0 1.1850947144 99.97329326 -0.001570984503 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 0.005999996842 0.0 1.18509471399 99.99105123 -0.0004971541516 0.0 101300.0 0.0 0.0 1.0 +-0.0003333331579 0.00633333 0.0 1.18509471399 99.99720095 -0.000147318419 0.0 101300.0 0.0 0.0 1.0 +0.0 -0.00633333 0.0 1.18509471399 100.0028926 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0 -0.005999996842 0.0 1.18509471399 100.0092478 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0 -0.005666663684 0.0 1.1850947144 100.0275993 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0 -0.005333330526 0.0 1.18509471412 100.0768592 0.0 0.0 101299.9998 0.0 0.0 1.0 +0.0 -0.004999997368 0.0 1.18509471379 100.1996374 0.0 0.0 101299.9984 0.0 0.0 1.0 +0.0 -0.004666664211 0.0 1.18509471431 100.4833925 0.0 0.0 101299.9893 0.0 0.0 1.0 +0.0 -0.004333331053 0.0 1.1850947142 101.0903935 0.0 0.0 101299.9366 0.0 0.0 1.0 +0.0 -0.003999997895 0.0 1.18509471357 102.2894757 0.0 0.0 101299.6719 0.0 0.0 1.0 +0.0 -0.003666664737 0.0 1.185094714 104.4700169 0.0 0.0 101298.5117 0.0 0.0 1.0 +0.0 -0.003333331579 0.0 1.18509471462 108.1044768 0.0 0.0 101294.0803 0.0 0.0 1.0 +0.0 -0.002999998421 0.0 1.18509471445 113.621433 0.0 0.0 101279.3551 0.0 0.0 1.0 +0.0 -0.002666665263 0.0 1.18509471453 121.1725123 0.0 0.0 101236.8727 0.0 0.0 1.0 +0.0 -0.002333332105 0.0 1.18509471433 130.3339785 0.0 0.0 101130.7552 0.0 0.0 1.0 +0.0 -0.001999998947 0.0 1.1850947134 139.8637657 0.0 0.0 100902.1614 0.0 0.0 1.0 +0.0 -0.001666665789 0.0 1.18509471369 147.6913507 0.0 0.0 100480.0413 0.0 0.0 1.0 +0.0 -0.001333332632 0.0 1.18509471399 151.2883782 0.0 0.0 99818.2645 0.0 0.0 1.0 +0.0 -0.0009999994737 0.0 1.18509471379 148.4190646 0.0 0.0 98952.29774 0.0 0.0 1.0 +0.0 -0.0006666663158 0.0 1.18509471406 138.0459219 0.0 0.0 98038.56318 0.0 0.0 1.0 +0.0 -0.0003333331579 0.0 1.18509471387 120.9946144 0.0 0.0 97327.4576 0.0 0.0 1.0 +0.0 0.0 0.0 1.18509471406 100.0 0.0 0.0 97057.50117 0.0 0.0 1.0 +0.0 0.0003333331579 0.0 1.18509471387 79.00538562 0.0 0.0 97327.4576 0.0 0.0 1.0 +0.0 0.0006666663158 0.0 1.18509471406 61.95407808 0.0 0.0 98038.56318 0.0 0.0 1.0 +0.0 0.0009999994737 0.0 1.18509471379 51.58093535 0.0 0.0 98952.29774 0.0 0.0 1.0 +0.0 0.001333332632 0.0 1.18509471399 48.71162184 0.0 0.0 99818.2645 0.0 0.0 1.0 +0.0 0.001666665789 0.0 1.18509471369 52.3086493 0.0 0.0 100480.0413 0.0 0.0 1.0 +0.0 0.001999998947 0.0 1.1850947134 60.13623427 0.0 0.0 100902.1614 0.0 0.0 1.0 +0.0 0.002333332105 0.0 1.18509471433 69.66602151 0.0 0.0 101130.7552 0.0 0.0 1.0 +0.0 0.002666665263 0.0 1.18509471453 78.82748769 0.0 0.0 101236.8727 0.0 0.0 1.0 +0.0 0.002999998421 0.0 1.18509471445 86.37856699 0.0 0.0 101279.3551 0.0 0.0 1.0 +0.0 0.003333331579 0.0 1.18509471462 91.89552324 0.0 0.0 101294.0803 0.0 0.0 1.0 +0.0 0.003666664737 0.0 1.185094714 95.52998307 0.0 0.0 101298.5117 0.0 0.0 1.0 +0.0 0.003999997895 0.0 1.18509471357 97.71052429 0.0 0.0 101299.6719 0.0 0.0 1.0 +0.0 0.004333331053 0.0 1.1850947142 98.90960647 0.0 0.0 101299.9366 0.0 0.0 1.0 +0.0 0.004666664211 0.0 1.18509471431 99.51660753 0.0 0.0 101299.9893 0.0 0.0 1.0 +0.0 0.004999997368 0.0 1.18509471379 99.80036263 0.0 0.0 101299.9984 0.0 0.0 1.0 +0.0 0.005333330526 0.0 1.18509471412 99.92314075 0.0 0.0 101299.9998 0.0 0.0 1.0 +0.0 0.005666663684 0.0 1.1850947144 99.97240074 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0 0.005999996842 0.0 1.18509471399 99.99075216 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0 0.00633333 0.0 1.18509471399 99.99710741 0.0 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 -0.00633333 0.0 1.18509471399 100.002799 0.000147318419 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 -0.005999996842 0.0 1.18509471399 100.0089488 0.0004971541516 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 -0.005666663684 0.0 1.1850947144 100.0267067 0.001570984503 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 -0.005333330526 0.0 1.18509471412 100.0743737 0.004648357709 0.0 101299.9998 0.0 0.0 1.0 +0.0003333331579 -0.004999997368 0.0 1.18509471372 100.1931814 0.01287875825 0.0 101299.9985 0.0 0.0 1.0 +0.0003333331579 -0.004666664211 0.0 1.18509471351 100.4677602 0.0334114444 0.0 101299.9899 0.0 0.0 1.0 +0.0003333331579 -0.004333331053 0.0 1.18509471367 101.0551317 0.08116397719 0.0 101299.9406 0.0 0.0 1.0 +0.0003333331579 -0.003999997895 0.0 1.18509471406 102.2154372 0.1846197673 0.0 101299.6928 0.0 0.0 1.0 +0.0003333331579 -0.003666664737 0.0 1.18509471373 104.3254627 0.3932238833 0.0 101298.6064 0.0 0.0 1.0 +0.0003333331579 -0.003333331579 0.0 1.18509471334 107.8423891 0.7842389102 0.0 101294.4569 0.0 0.0 1.0 +0.0003333331579 -0.002999998421 0.0 1.18509471329 113.1809346 1.464548284 0.0 101280.6687 0.0 0.0 1.0 +0.0003333331579 -0.002666665263 0.0 1.18509471339 120.4878223 2.560977789 0.0 101240.8895 0.0 0.0 1.0 +0.0003333331579 -0.002333332105 0.0 1.18509471415 129.3530192 4.193288463 0.0 101141.5245 0.0 0.0 1.0 +0.0003333331579 -0.001999998947 0.0 1.18509471404 138.5746262 6.429104373 0.0 100927.4765 0.0 0.0 1.0 +0.0003333331579 -0.001666665789 0.0 1.18509471413 146.1490779 9.229815571 0.0 100532.2165 0.0 0.0 1.0 +0.0003333331579 -0.001333332632 0.0 1.18509471399 149.6297824 12.40744559 0.0 99912.54951 0.0 0.0 1.0 +0.0003333331579 -0.0009999994737 0.0 1.18509471376 146.8532585 15.61775284 0.0 99101.68548 0.0 0.0 1.0 +0.0003333331579 -0.0006666663158 0.0 1.18509471383 136.815569 18.4077845 0.0 98246.0932 0.0 0.0 1.0 +0.0003333331579 -0.0003333331579 0.0 1.18509471388 120.3156774 20.31567735 0.0 97580.23631 0.0 0.0 1.0 +0.0003333331579 0.0 0.0 1.18509471387 100.0 20.99461438 0.0 97327.4576 0.0 0.0 1.0 +0.0003333331579 0.0003333331579 0.0 1.18509471388 79.68432265 20.31567735 0.0 97580.23631 0.0 0.0 1.0 +0.0003333331579 0.0006666663158 0.0 1.18509471383 63.184431 18.4077845 0.0 98246.0932 0.0 0.0 1.0 +0.0003333331579 0.0009999994737 0.0 1.18509471376 53.14674147 15.61775284 0.0 99101.68548 0.0 0.0 1.0 +0.0003333331579 0.001333332632 0.0 1.18509471399 50.37021762 12.40744559 0.0 99912.54951 0.0 0.0 1.0 +0.0003333331579 0.001666665789 0.0 1.18509471413 53.85092214 9.229815571 0.0 100532.2165 0.0 0.0 1.0 +0.0003333331579 0.001999998947 0.0 1.18509471404 61.42537376 6.429104373 0.0 100927.4765 0.0 0.0 1.0 +0.0003333331579 0.002333332105 0.0 1.18509471415 70.64698076 4.193288463 0.0 101141.5245 0.0 0.0 1.0 +0.0003333331579 0.002666665263 0.0 1.18509471339 79.51217769 2.560977789 0.0 101240.8895 0.0 0.0 1.0 +0.0003333331579 0.002999998421 0.0 1.18509471329 86.81906545 1.464548284 0.0 101280.6687 0.0 0.0 1.0 +0.0003333331579 0.003333331579 0.0 1.18509471334 92.1576109 0.7842389102 0.0 101294.4569 0.0 0.0 1.0 +0.0003333331579 0.003666664737 0.0 1.18509471373 95.67453728 0.3932238833 0.0 101298.6064 0.0 0.0 1.0 +0.0003333331579 0.003999997895 0.0 1.18509471406 97.78456279 0.1846197673 0.0 101299.6928 0.0 0.0 1.0 +0.0003333331579 0.004333331053 0.0 1.18509471367 98.9448683 0.08116397719 0.0 101299.9406 0.0 0.0 1.0 +0.0003333331579 0.004666664211 0.0 1.18509471351 99.53223978 0.0334114444 0.0 101299.9899 0.0 0.0 1.0 +0.0003333331579 0.004999997368 0.0 1.18509471372 99.80681863 0.01287875825 0.0 101299.9985 0.0 0.0 1.0 +0.0003333331579 0.005333330526 0.0 1.18509471412 99.92562628 0.004648357709 0.0 101299.9998 0.0 0.0 1.0 +0.0003333331579 0.005666663684 0.0 1.1850947144 99.97329326 0.001570984503 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 0.005999996842 0.0 1.18509471399 99.99105123 0.0004971541516 0.0 101300.0 0.0 0.0 1.0 +0.0003333331579 0.00633333 0.0 1.18509471399 99.99720095 0.000147318419 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 -0.00633333 0.0 1.18509471399 100.0025362 0.0002669668024 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 -0.005999996842 0.0 1.18509471399 100.0081084 0.0009009304811 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 -0.005666663684 0.0 1.1850947144 100.0241986 0.002846899336 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 -0.005333330526 0.0 1.1850947137 100.0673891 0.008423639093 0.0 101299.9998 0.0 0.0 1.0 +0.0006666663158 -0.004999997368 0.0 1.18509471435 100.1750393 0.02333856779 0.0 101299.9988 0.0 0.0 1.0 +0.0006666663158 -0.004666664211 0.0 1.18509471359 100.4238318 0.06054739476 0.0 101299.9917 0.0 0.0 1.0 +0.0006666663158 -0.004333331053 0.0 1.18509471458 100.9560418 0.1470833559 0.0 101299.9513 0.0 0.0 1.0 +0.0006666663158 -0.003999997895 0.0 1.18509471393 102.0073803 0.3345633848 0.0 101299.7478 0.0 0.0 1.0 +0.0006666663158 -0.003666664737 0.0 1.1850947143 103.9192484 0.7125906145 0.0 101298.8559 0.0 0.0 1.0 +0.0006666663158 -0.003333331579 0.0 1.18509471436 107.105892 1.421178394 0.0 101295.4492 0.0 0.0 1.0 +0.0006666663158 -0.002999998421 0.0 1.18509471353 111.9430821 2.654018247 0.0 101284.1291 0.0 0.0 1.0 +0.0006666663158 -0.002666665263 0.0 1.18509471379 118.5637629 4.64094073 0.0 101251.4706 0.0 0.0 1.0 +0.0006666663158 -0.002333332105 0.0 1.1850947141 126.5964084 7.598973841 0.0 101169.8924 0.0 0.0 1.0 +0.0006666663158 -0.001999998947 0.0 1.18509471393 134.9519927 11.65066424 0.0 100994.1601 0.0 0.0 1.0 +0.0006666663158 -0.001666665789 0.0 1.18509471422 141.8151098 16.72604394 0.0 100669.6537 0.0 0.0 1.0 +0.0006666663158 -0.001333332632 0.0 1.1850947139 144.9689333 22.48446663 0.0 100160.9103 0.0 0.0 1.0 +0.0006666663158 -0.0009999994737 0.0 1.1850947139 142.4531593 28.30210617 0.0 99495.19512 0.0 0.0 1.0 +0.0006666663158 -0.0006666663158 0.0 1.1850947138 133.3581327 33.35813267 0.0 98792.75826 0.0 0.0 1.0 +0.0006666663158 -0.0003333331579 0.0 1.18509471383 118.4077845 36.815569 0.0 98246.0932 0.0 0.0 1.0 +0.0006666663158 0.0 0.0 1.18509471406 100.0 38.04592192 0.0 98038.56318 0.0 0.0 1.0 +0.0006666663158 0.0003333331579 0.0 1.18509471383 81.5922155 36.815569 0.0 98246.0932 0.0 0.0 1.0 +0.0006666663158 0.0006666663158 0.0 1.1850947138 66.64186733 33.35813267 0.0 98792.75826 0.0 0.0 1.0 +0.0006666663158 0.0009999994737 0.0 1.1850947139 57.54684074 28.30210617 0.0 99495.19512 0.0 0.0 1.0 +0.0006666663158 0.001333332632 0.0 1.1850947139 55.03106675 22.48446663 0.0 100160.9103 0.0 0.0 1.0 +0.0006666663158 0.001666665789 0.0 1.18509471422 58.18489016 16.72604394 0.0 100669.6537 0.0 0.0 1.0 +0.0006666663158 0.001999998947 0.0 1.18509471393 65.04800728 11.65066424 0.0 100994.1601 0.0 0.0 1.0 +0.0006666663158 0.002333332105 0.0 1.1850947141 73.40359156 7.598973841 0.0 101169.8924 0.0 0.0 1.0 +0.0006666663158 0.002666665263 0.0 1.18509471379 81.43623708 4.64094073 0.0 101251.4706 0.0 0.0 1.0 +0.0006666663158 0.002999998421 0.0 1.18509471353 88.05691789 2.654018247 0.0 101284.1291 0.0 0.0 1.0 +0.0006666663158 0.003333331579 0.0 1.18509471436 92.89410803 1.421178394 0.0 101295.4492 0.0 0.0 1.0 +0.0006666663158 0.003666664737 0.0 1.1850947143 96.08075162 0.7125906145 0.0 101298.8559 0.0 0.0 1.0 +0.0006666663158 0.003999997895 0.0 1.18509471393 97.99261969 0.3345633848 0.0 101299.7478 0.0 0.0 1.0 +0.0006666663158 0.004333331053 0.0 1.18509471458 99.04395819 0.1470833559 0.0 101299.9513 0.0 0.0 1.0 +0.0006666663158 0.004666664211 0.0 1.18509471359 99.57616824 0.06054739476 0.0 101299.9917 0.0 0.0 1.0 +0.0006666663158 0.004999997368 0.0 1.18509471435 99.82496074 0.02333856779 0.0 101299.9988 0.0 0.0 1.0 +0.0006666663158 0.005333330526 0.0 1.1850947137 99.93261089 0.008423639093 0.0 101299.9998 0.0 0.0 1.0 +0.0006666663158 0.005666663684 0.0 1.1850947144 99.97580136 0.002846899336 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 0.005999996842 0.0 1.18509471399 99.99189163 0.0009009304811 0.0 101300.0 0.0 0.0 1.0 +0.0006666663158 0.00633333 0.0 1.18509471399 99.99746382 0.0002669668024 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 -0.00633333 0.0 1.18509471399 100.0021518 0.0003397547545 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 -0.005999996842 0.0 1.18509471399 100.0068794 0.001146567332 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 -0.005666663684 0.0 1.18509471399 100.0205309 0.003623100613 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 -0.005333330526 0.0 1.18509471405 100.0571751 0.01072032705 0.0 101299.9999 0.0 0.0 1.0 +0.0009999994737 -0.004999997368 0.0 1.18509471374 100.1485089 0.02970178053 0.0 101299.9991 0.0 0.0 1.0 +0.0009999994737 -0.004666664211 0.0 1.1850947145 100.3595924 0.077055518 0.0 101299.9941 0.0 0.0 1.0 +0.0009999994737 -0.004333331053 0.0 1.18509471402 100.8111364 0.1871853318 0.0 101299.9649 0.0 0.0 1.0 +0.0009999994737 -0.003999997895 0.0 1.18509471435 101.7031256 0.4257814068 0.0 101299.8185 0.0 0.0 1.0 +0.0009999994737 -0.003666664737 0.0 1.18509471387 103.3252156 0.9068769868 0.0 101299.1764 0.0 0.0 1.0 +0.0009999994737 -0.003333331579 0.0 1.18509471468 106.0288659 1.808659774 0.0 101296.7242 0.0 0.0 1.0 +0.0009999994737 -0.002999998421 0.0 1.18509471427 110.1328927 3.377630889 0.0 101288.5756 0.0 0.0 1.0 +0.0009999994737 -0.002666665263 0.0 1.18509471439 115.7500899 5.90628372 0.0 101265.0668 0.0 0.0 1.0 +0.0009999994737 -0.002333332105 0.0 1.18509471453 122.5652432 9.670818502 0.0 101206.3438 0.0 0.0 1.0 +0.0009999994737 -0.001999998947 0.0 1.18509471396 129.654388 14.827194 0.0 101079.8452 0.0 0.0 1.0 +0.0009999994737 -0.001666665789 0.0 1.18509471372 135.477276 21.28636558 0.0 100846.2535 0.0 0.0 1.0 +0.0009999994737 -0.001333332632 0.0 1.18509471369 138.1530806 28.61481042 0.0 100480.0413 0.0 0.0 1.0 +0.0009999994737 -0.0009999994737 0.0 1.18509471366 136.0186175 36.01861748 0.0 100000.835 0.0 0.0 1.0 +0.0009999994737 -0.0006666663158 0.0 1.1850947139 128.3021062 42.45315926 0.0 99495.19512 0.0 0.0 1.0 +0.0009999994737 -0.0003333331579 0.0 1.18509471376 115.6177528 46.85325853 0.0 99101.68548 0.0 0.0 1.0 +0.0009999994737 0.0 0.0 1.18509471379 100.0 48.41906465 0.0 98952.29774 0.0 0.0 1.0 +0.0009999994737 0.0003333331579 0.0 1.18509471376 84.38224716 46.85325853 0.0 99101.68548 0.0 0.0 1.0 +0.0009999994737 0.0006666663158 0.0 1.1850947139 71.69789383 42.45315926 0.0 99495.19512 0.0 0.0 1.0 +0.0009999994737 0.0009999994737 0.0 1.18509471366 63.98138252 36.01861748 0.0 100000.835 0.0 0.0 1.0 +0.0009999994737 0.001333332632 0.0 1.18509471369 61.84691944 28.61481042 0.0 100480.0413 0.0 0.0 1.0 +0.0009999994737 0.001666665789 0.0 1.18509471372 64.52272404 21.28636558 0.0 100846.2535 0.0 0.0 1.0 +0.0009999994737 0.001999998947 0.0 1.18509471396 70.34561201 14.827194 0.0 101079.8452 0.0 0.0 1.0 +0.0009999994737 0.002333332105 0.0 1.18509471453 77.43475683 9.670818502 0.0 101206.3438 0.0 0.0 1.0 +0.0009999994737 0.002666665263 0.0 1.18509471439 84.24991008 5.90628372 0.0 101265.0668 0.0 0.0 1.0 +0.0009999994737 0.002999998421 0.0 1.18509471427 89.86710733 3.377630889 0.0 101288.5756 0.0 0.0 1.0 +0.0009999994737 0.003333331579 0.0 1.18509471468 93.97113409 1.808659774 0.0 101296.7242 0.0 0.0 1.0 +0.0009999994737 0.003666664737 0.0 1.18509471387 96.67478438 0.9068769868 0.0 101299.1764 0.0 0.0 1.0 +0.0009999994737 0.003999997895 0.0 1.18509471435 98.29687437 0.4257814068 0.0 101299.8185 0.0 0.0 1.0 +0.0009999994737 0.004333331053 0.0 1.18509471402 99.18886356 0.1871853318 0.0 101299.9649 0.0 0.0 1.0 +0.0009999994737 0.004666664211 0.0 1.1850947145 99.64040758 0.077055518 0.0 101299.9941 0.0 0.0 1.0 +0.0009999994737 0.004999997368 0.0 1.18509471374 99.8514911 0.02970178053 0.0 101299.9991 0.0 0.0 1.0 +0.0009999994737 0.005333330526 0.0 1.18509471405 99.94282492 0.01072032705 0.0 101299.9999 0.0 0.0 1.0 +0.0009999994737 0.005666663684 0.0 1.18509471399 99.9794691 0.003623100613 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 0.005999996842 0.0 1.18509471399 99.9931206 0.001146567332 0.0 101300.0 0.0 0.0 1.0 +0.0009999994737 0.00633333 0.0 1.18509471399 99.99784822 0.0003397547545 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 -0.00633333 0.0 1.18509471399 100.0017095 0.0003598886195 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 -0.005999996842 0.0 1.18509471399 100.0054653 0.001214512906 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 -0.005666663684 0.0 1.18509471399 100.0163107 0.003837805536 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 -0.005333330526 0.0 1.18509471364 100.0454225 0.01135561357 0.0 101299.9999 0.0 0.0 1.0 +0.001333332632 -0.004999997368 0.0 1.18509471355 100.1179822 0.03146190788 0.0 101299.9994 0.0 0.0 1.0 +0.001333332632 -0.004666664211 0.0 1.18509471356 100.2856764 0.08162182758 0.0 101299.9962 0.0 0.0 1.0 +0.001333332632 -0.004333331053 0.0 1.18509471468 100.6444033 0.1982779336 0.0 101299.9779 0.0 0.0 1.0 +0.001333332632 -0.003999997895 0.0 1.18509471394 101.3530396 0.4510132107 0.0 101299.8854 0.0 0.0 1.0 +0.001333332632 -0.003666664737 0.0 1.18509471394 102.6417009 0.9606185122 0.0 101299.4802 0.0 0.0 1.0 +0.001333332632 -0.003333331579 0.0 1.18509471445 104.7896024 1.915840942 0.0 101297.9325 0.0 0.0 1.0 +0.001333332632 -0.002999998421 0.0 1.18509471457 108.0500259 3.577789277 0.0 101292.7896 0.0 0.0 1.0 +0.001333332632 -0.002666665263 0.0 1.18509471369 112.5125801 6.256290062 0.0 101277.9521 0.0 0.0 1.0 +0.001333332632 -0.002333332105 0.0 1.18509471339 117.9268445 10.24391116 0.0 101240.8895 0.0 0.0 1.0 +0.001333332632 -0.001999998947 0.0 1.18509471434 123.5587801 15.70585343 0.0 101161.0509 0.0 0.0 1.0 +0.001333332632 -0.001666665789 0.0 1.18509471432 128.1847444 22.54779549 0.0 101013.6212 0.0 0.0 1.0 +0.001333332632 -0.001333332632 0.0 1.18509471356 130.3105239 30.31052394 0.0 100782.4889 0.0 0.0 1.0 +0.001333332632 -0.0009999994737 0.0 1.18509471369 128.6148104 38.15308056 0.0 100480.0413 0.0 0.0 1.0 +0.001333332632 -0.0006666663158 0.0 1.1850947139 122.4844666 44.96893325 0.0 100160.9103 0.0 0.0 1.0 +0.001333332632 -0.0003333331579 0.0 1.18509471399 112.4074456 49.62978238 0.0 99912.54951 0.0 0.0 1.0 +0.001333332632 0.0 0.0 1.18509471399 100.0 51.28837816 0.0 99818.2645 0.0 0.0 1.0 +0.001333332632 0.0003333331579 0.0 1.18509471399 87.59255441 49.62978238 0.0 99912.54951 0.0 0.0 1.0 +0.001333332632 0.0006666663158 0.0 1.1850947139 77.51553337 44.96893325 0.0 100160.9103 0.0 0.0 1.0 +0.001333332632 0.0009999994737 0.0 1.18509471369 71.38518958 38.15308056 0.0 100480.0413 0.0 0.0 1.0 +0.001333332632 0.001333332632 0.0 1.18509471356 69.68947606 30.31052394 0.0 100782.4889 0.0 0.0 1.0 +0.001333332632 0.001666665789 0.0 1.18509471432 71.81525564 22.54779549 0.0 101013.6212 0.0 0.0 1.0 +0.001333332632 0.001999998947 0.0 1.18509471434 76.44121985 15.70585343 0.0 101161.0509 0.0 0.0 1.0 +0.001333332632 0.002333332105 0.0 1.18509471339 82.07315548 10.24391116 0.0 101240.8895 0.0 0.0 1.0 +0.001333332632 0.002666665263 0.0 1.18509471369 87.48741988 6.256290062 0.0 101277.9521 0.0 0.0 1.0 +0.001333332632 0.002999998421 0.0 1.18509471457 91.94997413 3.577789277 0.0 101292.7896 0.0 0.0 1.0 +0.001333332632 0.003333331579 0.0 1.18509471445 95.21039764 1.915840942 0.0 101297.9325 0.0 0.0 1.0 +0.001333332632 0.003666664737 0.0 1.18509471394 97.35829909 0.9606185122 0.0 101299.4802 0.0 0.0 1.0 +0.001333332632 0.003999997895 0.0 1.18509471394 98.64696037 0.4510132107 0.0 101299.8854 0.0 0.0 1.0 +0.001333332632 0.004333331053 0.0 1.18509471468 99.35559672 0.1982779336 0.0 101299.9779 0.0 0.0 1.0 +0.001333332632 0.004666664211 0.0 1.18509471356 99.7143236 0.08162182758 0.0 101299.9962 0.0 0.0 1.0 +0.001333332632 0.004999997368 0.0 1.18509471355 99.88201785 0.03146190788 0.0 101299.9994 0.0 0.0 1.0 +0.001333332632 0.005333330526 0.0 1.18509471364 99.95457755 0.01135561357 0.0 101299.9999 0.0 0.0 1.0 +0.001333332632 0.005666663684 0.0 1.18509471399 99.98368933 0.003837805536 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 0.005999996842 0.0 1.18509471399 99.99453469 0.001214512906 0.0 101300.0 0.0 0.0 1.0 +0.001333332632 0.00633333 0.0 1.18509471399 99.99829053 0.0003598886195 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 -0.00633333 0.0 1.18509471399 100.0012717 0.0003346484132 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 -0.005999996842 0.0 1.18509471399 100.0040656 0.001129335008 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 -0.005666663684 0.0 1.18509471399 100.0121334 0.003568647251 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 -0.005333330526 0.0 1.1850947144 100.0337895 0.01055920598 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 -0.004999997368 0.0 1.18509471418 100.0877661 0.02925537785 0.0 101299.9997 0.0 0.0 1.0 +0.001666665789 -0.004666664211 0.0 1.1850947137 100.2125128 0.07589741271 0.0 101299.9979 0.0 0.0 1.0 +0.001666665789 -0.004333331053 0.0 1.18509471329 100.4793673 0.1843720314 0.0 101299.9877 0.0 0.0 1.0 +0.001666665789 -0.003999997895 0.0 1.1850947142 101.0065171 0.4193821286 0.0 101299.9366 0.0 0.0 1.0 +0.001666665789 -0.003666664737 0.0 1.18509471457 101.9651436 0.8932470864 0.0 101299.7124 0.0 0.0 1.0 +0.001666665789 -0.003333331579 0.0 1.1850947143 103.5629531 1.781476536 0.0 101298.8559 0.0 0.0 1.0 +0.001666665789 -0.002999998421 0.0 1.18509471392 105.9883603 3.326866812 0.0 101296.0099 0.0 0.0 1.0 +0.001666665789 -0.002666665263 0.0 1.18509471371 109.3080244 5.817515276 0.0 101287.7992 0.0 0.0 1.0 +0.001666665789 -0.002333332105 0.0 1.18509471361 113.3356594 9.525471014 0.0 101267.2896 0.0 0.0 1.0 +0.001666665789 -0.001999998947 0.0 1.18509471367 117.5252186 14.6043488 0.0 101223.1087 0.0 0.0 1.0 +0.001666665789 -0.001666665789 0.0 1.18509471415 120.9664423 20.96644232 0.0 101141.5245 0.0 0.0 1.0 +0.001666665789 -0.001333332632 0.0 1.18509471432 122.5477955 28.18474436 0.0 101013.6212 0.0 0.0 1.0 +0.001666665789 -0.0009999994737 0.0 1.18509471372 121.2863656 35.47727596 0.0 100846.2535 0.0 0.0 1.0 +0.001666665789 -0.0006666663158 0.0 1.18509471422 116.7260439 41.81510984 0.0 100669.6537 0.0 0.0 1.0 +0.001666665789 -0.0003333331579 0.0 1.18509471413 109.2298156 46.14907786 0.0 100532.2165 0.0 0.0 1.0 +0.001666665789 0.0 0.0 1.18509471369 100.0 47.6913507 0.0 100480.0413 0.0 0.0 1.0 +0.001666665789 0.0003333331579 0.0 1.18509471413 90.77018443 46.14907786 0.0 100532.2165 0.0 0.0 1.0 +0.001666665789 0.0006666663158 0.0 1.18509471422 83.27395606 41.81510984 0.0 100669.6537 0.0 0.0 1.0 +0.001666665789 0.0009999994737 0.0 1.18509471372 78.71363442 35.47727596 0.0 100846.2535 0.0 0.0 1.0 +0.001666665789 0.001333332632 0.0 1.18509471432 77.45220451 28.18474436 0.0 101013.6212 0.0 0.0 1.0 +0.001666665789 0.001666665789 0.0 1.18509471415 79.03355768 20.96644232 0.0 101141.5245 0.0 0.0 1.0 +0.001666665789 0.001999998947 0.0 1.18509471367 82.47478144 14.6043488 0.0 101223.1087 0.0 0.0 1.0 +0.001666665789 0.002333332105 0.0 1.18509471361 86.66434058 9.525471014 0.0 101267.2896 0.0 0.0 1.0 +0.001666665789 0.002666665263 0.0 1.18509471371 90.69197556 5.817515276 0.0 101287.7992 0.0 0.0 1.0 +0.001666665789 0.002999998421 0.0 1.18509471392 94.01163974 3.326866812 0.0 101296.0099 0.0 0.0 1.0 +0.001666665789 0.003333331579 0.0 1.1850947143 96.43704693 1.781476536 0.0 101298.8559 0.0 0.0 1.0 +0.001666665789 0.003666664737 0.0 1.18509471457 98.03485641 0.8932470864 0.0 101299.7124 0.0 0.0 1.0 +0.001666665789 0.003999997895 0.0 1.1850947142 98.99348289 0.4193821286 0.0 101299.9366 0.0 0.0 1.0 +0.001666665789 0.004333331053 0.0 1.18509471329 99.52063272 0.1843720314 0.0 101299.9877 0.0 0.0 1.0 +0.001666665789 0.004666664211 0.0 1.1850947137 99.78748724 0.07589741271 0.0 101299.9979 0.0 0.0 1.0 +0.001666665789 0.004999997368 0.0 1.18509471418 99.91223387 0.02925537785 0.0 101299.9997 0.0 0.0 1.0 +0.001666665789 0.005333330526 0.0 1.1850947144 99.96621054 0.01055920598 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 0.005666663684 0.0 1.18509471399 99.9878666 0.003568647251 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 0.005999996842 0.0 1.18509471399 99.99593439 0.001129335008 0.0 101300.0 0.0 0.0 1.0 +0.001666665789 0.00633333 0.0 1.18509471399 99.99872834 0.0003346484132 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 -0.00633333 0.0 1.18509471399 100.0008858 0.000279722544 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 -0.005999996842 0.0 1.18509471399 100.0028319 0.0009439771682 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 -0.005666663684 0.0 1.18509471399 100.0084516 0.002982924909 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 -0.005333330526 0.0 1.1850947144 100.0235363 0.008826122708 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 -0.004999997368 0.0 1.18509471446 100.0611342 0.02445369049 0.0 101299.9999 0.0 0.0 1.0 +0.001999998947 -0.004666664211 0.0 1.18509471422 100.1480275 0.06344036465 0.0 101299.999 0.0 0.0 1.0 +0.001999998947 -0.004333331053 0.0 1.1850947145 100.3339072 0.154111036 0.0 101299.9941 0.0 0.0 1.0 +0.001999998947 -0.003999997895 0.0 1.18509471372 100.7010978 0.3505489083 0.0 101299.9692 0.0 0.0 1.0 +0.001999998947 -0.003666664737 0.0 1.18509471362 101.368837 0.746638375 0.0 101299.8604 0.0 0.0 1.0 +0.001999998947 -0.003333331579 0.0 1.1850947141 102.4818044 1.489082658 0.0 101299.4449 0.0 0.0 1.0 +0.001999998947 -0.002999998421 0.0 1.18509471347 104.1712419 2.780827912 0.0 101298.064 0.0 0.0 1.0 +0.001999998947 -0.002666665263 0.0 1.18509471462 106.4835814 4.862686057 0.0 101294.0803 0.0 0.0 1.0 +0.001999998947 -0.002333332105 0.0 1.18509471353 109.2890639 7.96205474 0.0 101284.1291 0.0 0.0 1.0 +0.001999998947 -0.001999998947 0.0 1.18509471442 112.2073359 12.20733594 0.0 101262.6929 0.0 0.0 1.0 +0.001999998947 -0.001666665789 0.0 1.18509471367 114.6043488 17.52521856 0.0 101223.1087 0.0 0.0 1.0 +0.001999998947 -0.001333332632 0.0 1.18509471434 115.7058534 23.55878015 0.0 101161.0509 0.0 0.0 1.0 +0.001999998947 -0.0009999994737 0.0 1.18509471396 114.827194 29.65438799 0.0 101079.8452 0.0 0.0 1.0 +0.001999998947 -0.0006666663158 0.0 1.18509471393 111.6506642 34.95199272 0.0 100994.1601 0.0 0.0 1.0 +0.001999998947 -0.0003333331579 0.0 1.18509471404 106.4291044 38.57462624 0.0 100927.4765 0.0 0.0 1.0 +0.001999998947 0.0 0.0 1.1850947134 100.0 39.86376573 0.0 100902.1614 0.0 0.0 1.0 +0.001999998947 0.0003333331579 0.0 1.18509471404 93.57089563 38.57462624 0.0 100927.4765 0.0 0.0 1.0 +0.001999998947 0.0006666663158 0.0 1.18509471393 88.34933576 34.95199272 0.0 100994.1601 0.0 0.0 1.0 +0.001999998947 0.0009999994737 0.0 1.18509471396 85.172806 29.65438799 0.0 101079.8452 0.0 0.0 1.0 +0.001999998947 0.001333332632 0.0 1.18509471434 84.29414657 23.55878015 0.0 101161.0509 0.0 0.0 1.0 +0.001999998947 0.001666665789 0.0 1.18509471367 85.3956512 17.52521856 0.0 101223.1087 0.0 0.0 1.0 +0.001999998947 0.001999998947 0.0 1.18509471442 87.79266406 12.20733594 0.0 101262.6929 0.0 0.0 1.0 +0.001999998947 0.002333332105 0.0 1.18509471353 90.71093614 7.96205474 0.0 101284.1291 0.0 0.0 1.0 +0.001999998947 0.002666665263 0.0 1.18509471462 93.51641859 4.862686057 0.0 101294.0803 0.0 0.0 1.0 +0.001999998947 0.002999998421 0.0 1.18509471347 95.82875813 2.780827912 0.0 101298.064 0.0 0.0 1.0 +0.001999998947 0.003333331579 0.0 1.1850947141 97.51819557 1.489082658 0.0 101299.4449 0.0 0.0 1.0 +0.001999998947 0.003666664737 0.0 1.18509471362 98.63116298 0.746638375 0.0 101299.8604 0.0 0.0 1.0 +0.001999998947 0.003999997895 0.0 1.18509471372 99.29890218 0.3505489083 0.0 101299.9692 0.0 0.0 1.0 +0.001999998947 0.004333331053 0.0 1.1850947145 99.66609276 0.154111036 0.0 101299.9941 0.0 0.0 1.0 +0.001999998947 0.004666664211 0.0 1.18509471422 99.85197248 0.06344036465 0.0 101299.999 0.0 0.0 1.0 +0.001999998947 0.004999997368 0.0 1.18509471446 99.93886577 0.02445369049 0.0 101299.9999 0.0 0.0 1.0 +0.001999998947 0.005333330526 0.0 1.1850947144 99.97646367 0.008826122708 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 0.005666663684 0.0 1.18509471399 99.99154838 0.002982924909 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 0.005999996842 0.0 1.18509471399 99.99716807 0.0009439771682 0.0 101300.0 0.0 0.0 1.0 +0.001999998947 0.00633333 0.0 1.18509471399 99.99911421 0.000279722544 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 -0.00633333 0.0 1.18509471399 100.0005777 0.0002128523855 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 -0.005999996842 0.0 1.18509471399 100.0018471 0.0007183110424 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 -0.005666663684 0.0 1.18509471399 100.0055124 0.002269830218 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 -0.005333330526 0.0 1.18509471399 100.0153512 0.006716159687 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 -0.004999997368 0.0 1.18509471364 100.0398739 0.0186078186 0.0 101299.9999 0.0 0.0 1.0 +0.002333332105 -0.004666664211 0.0 1.18509471424 100.0965488 0.04827438205 0.0 101299.9996 0.0 0.0 1.0 +0.002333332105 -0.004333331053 0.0 1.18509471437 100.2177861 0.1172694241 0.0 101299.9975 0.0 0.0 1.0 +0.002333332105 -0.003999997895 0.0 1.18509471381 100.4572807 0.2667470784 0.0 101299.9869 0.0 0.0 1.0 +0.002333332105 -0.003666664737 0.0 1.18509471367 100.8928037 0.5681478403 0.0 101299.9406 0.0 0.0 1.0 +0.002333332105 -0.003333331579 0.0 1.18509471347 101.6187203 1.133104224 0.0 101299.7638 0.0 0.0 1.0 +0.002333332105 -0.002999998421 0.0 1.18509471387 102.720631 2.116046303 0.0 101299.1764 0.0 0.0 1.0 +0.002333332105 -0.002666665263 0.0 1.18509471428 104.2288203 3.700217768 0.0 101297.4817 0.0 0.0 1.0 +0.002333332105 -0.002333332105 0.0 1.18509471451 106.0586548 6.058654841 0.0 101293.2484 0.0 0.0 1.0 +0.002333332105 -0.001999998947 0.0 1.18509471353 107.9620547 9.289063863 0.0 101284.1291 0.0 0.0 1.0 +0.002333332105 -0.001666665789 0.0 1.18509471361 109.525471 13.33565942 0.0 101267.2896 0.0 0.0 1.0 +0.002333332105 -0.001333332632 0.0 1.18509471339 110.2439112 17.92684452 0.0 101240.8895 0.0 0.0 1.0 +0.002333332105 -0.0009999994737 0.0 1.18509471453 109.6708185 22.56524317 0.0 101206.3438 0.0 0.0 1.0 +0.002333332105 -0.0006666663158 0.0 1.1850947141 107.5989738 26.59640844 0.0 101169.8924 0.0 0.0 1.0 +0.002333332105 -0.0003333331579 0.0 1.18509471415 104.1932885 29.35301924 0.0 101141.5245 0.0 0.0 1.0 +0.002333332105 0.0 0.0 1.18509471433 100.0 30.33397849 0.0 101130.7552 0.0 0.0 1.0 +0.002333332105 0.0003333331579 0.0 1.18509471415 95.80671154 29.35301924 0.0 101141.5245 0.0 0.0 1.0 +0.002333332105 0.0006666663158 0.0 1.1850947141 92.40102616 26.59640844 0.0 101169.8924 0.0 0.0 1.0 +0.002333332105 0.0009999994737 0.0 1.18509471453 90.3291815 22.56524317 0.0 101206.3438 0.0 0.0 1.0 +0.002333332105 0.001333332632 0.0 1.18509471339 89.75608884 17.92684452 0.0 101240.8895 0.0 0.0 1.0 +0.002333332105 0.001666665789 0.0 1.18509471361 90.47452899 13.33565942 0.0 101267.2896 0.0 0.0 1.0 +0.002333332105 0.001999998947 0.0 1.18509471353 92.03794526 9.289063863 0.0 101284.1291 0.0 0.0 1.0 +0.002333332105 0.002333332105 0.0 1.18509471451 93.94134516 6.058654841 0.0 101293.2484 0.0 0.0 1.0 +0.002333332105 0.002666665263 0.0 1.18509471428 95.77117969 3.700217768 0.0 101297.4817 0.0 0.0 1.0 +0.002333332105 0.002999998421 0.0 1.18509471387 97.27936904 2.116046303 0.0 101299.1764 0.0 0.0 1.0 +0.002333332105 0.003333331579 0.0 1.18509471347 98.38127968 1.133104224 0.0 101299.7638 0.0 0.0 1.0 +0.002333332105 0.003666664737 0.0 1.18509471367 99.10719625 0.5681478403 0.0 101299.9406 0.0 0.0 1.0 +0.002333332105 0.003999997895 0.0 1.18509471381 99.54271929 0.2667470784 0.0 101299.9869 0.0 0.0 1.0 +0.002333332105 0.004333331053 0.0 1.18509471437 99.78221393 0.1172694241 0.0 101299.9975 0.0 0.0 1.0 +0.002333332105 0.004666664211 0.0 1.18509471424 99.90345124 0.04827438205 0.0 101299.9996 0.0 0.0 1.0 +0.002333332105 0.004999997368 0.0 1.18509471364 99.9601261 0.0186078186 0.0 101299.9999 0.0 0.0 1.0 +0.002333332105 0.005333330526 0.0 1.18509471399 99.98464878 0.006716159687 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 0.005666663684 0.0 1.18509471399 99.99448756 0.002269830218 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 0.005999996842 0.0 1.18509471399 99.99815291 0.0007183110424 0.0 101300.0 0.0 0.0 1.0 +0.002333332105 0.00633333 0.0 1.18509471399 99.99942226 0.0002128523855 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.00633333 0.0 1.18509471399 100.0003528 0.0001485667221 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.005999996842 0.0 1.18509471399 100.0011281 0.0005013667888 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.005666663684 0.0 1.18509471399 100.0033666 0.001584296245 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.005333330526 0.0 1.18509471399 100.0093755 0.004687745582 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.004999997368 0.0 1.1850947144 100.0243523 0.01298788645 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 -0.004666664211 0.0 1.1850947137 100.0589655 0.03369455637 0.0 101299.9998 0.0 0.0 1.0 +0.002666665263 -0.004333331053 0.0 1.18509471457 100.133009 0.0818517204 0.0 101299.9991 0.0 0.0 1.0 +0.002666665263 -0.003999997895 0.0 1.18509471386 100.2792762 0.1861841434 0.0 101299.9951 0.0 0.0 1.0 +0.002666665263 -0.003666664737 0.0 1.18509471468 100.5452643 0.3965558671 0.0 101299.9779 0.0 0.0 1.0 +0.002666665263 -0.003333331579 0.0 1.18509471369 100.9886052 0.7908841611 0.0 101299.9119 0.0 0.0 1.0 +0.002666665263 -0.002999998421 0.0 1.18509471406 101.6615779 1.476958138 0.0 101299.6928 0.0 0.0 1.0 +0.002666665263 -0.002666665263 0.0 1.18509471412 102.5826782 2.582678242 0.0 101299.0607 0.0 0.0 1.0 +0.002666665263 -0.002333332105 0.0 1.18509471428 103.7002178 4.228820306 0.0 101297.4817 0.0 0.0 1.0 +0.002666665263 -0.001999998947 0.0 1.18509471462 104.8626861 6.483581409 0.0 101294.0803 0.0 0.0 1.0 +0.002666665263 -0.001666665789 0.0 1.18509471371 105.8175153 9.308024442 0.0 101287.7992 0.0 0.0 1.0 +0.002666665263 -0.001333332632 0.0 1.18509471369 106.2562901 12.51258012 0.0 101277.9521 0.0 0.0 1.0 +0.002666665263 -0.0009999994737 0.0 1.18509471439 105.9062837 15.75008992 0.0 101265.0668 0.0 0.0 1.0 +0.002666665263 -0.0006666663158 0.0 1.18509471379 104.6409407 18.56376292 0.0 101251.4706 0.0 0.0 1.0 +0.002666665263 -0.0003333331579 0.0 1.18509471339 102.5609778 20.48782231 0.0 101240.8895 0.0 0.0 1.0 +0.002666665263 0.0 0.0 1.18509471453 100.0 21.17251231 0.0 101236.8727 0.0 0.0 1.0 +0.002666665263 0.0003333331579 0.0 1.18509471339 97.43902221 20.48782231 0.0 101240.8895 0.0 0.0 1.0 +0.002666665263 0.0006666663158 0.0 1.18509471379 95.35905927 18.56376292 0.0 101251.4706 0.0 0.0 1.0 +0.002666665263 0.0009999994737 0.0 1.18509471439 94.09371628 15.75008992 0.0 101265.0668 0.0 0.0 1.0 +0.002666665263 0.001333332632 0.0 1.18509471369 93.74370994 12.51258012 0.0 101277.9521 0.0 0.0 1.0 +0.002666665263 0.001666665789 0.0 1.18509471371 94.18248472 9.308024442 0.0 101287.7992 0.0 0.0 1.0 +0.002666665263 0.001999998947 0.0 1.18509471462 95.13731394 6.483581409 0.0 101294.0803 0.0 0.0 1.0 +0.002666665263 0.002333332105 0.0 1.18509471428 96.29978223 4.228820306 0.0 101297.4817 0.0 0.0 1.0 +0.002666665263 0.002666665263 0.0 1.18509471412 97.41732176 2.582678242 0.0 101299.0607 0.0 0.0 1.0 +0.002666665263 0.002999998421 0.0 1.18509471406 98.33842209 1.476958138 0.0 101299.6928 0.0 0.0 1.0 +0.002666665263 0.003333331579 0.0 1.18509471369 99.0113948 0.7908841611 0.0 101299.9119 0.0 0.0 1.0 +0.002666665263 0.003666664737 0.0 1.18509471468 99.45473568 0.3965558671 0.0 101299.9779 0.0 0.0 1.0 +0.002666665263 0.003999997895 0.0 1.18509471386 99.72072378 0.1861841434 0.0 101299.9951 0.0 0.0 1.0 +0.002666665263 0.004333331053 0.0 1.18509471457 99.86699095 0.0818517204 0.0 101299.9991 0.0 0.0 1.0 +0.002666665263 0.004666664211 0.0 1.1850947137 99.94103453 0.03369455637 0.0 101299.9998 0.0 0.0 1.0 +0.002666665263 0.004999997368 0.0 1.1850947144 99.97564771 0.01298788645 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 0.005333330526 0.0 1.18509471399 99.99062451 0.004687745582 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 0.005666663684 0.0 1.18509471399 99.99663337 0.001584296245 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 0.005999996842 0.0 1.18509471399 99.99887192 0.0005013667888 0.0 101300.0 0.0 0.0 1.0 +0.002666665263 0.00633333 0.0 1.18509471399 99.99964715 0.0001485667221 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.00633333 0.0 1.18509471399 100.0002018 9.558108281e-05 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.005999996842 0.0 1.18509471399 100.0006451 0.0003225566256 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.005666663684 0.0 1.18509471399 100.0019253 0.001019264264 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.005333330526 0.0 1.18509471399 100.0053616 0.003015882644 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.004999997368 0.0 1.18509471399 100.0139264 0.008355816383 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 -0.004666664211 0.0 1.18509471323 100.0337206 0.02167754755 0.0 101299.9999 0.0 0.0 1.0 +0.002999998421 -0.004333331053 0.0 1.18509471418 100.076064 0.05265968014 0.0 101299.9997 0.0 0.0 1.0 +0.002999998421 -0.003999997895 0.0 1.18509471379 100.1597099 0.1197824235 0.0 101299.9984 0.0 0.0 1.0 +0.002999998421 -0.003666664737 0.0 1.18509471452 100.3118207 0.2551260379 0.0 101299.9928 0.0 0.0 1.0 +0.002999998421 -0.003333331579 0.0 1.18509471407 100.5653544 0.5088189563 0.0 101299.9712 0.0 0.0 1.0 +0.002999998421 -0.002999998421 0.0 1.18509471347 100.9502078 0.9502077994 0.0 101299.8995 0.0 0.0 1.0 +0.002999998421 -0.002666665263 0.0 1.18509471406 101.4769581 1.661577905 0.0 101299.6928 0.0 0.0 1.0 +0.002999998421 -0.002333332105 0.0 1.18509471387 102.1160463 2.72063096 0.0 101299.1764 0.0 0.0 1.0 +0.002999998421 -0.001999998947 0.0 1.18509471347 102.7808279 4.171241868 0.0 101298.064 0.0 0.0 1.0 +0.002999998421 -0.001666665789 0.0 1.18509471392 103.3268668 5.988360262 0.0 101296.0099 0.0 0.0 1.0 +0.002999998421 -0.001333332632 0.0 1.18509471457 103.5777893 8.050025873 0.0 101292.7896 0.0 0.0 1.0 +0.002999998421 -0.0009999994737 0.0 1.18509471427 103.3776309 10.13289267 0.0 101288.5756 0.0 0.0 1.0 +0.002999998421 -0.0006666663158 0.0 1.18509471353 102.6540182 11.94308211 0.0 101284.1291 0.0 0.0 1.0 +0.002999998421 -0.0003333331579 0.0 1.18509471329 101.4645483 13.18093455 0.0 101280.6687 0.0 0.0 1.0 +0.002999998421 0.0 0.0 1.18509471445 100.0 13.62143301 0.0 101279.3551 0.0 0.0 1.0 +0.002999998421 0.0003333331579 0.0 1.18509471329 98.53545172 13.18093455 0.0 101280.6687 0.0 0.0 1.0 +0.002999998421 0.0006666663158 0.0 1.18509471353 97.34598175 11.94308211 0.0 101284.1291 0.0 0.0 1.0 +0.002999998421 0.0009999994737 0.0 1.18509471427 96.62236911 10.13289267 0.0 101288.5756 0.0 0.0 1.0 +0.002999998421 0.001333332632 0.0 1.18509471457 96.42221072 8.050025873 0.0 101292.7896 0.0 0.0 1.0 +0.002999998421 0.001666665789 0.0 1.18509471392 96.67313319 5.988360262 0.0 101296.0099 0.0 0.0 1.0 +0.002999998421 0.001999998947 0.0 1.18509471347 97.21917209 4.171241868 0.0 101298.064 0.0 0.0 1.0 +0.002999998421 0.002333332105 0.0 1.18509471387 97.8839537 2.72063096 0.0 101299.1764 0.0 0.0 1.0 +0.002999998421 0.002666665263 0.0 1.18509471406 98.52304186 1.661577905 0.0 101299.6928 0.0 0.0 1.0 +0.002999998421 0.002999998421 0.0 1.18509471347 99.0497922 0.9502077994 0.0 101299.8995 0.0 0.0 1.0 +0.002999998421 0.003333331579 0.0 1.18509471407 99.4346456 0.5088189563 0.0 101299.9712 0.0 0.0 1.0 +0.002999998421 0.003666664737 0.0 1.18509471452 99.68817929 0.2551260379 0.0 101299.9928 0.0 0.0 1.0 +0.002999998421 0.003999997895 0.0 1.18509471379 99.8402901 0.1197824235 0.0 101299.9984 0.0 0.0 1.0 +0.002999998421 0.004333331053 0.0 1.18509471418 99.92393602 0.05265968014 0.0 101299.9997 0.0 0.0 1.0 +0.002999998421 0.004666664211 0.0 1.18509471323 99.96627937 0.02167754755 0.0 101299.9999 0.0 0.0 1.0 +0.002999998421 0.004999997368 0.0 1.18509471399 99.98607364 0.008355816383 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 0.005333330526 0.0 1.18509471399 99.99463843 0.003015882644 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 0.005666663684 0.0 1.18509471399 99.99807472 0.001019264264 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 0.005999996842 0.0 1.18509471399 99.99935489 0.0003225566256 0.0 101300.0 0.0 0.0 1.0 +0.002999998421 0.00633333 0.0 1.18509471399 99.99979822 9.558108281e-05 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.00633333 0.0 1.18509471399 100.0001081 5.686880845e-05 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.005999996842 0.0 1.18509471399 100.0003454 0.0001919146594 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.005666663684 0.0 1.18509471399 100.001031 0.0006064415935 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.005333330526 0.0 1.18509471399 100.002871 0.001794389092 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.004999997368 0.0 1.18509471399 100.0074573 0.004971541516 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.004666664211 0.0 1.18509471399 100.0180568 0.01289770175 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 -0.004333331053 0.0 1.18509471405 100.0407309 0.03133144316 0.0 101299.9999 0.0 0.0 1.0 +0.003333331579 -0.003999997895 0.0 1.18509471349 100.0855217 0.07126811602 0.0 101299.9995 0.0 0.0 1.0 +0.003333331579 -0.003666664737 0.0 1.1850947137 100.1669743 0.1517948254 0.0 101299.9979 0.0 0.0 1.0 +0.003333331579 -0.003333331579 0.0 1.18509471359 100.302737 0.3027369738 0.0 101299.9917 0.0 0.0 1.0 +0.003333331579 -0.002999998421 0.0 1.18509471407 100.508819 0.5653543959 0.0 101299.9712 0.0 0.0 1.0 +0.003333331579 -0.002666665263 0.0 1.18509471369 100.7908842 0.9886052014 0.0 101299.9119 0.0 0.0 1.0 +0.003333331579 -0.002333332105 0.0 1.18509471347 101.1331042 1.61872032 0.0 101299.7638 0.0 0.0 1.0 +0.003333331579 -0.001999998947 0.0 1.1850947141 101.4890827 2.481804431 0.0 101299.4449 0.0 0.0 1.0 +0.003333331579 -0.001666665789 0.0 1.1850947143 101.7814765 3.562953072 0.0 101298.8559 0.0 0.0 1.0 +0.003333331579 -0.001333332632 0.0 1.18509471445 101.9158409 4.789602356 0.0 101297.9325 0.0 0.0 1.0 +0.003333331579 -0.0009999994737 0.0 1.18509471468 101.8086598 6.028865913 0.0 101296.7242 0.0 0.0 1.0 +0.003333331579 -0.0006666663158 0.0 1.18509471436 101.4211784 7.10589197 0.0 101295.4492 0.0 0.0 1.0 +0.003333331579 -0.0003333331579 0.0 1.18509471334 100.7842389 7.842389102 0.0 101294.4569 0.0 0.0 1.0 +0.003333331579 0.0 0.0 1.18509471462 100.0 8.104476761 0.0 101294.0803 0.0 0.0 1.0 +0.003333331579 0.0003333331579 0.0 1.18509471334 99.21576109 7.842389102 0.0 101294.4569 0.0 0.0 1.0 +0.003333331579 0.0006666663158 0.0 1.18509471436 98.57882161 7.10589197 0.0 101295.4492 0.0 0.0 1.0 +0.003333331579 0.0009999994737 0.0 1.18509471468 98.19134023 6.028865913 0.0 101296.7242 0.0 0.0 1.0 +0.003333331579 0.001333332632 0.0 1.18509471445 98.08415906 4.789602356 0.0 101297.9325 0.0 0.0 1.0 +0.003333331579 0.001666665789 0.0 1.1850947143 98.21852346 3.562953072 0.0 101298.8559 0.0 0.0 1.0 +0.003333331579 0.001999998947 0.0 1.1850947141 98.51091734 2.481804431 0.0 101299.4449 0.0 0.0 1.0 +0.003333331579 0.002333332105 0.0 1.18509471347 98.86689578 1.61872032 0.0 101299.7638 0.0 0.0 1.0 +0.003333331579 0.002666665263 0.0 1.18509471369 99.20911584 0.9886052014 0.0 101299.9119 0.0 0.0 1.0 +0.003333331579 0.002999998421 0.0 1.18509471407 99.49118104 0.5653543959 0.0 101299.9712 0.0 0.0 1.0 +0.003333331579 0.003333331579 0.0 1.18509471359 99.69726303 0.3027369738 0.0 101299.9917 0.0 0.0 1.0 +0.003333331579 0.003666664737 0.0 1.1850947137 99.83302569 0.1517948254 0.0 101299.9979 0.0 0.0 1.0 +0.003333331579 0.003999997895 0.0 1.18509471349 99.91447826 0.07126811602 0.0 101299.9995 0.0 0.0 1.0 +0.003333331579 0.004333331053 0.0 1.18509471405 99.95926912 0.03133144316 0.0 101299.9999 0.0 0.0 1.0 +0.003333331579 0.004666664211 0.0 1.18509471399 99.98194322 0.01289770175 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 0.004999997368 0.0 1.18509471399 99.99254269 0.004971541516 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 0.005333330526 0.0 1.18509471399 99.99712898 0.001794389092 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 0.005666663684 0.0 1.18509471399 99.99896905 0.0006064415935 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 0.005999996842 0.0 1.18509471399 99.99965455 0.0001919146594 0.0 101300.0 0.0 0.0 1.0 +0.003333331579 0.00633333 0.0 1.18509471399 99.99989195 5.686880845e-05 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.00633333 0.0 1.18509471399 100.0000542 3.136594059e-05 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.005999996842 0.0 1.18509471399 100.0001732 0.0001058503593 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.005666663684 0.0 1.18509471399 100.0005169 0.0003344823201 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.005333330526 0.0 1.18509471399 100.0014396 0.0009896937036 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.004999997368 0.0 1.18509471399 100.0037392 0.00274204929 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.004666664211 0.0 1.18509471399 100.0090538 0.007113715901 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.004333331053 0.0 1.1850947144 100.0204228 0.01728082953 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 -0.003999997895 0.0 1.18509471405 100.0428813 0.03930786584 0.0 101299.9999 0.0 0.0 1.0 +0.003666664737 -0.003666664737 0.0 1.18509471431 100.0837223 0.08372230061 0.0 101299.9995 0.0 0.0 1.0 +0.003666664737 -0.003333331579 0.0 1.1850947137 100.1517948 0.166974308 0.0 101299.9979 0.0 0.0 1.0 +0.003666664737 -0.002999998421 0.0 1.18509471452 100.255126 0.311820713 0.0 101299.9928 0.0 0.0 1.0 +0.003666664737 -0.002666665263 0.0 1.18509471468 100.3965559 0.5452643173 0.0 101299.9779 0.0 0.0 1.0 +0.003666664737 -0.002333332105 0.0 1.18509471367 100.5681478 0.8928037491 0.0 101299.9406 0.0 0.0 1.0 +0.003666664737 -0.001999998947 0.0 1.18509471362 100.7466384 1.368837021 0.0 101299.8604 0.0 0.0 1.0 +0.003666664737 -0.001666665789 0.0 1.18509471457 100.8932471 1.96514359 0.0 101299.7124 0.0 0.0 1.0 +0.003666664737 -0.001333332632 0.0 1.18509471394 100.9606185 2.641700909 0.0 101299.4802 0.0 0.0 1.0 +0.003666664737 -0.0009999994737 0.0 1.18509471387 100.906877 3.325215618 0.0 101299.1764 0.0 0.0 1.0 +0.003666664737 -0.0006666663158 0.0 1.1850947143 100.7125906 3.91924838 0.0 101298.8559 0.0 0.0 1.0 +0.003666664737 -0.0003333331579 0.0 1.18509471373 100.3932239 4.325462717 0.0 101298.6064 0.0 0.0 1.0 +0.003666664737 0.0 0.0 1.185094714 100.0 4.470016931 0.0 101298.5117 0.0 0.0 1.0 +0.003666664737 0.0003333331579 0.0 1.18509471373 99.60677612 4.325462717 0.0 101298.6064 0.0 0.0 1.0 +0.003666664737 0.0006666663158 0.0 1.1850947143 99.28740939 3.91924838 0.0 101298.8559 0.0 0.0 1.0 +0.003666664737 0.0009999994737 0.0 1.18509471387 99.09312301 3.325215618 0.0 101299.1764 0.0 0.0 1.0 +0.003666664737 0.001333332632 0.0 1.18509471394 99.03938149 2.641700909 0.0 101299.4802 0.0 0.0 1.0 +0.003666664737 0.001666665789 0.0 1.18509471457 99.10675291 1.96514359 0.0 101299.7124 0.0 0.0 1.0 +0.003666664737 0.001999998947 0.0 1.18509471362 99.25336163 1.368837021 0.0 101299.8604 0.0 0.0 1.0 +0.003666664737 0.002333332105 0.0 1.18509471367 99.43185216 0.8928037491 0.0 101299.9406 0.0 0.0 1.0 +0.003666664737 0.002666665263 0.0 1.18509471468 99.60344413 0.5452643173 0.0 101299.9779 0.0 0.0 1.0 +0.003666664737 0.002999998421 0.0 1.18509471452 99.74487396 0.311820713 0.0 101299.9928 0.0 0.0 1.0 +0.003666664737 0.003333331579 0.0 1.1850947137 99.84820517 0.166974308 0.0 101299.9979 0.0 0.0 1.0 +0.003666664737 0.003666664737 0.0 1.18509471431 99.9162777 0.08372230061 0.0 101299.9995 0.0 0.0 1.0 +0.003666664737 0.003999997895 0.0 1.18509471405 99.95711869 0.03930786584 0.0 101299.9999 0.0 0.0 1.0 +0.003666664737 0.004333331053 0.0 1.1850947144 99.9795772 0.01728082953 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.004666664211 0.0 1.18509471399 99.99094618 0.007113715901 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.004999997368 0.0 1.18509471399 99.99626084 0.00274204929 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.005333330526 0.0 1.18509471399 99.99856045 0.0009896937036 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.005666663684 0.0 1.18509471399 99.99948307 0.0003344823201 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.005999996842 0.0 1.18509471399 99.99982679 0.0001058503593 0.0 101300.0 0.0 0.0 1.0 +0.003666664737 0.00633333 0.0 1.18509471399 99.99994582 3.136594059e-05 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.00633333 0.0 1.18509471399 100.0000254 1.60651649e-05 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.005999996842 0.0 1.18509471399 100.0000813 5.421496836e-05 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.005666663684 0.0 1.18509471399 100.0002427 0.0001713168338 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.005333330526 0.0 1.18509471399 100.0006759 0.0005069062891 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.004999997368 0.0 1.18509471399 100.0017555 0.00140443657 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.004666664211 0.0 1.18509471399 100.0042508 0.003643538719 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.004333331053 0.0 1.18509471399 100.0095886 0.008850982017 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.003999997895 0.0 1.1850947144 100.0201329 0.02013290004 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 -0.003666664737 0.0 1.18509471405 100.0393079 0.04288130819 0.0 101299.9999 0.0 0.0 1.0 +0.003999997895 -0.003333331579 0.0 1.18509471349 100.0712681 0.08552173923 0.0 101299.9995 0.0 0.0 1.0 +0.003999997895 -0.002999998421 0.0 1.18509471379 100.1197824 0.159709898 0.0 101299.9984 0.0 0.0 1.0 +0.003999997895 -0.002666665263 0.0 1.18509471386 100.1861841 0.2792762151 0.0 101299.9951 0.0 0.0 1.0 +0.003999997895 -0.002333332105 0.0 1.18509471381 100.2667471 0.4572807059 0.0 101299.9869 0.0 0.0 1.0 +0.003999997895 -0.001999998947 0.0 1.18509471372 100.3505489 0.7010978166 0.0 101299.9692 0.0 0.0 1.0 +0.003999997895 -0.001666665789 0.0 1.1850947142 100.4193821 1.006517109 0.0 101299.9366 0.0 0.0 1.0 +0.003999997895 -0.001333332632 0.0 1.18509471394 100.4510132 1.353039632 0.0 101299.8854 0.0 0.0 1.0 +0.003999997895 -0.0009999994737 0.0 1.18509471435 100.4257814 1.703125627 0.0 101299.8185 0.0 0.0 1.0 +0.003999997895 -0.0006666663158 0.0 1.18509471393 100.3345634 2.007380309 0.0 101299.7478 0.0 0.0 1.0 +0.003999997895 -0.0003333331579 0.0 1.18509471406 100.1846198 2.215437207 0.0 101299.6928 0.0 0.0 1.0 +0.003999997895 0.0 0.0 1.18509471357 100.0 2.28947571 0.0 101299.6719 0.0 0.0 1.0 +0.003999997895 0.0003333331579 0.0 1.18509471406 99.81538023 2.215437207 0.0 101299.6928 0.0 0.0 1.0 +0.003999997895 0.0006666663158 0.0 1.18509471393 99.66543662 2.007380309 0.0 101299.7478 0.0 0.0 1.0 +0.003999997895 0.0009999994737 0.0 1.18509471435 99.57421859 1.703125627 0.0 101299.8185 0.0 0.0 1.0 +0.003999997895 0.001333332632 0.0 1.18509471394 99.54898679 1.353039632 0.0 101299.8854 0.0 0.0 1.0 +0.003999997895 0.001666665789 0.0 1.1850947142 99.58061787 1.006517109 0.0 101299.9366 0.0 0.0 1.0 +0.003999997895 0.001999998947 0.0 1.18509471372 99.64945109 0.7010978166 0.0 101299.9692 0.0 0.0 1.0 +0.003999997895 0.002333332105 0.0 1.18509471381 99.73325292 0.4572807059 0.0 101299.9869 0.0 0.0 1.0 +0.003999997895 0.002666665263 0.0 1.18509471386 99.81381586 0.2792762151 0.0 101299.9951 0.0 0.0 1.0 +0.003999997895 0.002999998421 0.0 1.18509471379 99.88021758 0.159709898 0.0 101299.9984 0.0 0.0 1.0 +0.003999997895 0.003333331579 0.0 1.18509471349 99.92873188 0.08552173923 0.0 101299.9995 0.0 0.0 1.0 +0.003999997895 0.003666664737 0.0 1.18509471405 99.96069213 0.04288130819 0.0 101299.9999 0.0 0.0 1.0 +0.003999997895 0.003999997895 0.0 1.1850947144 99.9798671 0.02013290004 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.004333331053 0.0 1.18509471399 99.99041144 0.008850982017 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.004666664211 0.0 1.18509471399 99.9957492 0.003643538719 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.004999997368 0.0 1.18509471399 99.99824445 0.00140443657 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.005333330526 0.0 1.18509471399 99.99932412 0.0005069062891 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.005666663684 0.0 1.18509471399 99.9997573 0.0001713168338 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.005999996842 0.0 1.18509471399 99.99991868 5.421496836e-05 0.0 101300.0 0.0 0.0 1.0 +0.003999997895 0.00633333 0.0 1.18509471399 99.99997456 1.60651649e-05 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.00633333 0.0 1.18509471399 100.0000112 7.651250397e-06 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.005999996842 0.0 1.18509471399 100.0000358 2.582060631e-05 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.005666663684 0.0 1.18509471399 100.0001067 8.159194133e-05 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.005333330526 0.0 1.18509471399 100.0002971 0.0002414209234 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.004999997368 0.0 1.18509471399 100.0007718 0.0006688817655 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.004666664211 0.0 1.18509471399 100.0018688 0.001735284215 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.004333331053 0.0 1.18509471399 100.0042154 0.004215398976 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.003999997895 0.0 1.18509471399 100.008851 0.009588563852 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.003666664737 0.0 1.1850947144 100.0172808 0.02042279854 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 -0.003333331579 0.0 1.18509471405 100.0313314 0.0407308761 0.0 101299.9999 0.0 0.0 1.0 +0.004333331053 -0.002999998421 0.0 1.18509471418 100.0526597 0.07606398242 0.0 101299.9997 0.0 0.0 1.0 +0.004333331053 -0.002666665263 0.0 1.18509471457 100.0818517 0.1330090457 0.0 101299.9991 0.0 0.0 1.0 +0.004333331053 -0.002333332105 0.0 1.18509471437 100.1172694 0.2177860734 0.0 101299.9975 0.0 0.0 1.0 +0.004333331053 -0.001999998947 0.0 1.1850947145 100.154111 0.3339072446 0.0 101299.9941 0.0 0.0 1.0 +0.004333331053 -0.001666665789 0.0 1.18509471329 100.184372 0.4793672815 0.0 101299.9877 0.0 0.0 1.0 +0.004333331053 -0.001333332632 0.0 1.18509471468 100.1982779 0.6444032841 0.0 101299.9779 0.0 0.0 1.0 +0.004333331053 -0.0009999994737 0.0 1.18509471402 100.1871853 0.8111364378 0.0 101299.9649 0.0 0.0 1.0 +0.004333331053 -0.0006666663158 0.0 1.18509471458 100.1470834 0.9560418134 0.0 101299.9513 0.0 0.0 1.0 +0.004333331053 -0.0003333331579 0.0 1.18509471367 100.081164 1.055131703 0.0 101299.9406 0.0 0.0 1.0 +0.004333331053 0.0 0.0 1.1850947142 100.0 1.090393534 0.0 101299.9366 0.0 0.0 1.0 +0.004333331053 0.0003333331579 0.0 1.18509471367 99.91883602 1.055131703 0.0 101299.9406 0.0 0.0 1.0 +0.004333331053 0.0006666663158 0.0 1.18509471458 99.85291664 0.9560418134 0.0 101299.9513 0.0 0.0 1.0 +0.004333331053 0.0009999994737 0.0 1.18509471402 99.81281467 0.8111364378 0.0 101299.9649 0.0 0.0 1.0 +0.004333331053 0.001333332632 0.0 1.18509471468 99.80172207 0.6444032841 0.0 101299.9779 0.0 0.0 1.0 +0.004333331053 0.001666665789 0.0 1.18509471329 99.81562797 0.4793672815 0.0 101299.9877 0.0 0.0 1.0 +0.004333331053 0.001999998947 0.0 1.1850947145 99.84588896 0.3339072446 0.0 101299.9941 0.0 0.0 1.0 +0.004333331053 0.002333332105 0.0 1.18509471437 99.88273058 0.2177860734 0.0 101299.9975 0.0 0.0 1.0 +0.004333331053 0.002666665263 0.0 1.18509471457 99.91814828 0.1330090457 0.0 101299.9991 0.0 0.0 1.0 +0.004333331053 0.002999998421 0.0 1.18509471418 99.94734032 0.07606398242 0.0 101299.9997 0.0 0.0 1.0 +0.004333331053 0.003333331579 0.0 1.18509471405 99.96866856 0.0407308761 0.0 101299.9999 0.0 0.0 1.0 +0.004333331053 0.003666664737 0.0 1.1850947144 99.98271917 0.02042279854 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.003999997895 0.0 1.18509471399 99.99114902 0.009588563852 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.004333331053 0.0 1.18509471399 99.9957846 0.004215398976 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.004666664211 0.0 1.18509471399 99.99813123 0.001735284215 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.004999997368 0.0 1.18509471399 99.99922821 0.0006688817655 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.005333330526 0.0 1.18509471399 99.99970287 0.0002414209234 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.005666663684 0.0 1.18509471399 99.9998933 8.159194133e-05 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.005999996842 0.0 1.18509471399 99.99996425 2.582060631e-05 0.0 101300.0 0.0 0.0 1.0 +0.004333331053 0.00633333 0.0 1.18509471399 99.99998882 7.651250397e-06 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.00633333 0.0 1.18509471399 100.0000046 3.391946777e-06 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.005999996842 0.0 1.18509471399 100.0000147 1.144677246e-05 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.005666663684 0.0 1.18509471399 100.0000439 3.617128026e-05 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.005333330526 0.0 1.18509471399 100.0001223 0.0001070265487 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.004999997368 0.0 1.18509471399 100.0003177 0.0002965281792 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.004666664211 0.0 1.18509471399 100.0007693 0.0007692849398 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.004333331053 0.0 1.18509471399 100.0017353 0.001868767617 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.003999997895 0.0 1.18509471399 100.0036435 0.004250795173 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.003666664737 0.0 1.18509471399 100.0071137 0.009053820237 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.003333331579 0.0 1.18509471399 100.0128977 0.01805678245 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 -0.002999998421 0.0 1.18509471323 100.0216775 0.03372062952 0.0 101299.9999 0.0 0.0 1.0 +0.004666664211 -0.002666665263 0.0 1.1850947137 100.0336946 0.05896547365 0.0 101299.9998 0.0 0.0 1.0 +0.004666664211 -0.002333332105 0.0 1.18509471424 100.0482744 0.0965487641 0.0 101299.9996 0.0 0.0 1.0 +0.004666664211 -0.001999998947 0.0 1.18509471422 100.0634404 0.1480275175 0.0 101299.999 0.0 0.0 1.0 +0.004666664211 -0.001666665789 0.0 1.1850947137 100.0758974 0.2125127556 0.0 101299.9979 0.0 0.0 1.0 +0.004666664211 -0.001333332632 0.0 1.18509471356 100.0816218 0.2856763965 0.0 101299.9962 0.0 0.0 1.0 +0.004666664211 -0.0009999994737 0.0 1.1850947145 100.0770555 0.3595924173 0.0 101299.9941 0.0 0.0 1.0 +0.004666664211 -0.0006666663158 0.0 1.18509471359 100.0605474 0.4238317633 0.0 101299.9917 0.0 0.0 1.0 +0.004666664211 -0.0003333331579 0.0 1.18509471351 100.0334114 0.4677602215 0.0 101299.9899 0.0 0.0 1.0 +0.004666664211 0.0 0.0 1.18509471431 100.0 0.4833924708 0.0 101299.9893 0.0 0.0 1.0 +0.004666664211 0.0003333331579 0.0 1.18509471351 99.96658856 0.4677602215 0.0 101299.9899 0.0 0.0 1.0 +0.004666664211 0.0006666663158 0.0 1.18509471359 99.93945261 0.4238317633 0.0 101299.9917 0.0 0.0 1.0 +0.004666664211 0.0009999994737 0.0 1.1850947145 99.92294448 0.3595924173 0.0 101299.9941 0.0 0.0 1.0 +0.004666664211 0.001333332632 0.0 1.18509471356 99.91837817 0.2856763965 0.0 101299.9962 0.0 0.0 1.0 +0.004666664211 0.001666665789 0.0 1.1850947137 99.92410259 0.2125127556 0.0 101299.9979 0.0 0.0 1.0 +0.004666664211 0.001999998947 0.0 1.18509471422 99.93655964 0.1480275175 0.0 101299.999 0.0 0.0 1.0 +0.004666664211 0.002333332105 0.0 1.18509471424 99.95172562 0.0965487641 0.0 101299.9996 0.0 0.0 1.0 +0.004666664211 0.002666665263 0.0 1.1850947137 99.96630544 0.05896547365 0.0 101299.9998 0.0 0.0 1.0 +0.004666664211 0.002999998421 0.0 1.18509471323 99.97832245 0.03372062952 0.0 101299.9999 0.0 0.0 1.0 +0.004666664211 0.003333331579 0.0 1.18509471399 99.9871023 0.01805678245 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.003666664737 0.0 1.18509471399 99.99288628 0.009053820237 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.003999997895 0.0 1.18509471399 99.99635646 0.004250795173 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.004333331053 0.0 1.18509471399 99.99826472 0.001868767617 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.004666664211 0.0 1.18509471399 99.99923072 0.0007692849398 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.004999997368 0.0 1.18509471399 99.99968229 0.0002965281792 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.005333330526 0.0 1.18509471399 99.99987768 0.0001070265487 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.005666663684 0.0 1.18509471399 99.99995608 3.617128026e-05 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.005999996842 0.0 1.18509471399 99.99998528 1.144677246e-05 0.0 101300.0 0.0 0.0 1.0 +0.004666664211 0.00633333 0.0 1.18509471399 99.9999954 3.391946777e-06 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.00633333 0.0 1.18509471399 100.0000018 1.40084793e-06 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.005999996842 0.0 1.18509471399 100.0000057 4.727428986e-06 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.005666663684 0.0 1.18509471399 100.0000169 1.493846054e-05 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.005333330526 0.0 1.18509471399 100.0000471 4.420114144e-05 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.004999997368 0.0 1.18509471399 100.0001225 0.0001224638573 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.004666664211 0.0 1.18509471399 100.0002965 0.0003177087634 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.004333331053 0.0 1.18509471399 100.0006689 0.0007717866525 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.003999997895 0.0 1.18509471399 100.0014044 0.001755545712 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.003666664737 0.0 1.18509471399 100.002742 0.003739158123 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.003333331579 0.0 1.18509471399 100.0049715 0.007457312274 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.002999998421 0.0 1.18509471399 100.0083558 0.01392636064 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.002666665263 0.0 1.1850947144 100.0129879 0.0243522871 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 -0.002333332105 0.0 1.18509471364 100.0186078 0.03987389699 0.0 101299.9999 0.0 0.0 1.0 +0.004999997368 -0.001999998947 0.0 1.18509471446 100.0244537 0.06113422622 0.0 101299.9999 0.0 0.0 1.0 +0.004999997368 -0.001666665789 0.0 1.18509471418 100.0292554 0.08776613356 0.0 101299.9997 0.0 0.0 1.0 +0.004999997368 -0.001333332632 0.0 1.18509471355 100.0314619 0.1179821546 0.0 101299.9994 0.0 0.0 1.0 +0.004999997368 -0.0009999994737 0.0 1.18509471374 100.0297018 0.1485089026 0.0 101299.9991 0.0 0.0 1.0 +0.004999997368 -0.0006666663158 0.0 1.18509471435 100.0233386 0.1750392585 0.0 101299.9988 0.0 0.0 1.0 +0.004999997368 -0.0003333331579 0.0 1.18509471372 100.0128788 0.1931813738 0.0 101299.9985 0.0 0.0 1.0 +0.004999997368 0.0 0.0 1.18509471379 100.0 0.1996373725 0.0 101299.9984 0.0 0.0 1.0 +0.004999997368 0.0003333331579 0.0 1.18509471372 99.98712124 0.1931813738 0.0 101299.9985 0.0 0.0 1.0 +0.004999997368 0.0006666663158 0.0 1.18509471435 99.97666143 0.1750392585 0.0 101299.9988 0.0 0.0 1.0 +0.004999997368 0.0009999994737 0.0 1.18509471374 99.97029822 0.1485089026 0.0 101299.9991 0.0 0.0 1.0 +0.004999997368 0.001333332632 0.0 1.18509471355 99.96853809 0.1179821546 0.0 101299.9994 0.0 0.0 1.0 +0.004999997368 0.001666665789 0.0 1.18509471418 99.97074462 0.08776613356 0.0 101299.9997 0.0 0.0 1.0 +0.004999997368 0.001999998947 0.0 1.18509471446 99.97554631 0.06113422622 0.0 101299.9999 0.0 0.0 1.0 +0.004999997368 0.002333332105 0.0 1.18509471364 99.98139218 0.03987389699 0.0 101299.9999 0.0 0.0 1.0 +0.004999997368 0.002666665263 0.0 1.1850947144 99.98701211 0.0243522871 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.002999998421 0.0 1.18509471399 99.99164418 0.01392636064 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.003333331579 0.0 1.18509471399 99.99502846 0.007457312274 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.003666664737 0.0 1.18509471399 99.99725795 0.003739158123 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.003999997895 0.0 1.18509471399 99.99859556 0.001755545712 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.004333331053 0.0 1.18509471399 99.99933112 0.0007717866525 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.004666664211 0.0 1.18509471399 99.99970347 0.0003177087634 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.004999997368 0.0 1.18509471399 99.99987754 0.0001224638573 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.005333330526 0.0 1.18509471399 99.99995285 4.420114144e-05 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.005666663684 0.0 1.18509471399 99.99998307 1.493846054e-05 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.005999996842 0.0 1.18509471399 99.99999433 4.727428986e-06 0.0 101300.0 0.0 0.0 1.0 +0.004999997368 0.00633333 0.0 1.18509471399 99.99999823 1.40084793e-06 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.00633333 0.0 1.18509471399 100.0000006 5.393184361e-07 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.005999996842 0.0 1.18509471399 100.000002 1.820033104e-06 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.005666663684 0.0 1.18509471399 100.0000061 5.751221816e-06 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.005333330526 0.0 1.18509471399 100.000017 1.701718649e-05 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.004999997368 0.0 1.18509471399 100.0000442 4.71478842e-05 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.004666664211 0.0 1.18509471399 100.000107 0.0001223160556 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.004333331053 0.0 1.18509471399 100.0002414 0.0002971334442 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.003999997895 0.0 1.18509471399 100.0005069 0.0006758750522 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.003666664737 0.0 1.18509471399 100.0009897 0.001439554478 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.003333331579 0.0 1.18509471399 100.0017944 0.002871022547 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.002999998421 0.0 1.18509471399 100.0030159 0.005361569145 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.002666665263 0.0 1.18509471399 100.0046877 0.009375491164 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.002333332105 0.0 1.18509471399 100.0067162 0.01535122214 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.001999998947 0.0 1.1850947144 100.0088261 0.02353632722 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.001666665789 0.0 1.1850947144 100.0105592 0.03378945913 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 -0.001333332632 0.0 1.18509471364 100.0113556 0.04542245429 0.0 101299.9999 0.0 0.0 1.0 +0.005333330526 -0.0009999994737 0.0 1.18509471405 100.0107203 0.05717507759 0.0 101299.9999 0.0 0.0 1.0 +0.005333330526 -0.0006666663158 0.0 1.1850947137 100.0084236 0.06738911275 0.0 101299.9998 0.0 0.0 1.0 +0.005333330526 -0.0003333331579 0.0 1.18509471412 100.0046484 0.07437372334 0.0 101299.9998 0.0 0.0 1.0 +0.005333330526 0.0 0.0 1.18509471412 100.0 0.0768592459 0.0 101299.9998 0.0 0.0 1.0 +0.005333330526 0.0003333331579 0.0 1.18509471412 99.99535164 0.07437372334 0.0 101299.9998 0.0 0.0 1.0 +0.005333330526 0.0006666663158 0.0 1.1850947137 99.99157636 0.06738911275 0.0 101299.9998 0.0 0.0 1.0 +0.005333330526 0.0009999994737 0.0 1.18509471405 99.98927967 0.05717507759 0.0 101299.9999 0.0 0.0 1.0 +0.005333330526 0.001333332632 0.0 1.18509471364 99.98864439 0.04542245429 0.0 101299.9999 0.0 0.0 1.0 +0.005333330526 0.001666665789 0.0 1.1850947144 99.98944079 0.03378945913 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.001999998947 0.0 1.1850947144 99.99117388 0.02353632722 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.002333332105 0.0 1.18509471399 99.99328384 0.01535122214 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.002666665263 0.0 1.18509471399 99.99531225 0.009375491164 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.002999998421 0.0 1.18509471399 99.99698412 0.005361569145 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.003333331579 0.0 1.18509471399 99.99820561 0.002871022547 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.003666664737 0.0 1.18509471399 99.99901031 0.001439554478 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.003999997895 0.0 1.18509471399 99.99949309 0.0006758750522 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.004333331053 0.0 1.18509471399 99.99975858 0.0002971334442 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.004666664211 0.0 1.18509471399 99.99989297 0.0001223160556 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.004999997368 0.0 1.18509471399 99.9999558 4.71478842e-05 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.005333330526 0.0 1.18509471399 99.99998298 1.701718649e-05 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.005666663684 0.0 1.18509471399 99.99999389 5.751221816e-06 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.005999996842 0.0 1.18509471399 99.99999795 1.820033104e-06 0.0 101300.0 0.0 0.0 1.0 +0.005333330526 0.00633333 0.0 1.18509471399 99.99999936 5.393184361e-07 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.00633333 0.0 1.18509471399 100.0000002 1.936629598e-07 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.005999996842 0.0 1.18509471399 100.0000007 6.535526589e-07 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.005666663684 0.0 1.18509471399 100.0000021 2.065196672e-06 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.005333330526 0.0 1.18509471399 100.0000058 6.110673179e-06 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.004999997368 0.0 1.18509471399 100.0000149 1.693025528e-05 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.004666664211 0.0 1.18509471399 100.0000362 4.392226888e-05 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.004333331053 0.0 1.18509471399 100.0000816 0.0001066971541 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.003999997895 0.0 1.18509471399 100.0001713 0.0002426988478 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.003666664737 0.0 1.18509471399 100.0003345 0.000516927222 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.003333331579 0.0 1.18509471399 100.0006064 0.001030950709 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.002999998421 0.0 1.18509471399 100.0010193 0.001925276942 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.002666665263 0.0 1.18509471399 100.0015843 0.003366629521 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.002333332105 0.0 1.18509471399 100.0022698 0.005512444814 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.001999998947 0.0 1.18509471399 100.0029829 0.008451620577 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.001666665789 0.0 1.18509471399 100.0035686 0.01213340065 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.001333332632 0.0 1.18509471399 100.0038378 0.01631067353 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.0009999994737 0.0 1.18509471399 100.0036231 0.02053090347 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.0006666663158 0.0 1.1850947144 100.0028469 0.02419864436 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 -0.0003333331579 0.0 1.1850947144 100.001571 0.02670673655 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.0 0.0 1.1850947144 100.0 0.02759925871 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.0003333331579 0.0 1.1850947144 99.99842902 0.02670673655 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.0006666663158 0.0 1.1850947144 99.9971531 0.02419864436 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.0009999994737 0.0 1.18509471399 99.9963769 0.02053090347 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.001333332632 0.0 1.18509471399 99.99616219 0.01631067353 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.001666665789 0.0 1.18509471399 99.99643135 0.01213340065 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.001999998947 0.0 1.18509471399 99.99701708 0.008451620577 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.002333332105 0.0 1.18509471399 99.99773017 0.005512444814 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.002666665263 0.0 1.18509471399 99.9984157 0.003366629521 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.002999998421 0.0 1.18509471399 99.99898074 0.001925276942 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.003333331579 0.0 1.18509471399 99.99939356 0.001030950709 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.003666664737 0.0 1.18509471399 99.99966552 0.000516927222 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.003999997895 0.0 1.18509471399 99.99982868 0.0002426988478 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.004333331053 0.0 1.18509471399 99.99991841 0.0001066971541 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.004666664211 0.0 1.18509471399 99.99996383 4.392226888e-05 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.004999997368 0.0 1.18509471399 99.99998506 1.693025528e-05 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.005333330526 0.0 1.18509471399 99.99999425 6.110673179e-06 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.005666663684 0.0 1.18509471399 99.99999793 2.065196672e-06 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.005999996842 0.0 1.18509471399 99.99999931 6.535526589e-07 0.0 101300.0 0.0 0.0 1.0 +0.005666663684 0.00633333 0.0 1.18509471399 99.99999978 1.936629598e-07 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.00633333 0.0 1.18509471399 100.0000001 6.489172486e-08 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.005999996842 0.0 1.18509471399 100.0000002 2.189895237e-07 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.005666663684 0.0 1.18509471399 100.0000007 6.919969329e-07 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.005333330526 0.0 1.18509471399 100.0000018 2.047537243e-06 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.004999997368 0.0 1.18509471399 100.0000047 5.672914784e-06 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.004666664211 0.0 1.18509471399 100.0000114 1.471727888e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.004333331053 0.0 1.18509471399 100.0000258 3.575160873e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.003999997895 0.0 1.18509471399 100.0000542 8.132245254e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.003666664737 0.0 1.18509471399 100.0001059 0.0001732096788 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.003333331579 0.0 1.18509471399 100.0001919 0.000345446387 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.002999998421 0.0 1.18509471399 100.0003226 0.0006451132512 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.002666665263 0.0 1.18509471399 100.0005014 0.001128075275 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.002333332105 0.0 1.18509471399 100.0007183 0.001847085538 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.001999998947 0.0 1.18509471399 100.000944 0.002831931505 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.001666665789 0.0 1.18509471399 100.0011293 0.004065606029 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.001333332632 0.0 1.18509471399 100.0012145 0.005465308079 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.0009999994737 0.0 1.18509471399 100.0011466 0.006879403995 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.0006666663158 0.0 1.18509471399 100.0009009 0.00810837433 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 -0.0003333331579 0.0 1.18509471399 100.0004972 0.008948774728 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.0 0.0 1.18509471399 100.0 0.009247837092 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.0003333331579 0.0 1.18509471399 99.99950285 0.008948774728 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.0006666663158 0.0 1.18509471399 99.99909907 0.00810837433 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.0009999994737 0.0 1.18509471399 99.99885343 0.006879403995 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.001333332632 0.0 1.18509471399 99.99878549 0.005465308079 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.001666665789 0.0 1.18509471399 99.99887066 0.004065606029 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.001999998947 0.0 1.18509471399 99.99905602 0.002831931505 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.002333332105 0.0 1.18509471399 99.99928169 0.001847085538 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.002666665263 0.0 1.18509471399 99.99949863 0.001128075275 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.002999998421 0.0 1.18509471399 99.99967744 0.0006451132512 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.003333331579 0.0 1.18509471399 99.99980809 0.000345446387 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.003666664737 0.0 1.18509471399 99.99989415 0.0001732096788 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.003999997895 0.0 1.18509471399 99.99994579 8.132245254e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.004333331053 0.0 1.18509471399 99.99997418 3.575160873e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.004666664211 0.0 1.18509471399 99.99998855 1.471727888e-05 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.004999997368 0.0 1.18509471399 99.99999527 5.672914784e-06 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.005333330526 0.0 1.18509471399 99.99999818 2.047537243e-06 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.005666663684 0.0 1.18509471399 99.99999935 6.919969329e-07 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.005999996842 0.0 1.18509471399 99.99999978 2.189895237e-07 0.0 101300.0 0.0 0.0 1.0 +0.005999996842 0.00633333 0.0 1.18509471399 99.99999993 6.489172486e-08 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.00633333 0.0 1.18509471399 100.0 2.029721224e-08 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.005999996842 0.0 1.18509471399 100.0000001 6.849682069e-08 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.005666663684 0.0 1.18509471399 100.0000002 2.164468374e-07 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.005333330526 0.0 1.18509471399 100.0000005 6.404406429e-07 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.004999997368 0.0 1.18509471399 100.0000014 1.774407379e-06 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.004666664211 0.0 1.18509471399 100.0000034 4.60335634e-06 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.004333331053 0.0 1.18509471399 100.0000077 1.118259673e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.003999997895 0.0 1.18509471399 100.0000161 2.54365111e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.003666664737 0.0 1.18509471399 100.0000314 5.417753375e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.003333331579 0.0 1.18509471399 100.0000569 0.0001080507361 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.002999998421 0.0 1.18509471399 100.0000956 0.0002017822859 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.002666665263 0.0 1.18509471399 100.0001486 0.000352845965 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.002333332105 0.0 1.18509471399 100.0002129 0.0005777421893 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.001999998947 0.0 1.18509471399 100.0002797 0.0008857880559 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.001666665789 0.0 1.18509471399 100.0003346 0.00127166397 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.001333332632 0.0 1.18509471399 100.0003599 0.001709470942 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.0009999994737 0.0 1.18509471399 100.0003398 0.002151780112 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.0006666663158 0.0 1.18509471399 100.000267 0.002536184623 0.0 101300.0 0.0 0.0 1.0 +0.00633333 -0.0003333331579 0.0 1.18509471399 100.0001473 0.002799049962 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.0 0.0 1.18509471399 100.0 0.002892592432 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.0003333331579 0.0 1.18509471399 99.99985268 0.002799049962 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.0006666663158 0.0 1.18509471399 99.99973303 0.002536184623 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.0009999994737 0.0 1.18509471399 99.99966025 0.002151780112 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.001333332632 0.0 1.18509471399 99.99964011 0.001709470942 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.001666665789 0.0 1.18509471399 99.99966535 0.00127166397 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.001999998947 0.0 1.18509471399 99.99972028 0.0008857880559 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.002333332105 0.0 1.18509471399 99.99978715 0.0005777421893 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.002666665263 0.0 1.18509471399 99.99985143 0.000352845965 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.002999998421 0.0 1.18509471399 99.99990442 0.0002017822859 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.003333331579 0.0 1.18509471399 99.99994313 0.0001080507361 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.003666664737 0.0 1.18509471399 99.99996863 5.417753375e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.003999997895 0.0 1.18509471399 99.99998393 2.54365111e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.004333331053 0.0 1.18509471399 99.99999235 1.118259673e-05 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.004666664211 0.0 1.18509471399 99.99999661 4.60335634e-06 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.004999997368 0.0 1.18509471399 99.9999986 1.774407379e-06 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.005333330526 0.0 1.18509471399 99.99999946 6.404406429e-07 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.005666663684 0.0 1.18509471399 99.99999981 2.164468374e-07 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.005999996842 0.0 1.18509471399 99.99999994 6.849682069e-08 0.0 101300.0 0.0 0.0 1.0 +0.00633333 0.00633333 0.0 1.18509471399 99.99999998 2.029721224e-08 0.0 101300.0 0.0 0.0 1.0 diff --git a/testCases/regressionTests.py b/testCases/regressionTests.py index e35a956..fa7a3e1 100755 --- a/testCases/regressionTests.py +++ b/testCases/regressionTests.py @@ -1,5 +1,5 @@ # This file is part of aither. -# Copyright (C) 2015-17 Michael Nucci (michael.nucci@gmail.com) +# Copyright (C) 2015-18 Michael Nucci (michael.nucci@gmail.com) # # Aither is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -39,6 +39,8 @@ def __init__(self): self.percentTolerance = 0.01 self.isRestart = False self.restartFile = "none" + self.passedStatus = "none" + self.isProfile = False def SetRegressionCase(self, name): self.caseName = name @@ -52,6 +54,9 @@ def SetNumberOfProcessors(self, num): def Processors(self): return self.procs + def PassedStatus(self): + return self.passedStatus + def SetResiduals(self, resid): self.residuals = resid @@ -76,6 +81,9 @@ def GoToRunDirectory(self): def SetRestart(self, resFlag): self.isRestart = resFlag + def SetProfile(self, profFlag): + self.isProfile = profFlag + def SetRestartFile(self, resFile): self.restartFile = resFile @@ -104,7 +112,7 @@ def CompareResiduals(self, returnCode): for ii, resid in enumerate(resids)] else: passing = [False for ii in resids] - return passing, resids + return passing, resids, truthResids def GetResiduals(self): return self.residuals @@ -121,6 +129,8 @@ def ModifyInputFile(self): fout.write("iterations: " + str(self.iterations) + "\n") elif "outputFrequency:" in line: fout.write("outputFrequency: " + str(self.iterations) + "\n") + elif "restartFrequency:" in line and self.isProfile: + fout.write("restartFrequency: " + str(self.iterations) + "\n") else: fout.write(line) @@ -152,19 +162,25 @@ def RunCase(self): if (returnCode == 0): print("Simulation completed with no errors") + # test residuals for pass/fail + if not self.isProfile: + passed, resids, truth = self.CompareResiduals(returnCode) + if all(passed): + print("All tests for", self.caseName, "PASSED!") + self.passedStatus = "PASSED" + else: + print("Tests for", self.caseName, "FAILED!") + print("Residuals should be:", truth) + print("Residuals are:", resids) + self.passedStatus = "MISMATCH" + else: + passed = [True] + self.passedStatus = "PROFILE" else: print("ERROR: Simulation terminated with errors") + self.passedStatus = "ERRORS" duration = datetime.datetime.now() - start - # test residuals for pass/fail - passed, resids = self.CompareResiduals(returnCode) - if all(passed): - print("All tests for", self.caseName, "PASSED!") - else: - print("Tests for", self.caseName, "FAILED!") - print("Residuals should be:", self.GetResiduals()) - print("Residuals are:", resids) - print("Test Duration:", duration) print("---------- End Test:", self.caseName, "----------") print("") @@ -177,7 +193,7 @@ def main(): # Set up options parser = optparse.OptionParser() parser.add_option("-a", "--aitherPath", action="store", dest="aitherPath", - default="aither", + default="aither", help="Path to aither executable. Default = aither") parser.add_option("-o", "--operatingSystem", action="store", dest="operatingSystem", default="linux", @@ -185,19 +201,27 @@ def main(): parser.add_option("-m", "--mpirunPath", action="store", dest="mpirunPath", default="mpirun", help="Path to mpirun. Default = mpirun") - + parser.add_option("-b", "--build", action="store", + dest="build", default="release", + help="build type used in compilation. Default = release") + options, remainder = parser.parse_args() # travis macOS images have 1 proc, ubuntu have 2 # appveyor windows images have 2 procs - if (options.operatingSystem == "linux" or options.operatingSystem == "windows"): - maxProcs = 2 - else: + maxProcs = 2 + if (options.operatingSystem == "macOS"): maxProcs = 1 + isProfile = options.build == "debug" numIterations = 100 numIterationsShort = 20 numIterationsRestart = 50 + if isProfile: + numIterations = 1 + numIterationsShort = 1 + numIterationsRestart = 1 + totalPass = True # ------------------------------------------------------------------ @@ -211,9 +235,11 @@ def main(): subCyl.SetRegressionCase("subsonicCylinder") subCyl.SetAitherPath(options.aitherPath) subCyl.SetRunDirectory("subsonicCylinder") + subCyl.SetProfile(isProfile) subCyl.SetNumberOfProcessors(1) subCyl.SetNumberOfIterations(numIterations) - subCyl.SetResiduals([1.5371e-1, 1.4991e-1, 1.5910e-1, 8.2250e-1, 1.5297e-1]) + subCyl.SetResiduals( + [1.8751e-01, 2.6727e-01, 3.1217e-01, 7.9662e-01, 1.8639e-01]) subCyl.SetIgnoreIndices(3) subCyl.SetMpirunPath(options.mpirunPath) @@ -228,10 +254,11 @@ def main(): multiCyl.SetRegressionCase("multiblockCylinder") multiCyl.SetAitherPath(options.aitherPath) multiCyl.SetRunDirectory("multiblockCylinder") + multiCyl.SetProfile(isProfile) multiCyl.SetNumberOfProcessors(maxProcs) multiCyl.SetNumberOfIterations(numIterations) - multiCyl.SetResiduals([2.3117e-01, 2.5907e-01, 4.0735e-01, 1.0640e+00, - 2.2955e-01]) + multiCyl.SetResiduals( + [2.0447e-01, 3.1399e-01, 4.5458e-01, 1.1121e+00, 1.9913e-01]) multiCyl.SetIgnoreIndices(3) multiCyl.SetMpirunPath(options.mpirunPath) @@ -246,9 +273,11 @@ def main(): shockTube.SetRegressionCase("shockTube") shockTube.SetAitherPath(options.aitherPath) shockTube.SetRunDirectory("shockTube") + shockTube.SetProfile(isProfile) shockTube.SetNumberOfProcessors(1) shockTube.SetNumberOfIterations(numIterations) - shockTube.SetResiduals([5.0503e-1, 4.4569e-1, 1.0e0, 1.0e0, 2.6181e-1]) + shockTube.SetResiduals( + [4.8537e-01, 4.5855e-01, 1.0000e+00, 1.0000e+00, 2.6434e-01]) shockTube.SetIgnoreIndices(2) shockTube.SetIgnoreIndices(3) shockTube.SetMpirunPath(options.mpirunPath) @@ -263,7 +292,7 @@ def main(): shockTubeRestart = shockTube shockTubeRestart.SetNumberOfIterations(numIterationsRestart) shockTubeRestart.SetRestart(True) - shockTubeRestart.SetRestartFile("shockTube_50.rst") + shockTubeRestart.SetRestartFile("shockTube_" + str(numIterationsRestart) + ".rst") # run regression case passed = shockTubeRestart.RunCase() @@ -276,6 +305,7 @@ def main(): supWedge.SetRegressionCase("supersonicWedge") supWedge.SetAitherPath(options.aitherPath) supWedge.SetRunDirectory("supersonicWedge") + supWedge.SetProfile(isProfile) supWedge.SetNumberOfProcessors(1) supWedge.SetNumberOfIterations(numIterations) supWedge.SetResiduals([4.1813e-1, 4.2549e-1, 3.6525e-1, 3.9971e-1, 4.0998e-1]) @@ -293,9 +323,10 @@ def main(): transBump.SetRegressionCase("transonicBump") transBump.SetAitherPath(options.aitherPath) transBump.SetRunDirectory("transonicBump") + transBump.SetProfile(isProfile) transBump.SetNumberOfProcessors(1) transBump.SetNumberOfIterations(numIterations) - transBump.SetResiduals([1.1839e-1, 6.8615e-2, 8.4925e-2, 1.0000, 9.9669e-2]) + transBump.SetResiduals([1.1901e-01, 7.0606e-02, 8.4288e-02, 1.0000e+00, 1.0032e-01]) transBump.SetIgnoreIndices(3) transBump.SetMpirunPath(options.mpirunPath) @@ -310,12 +341,15 @@ def main(): viscPlate.SetRegressionCase("viscousFlatPlate") viscPlate.SetAitherPath(options.aitherPath) viscPlate.SetRunDirectory("viscousFlatPlate") + viscPlate.SetProfile(isProfile) viscPlate.SetNumberOfProcessors(maxProcs) viscPlate.SetNumberOfIterations(numIterations) if viscPlate.Processors() == 2: - viscPlate.SetResiduals([7.7239e-2, 2.4713e-1, 5.6557e-2, 8.4112e-1, 7.9342e-2]) + viscPlate.SetResiduals( + [7.6770e-02, 2.4712e-01, 5.2446e-02, 1.0000e+00, 7.9490e-02]) else: - viscPlate.SetResiduals([7.6467e-2, 2.4714e-1, 4.0109e-2, 8.3161e-1, 7.9240e-2]) + viscPlate.SetResiduals( + [7.4673e-02, 2.4711e-01, 3.8960e-02, 1.0000e+00, 7.7683e-02]) viscPlate.SetIgnoreIndices(3) viscPlate.SetMpirunPath(options.mpirunPath) @@ -330,14 +364,15 @@ def main(): turbPlate.SetRegressionCase("turbFlatPlate") turbPlate.SetAitherPath(options.aitherPath) turbPlate.SetRunDirectory("turbFlatPlate") + turbPlate.SetProfile(isProfile) turbPlate.SetNumberOfProcessors(maxProcs) turbPlate.SetNumberOfIterations(numIterationsShort) if turbPlate.Processors() == 2: - turbPlate.SetResiduals([2.2326e-01, 2.9704e-01, 4.5442e-01, 2.4928e-01, - 2.1792e-01, 7.9769e-07, 2.3288e-04]) + turbPlate.SetResiduals([2.2801e-01, 2.9863e-01, 1.0000e+00, 3.2381e-01, + 2.2326e-01, 2.5206e-07, 3.3015e-06]) else: - turbPlate.SetResiduals([2.1828e-01, 2.9702e-01, 4.5628e-01, 2.4928e-01, - 2.1361e-01, 7.9753e-07, 2.3287e-04]) + turbPlate.SetResiduals([2.2309e-01, 2.9862e-01, 1.0000e+00, 3.2376e-01, + 2.1910e-01, 2.5208e-07, 3.3009e-06]) turbPlate.SetIgnoreIndices(2) turbPlate.SetMpirunPath(options.mpirunPath) @@ -352,14 +387,15 @@ def main(): rae2822.SetRegressionCase("rae2822") rae2822.SetAitherPath(options.aitherPath) rae2822.SetRunDirectory("rae2822") + rae2822.SetProfile(isProfile) rae2822.SetNumberOfProcessors(maxProcs) rae2822.SetNumberOfIterations(numIterationsShort) if rae2822.Processors() == 2: - rae2822.SetResiduals([5.5472e-01, 7.2623e-01, 5.0035e-01, 4.8794e-01, - 4.9827e-01, 2.4542e-05, 9.3450e-05]) + rae2822.SetResiduals([5.5892e-01, 6.7268e-01, 5.3250e-01, 1.0000e+00, + 5.0058e-01, 2.5771e-09, 3.4059e-10]) else: - rae2822.SetResiduals([5.5195e-01, 7.2220e-01, 5.0410e-01, 6.9139e-01, - 4.9487e-01, 2.4542e-05, 9.2871e-05]) + rae2822.SetResiduals([5.5618e-01, 6.6813e-01, 5.3620e-01, 1.0000e+00, + 4.9726e-01, 2.5769e-09, 3.4032e-10]) rae2822.SetIgnoreIndices(3) rae2822.SetMpirunPath(options.mpirunPath) @@ -374,9 +410,11 @@ def main(): couette.SetRegressionCase("couette") couette.SetAitherPath(options.aitherPath) couette.SetRunDirectory("couette") + couette.SetProfile(isProfile) couette.SetNumberOfProcessors(1) couette.SetNumberOfIterations(numIterations) - couette.SetResiduals([1.1343e-1, 5.0725e-1, 7.4086e-2, 4.7218e-1, 2.2789e-1]) + couette.SetResiduals([1.1816e-01, 5.0725e-01, 6.9807e-02, 5.5916e-01, + 2.3024e-01]) couette.SetIgnoreIndices(3) couette.SetMpirunPath(options.mpirunPath) @@ -391,14 +429,15 @@ def main(): wallLaw.SetRegressionCase("wallLaw") wallLaw.SetAitherPath(options.aitherPath) wallLaw.SetRunDirectory("wallLaw") + wallLaw.SetProfile(isProfile) wallLaw.SetNumberOfProcessors(maxProcs) wallLaw.SetNumberOfIterations(numIterationsShort) if wallLaw.Processors() == 2: - wallLaw.SetResiduals([8.1949e-01, 1.0542e-01, 1.3522e-01, 9.2939e-01, - 8.5213e-01, 6.0529e-02, 6.7596e-05]) + wallLaw.SetResiduals([7.3745e-01, 1.5345e-01, 3.1677e-01, 9.2831e-01, + 7.1928e-01, 2.6861e-02, 2.6255e-07]) else: - wallLaw.SetResiduals([8.1310e-01, 1.0392e-01, 1.3302e-01, 9.2927e-01, - 8.4532e-01, 6.0527e-02, 6.7585e-05]) + wallLaw.SetResiduals([7.4098e-01, 1.4914e-01, 3.1463e-01, 9.2837e-01, + 7.2133e-01, 2.6860e-02, 2.6250e-07]) wallLaw.SetIgnoreIndices(1) wallLaw.SetMpirunPath(options.mpirunPath) @@ -413,16 +452,17 @@ def main(): thermallyPerfect.SetRegressionCase("thermallyPerfect") thermallyPerfect.SetAitherPath(options.aitherPath) thermallyPerfect.SetRunDirectory("thermallyPerfect") + thermallyPerfect.SetProfile(isProfile) thermallyPerfect.SetNumberOfProcessors(maxProcs) thermallyPerfect.SetNumberOfIterations(numIterationsShort) if thermallyPerfect.Processors() == 2: - thermallyPerfect.SetResiduals([5.8862e-01, 3.8007e-01, 4.9681e-01, - 8.4268e-03, 6.0802e-01, 3.5653e-02, - 1.4414e-02]) + thermallyPerfect.SetResiduals([5.8177e-01, 3.8066e-01, 4.8670e-01, + 1.0000e+00, 5.9931e-01, 1.2830e-06, + 3.5031e-04]) else: - thermallyPerfect.SetResiduals([5.8862e-01, 3.8007e-01, 4.9681e-01, - 1.9063e-03, 6.0803e-01, 3.5651e-02, - 1.4414e-02]) + thermallyPerfect.SetResiduals([5.8177e-01, 3.8066e-01, 4.8670e-01, + 1.0000e+00, 5.9931e-01, 1.2830e-06, + 3.5031e-04]) thermallyPerfect.SetIgnoreIndices(3) thermallyPerfect.SetMpirunPath(options.mpirunPath) @@ -437,26 +477,87 @@ def main(): uniform.SetRegressionCase("uniformFlow") uniform.SetAitherPath(options.aitherPath) uniform.SetRunDirectory("uniformFlow") + uniform.SetProfile(isProfile) uniform.SetNumberOfProcessors(1) uniform.SetNumberOfIterations(numIterationsShort) - uniform.SetResiduals([2.6167e-01, 3.2443e-01, 1.8594e-01, 1.8633e-01, - 2.5828e-01, 7.7757e-09, 2.4621e-09]) + uniform.SetResiduals([1.0342e+00, 9.0115e-01, 2.7211e-01, 8.8273e-01, + 9.0131e-01, 1.4756e-07, 1.8748e-07]) uniform.SetMpirunPath(options.mpirunPath) # run regression case passed = uniform.RunCase() + # only care if this case ran, since nothing is changing, residuals have + # some variation with compiler, os, optimiziation level, etc + + # ------------------------------------------------------------------ + # convecting vortex + # initialization from file, nonreflecting boundary + vortex = regressionTest() + vortex.SetRegressionCase("convectingVortex") + vortex.SetAitherPath(options.aitherPath) + vortex.SetRunDirectory("convectingVortex") + vortex.SetProfile(isProfile) + vortex.SetNumberOfProcessors(1) + vortex.SetNumberOfIterations(numIterations) + vortex.SetResiduals([5.2772e+00, 6.3732e-01, 7.0928e-01, 1.0000e+00, + 7.9563e-01]) + vortex.SetIgnoreIndices(3) + vortex.SetMpirunPath(options.mpirunPath) + + # run regression case + passed = vortex.RunCase() + totalPass = totalPass and all(passed) + + # ------------------------------------------------------------------ + # supersonic mixing with diffusion + # turbulent, schmidt diffusion, 4th central, bdplur + supersonicMixing = regressionTest() + supersonicMixing.SetRegressionCase("supersonicMixing") + supersonicMixing.SetAitherPath(options.aitherPath) + supersonicMixing.SetRunDirectory("supersonicMixing") + supersonicMixing.SetProfile(isProfile) + supersonicMixing.SetNumberOfProcessors(maxProcs) + supersonicMixing.SetNumberOfIterations(numIterationsShort) + if supersonicMixing.Processors() == 2: + supersonicMixing.SetResiduals([2.1444e-01, 1.5217e-01, 1.2462e+00, + 8.2062e-02, 1.1356e-01, 3.6555e-04, + 1.1891e-05]) + else: + supersonicMixing.SetResiduals([2.1185e-01, 1.5024e-01, 1.2409e+00, + 8.6013e-02, 1.1192e-01, 3.6604e-04, + 1.1882e-05]) + supersonicMixing.SetIgnoreIndices(3) + supersonicMixing.SetMpirunPath(options.mpirunPath) + + # run regression case + passed = supersonicMixing.RunCase() totalPass = totalPass and all(passed) # ------------------------------------------------------------------ # regression test overall pass/fail # ------------------------------------------------------------------ - if totalPass: + if totalPass and uniform.PassedStatus() != "ERRORS": print("All tests passed!") - sys.exit(0) else: print("ERROR: Some tests failed") sys.exit(1) - + print("--------------------------------------------------") + print("subsonicCylinder:", subCyl.PassedStatus()) + print("multiblockCylinder:", multiCyl.PassedStatus()) + print("shockTube:", shockTube.PassedStatus()) + print("shockTubeRestart:", shockTubeRestart.PassedStatus()) + print("supersonicWedge:", supWedge.PassedStatus()) + print("transonicBump:", transBump.PassedStatus()) + print("viscousFlatPlate:", viscPlate.PassedStatus()) + print("turbulentFlatPlate:", turbPlate.PassedStatus()) + print("rae2822:", rae2822.PassedStatus()) + print("couette:", couette.PassedStatus()) + print("wallLaw:", wallLaw.PassedStatus()) + print("thermallyPerfect:", thermallyPerfect.PassedStatus()) + print("uniform:", uniform.PassedStatus()) + print("convectingVortex:", vortex.PassedStatus()) + print("supersonicMixing:", supersonicMixing.PassedStatus()) + sys.exit(0) if __name__ == "__main__": main() diff --git a/testCases/shockTube/shockTube.inp b/testCases/shockTube/shockTube.inp index 5027514..c7dc046 100755 --- a/testCases/shockTube/shockTube.inp +++ b/testCases/shockTube/shockTube.inp @@ -14,7 +14,7 @@ outputFrequency: 100 outputVariables: restartFrequency: 50 -fluids: +fluids: #reference conditions referenceTemperature: 288.15 diff --git a/testCases/supersonicMixing/supersonicMixing.inp b/testCases/supersonicMixing/supersonicMixing.inp new file mode 100755 index 0000000..a86d1db --- /dev/null +++ b/testCases/supersonicMixing/supersonicMixing.inp @@ -0,0 +1,109 @@ +# Supersonic mixing simulation of Burrows & Kurkov experiments +# https://www.grc.nasa.gov/WWW/wind/valid/bk/study01/bk1.html + +# grid name +gridName: supersonicMixing + +# solver parameters +decompositionMethod: cubic +equationSet: rans +timeIntegration: implicitEuler +cflStart: 100 +cflMax: 100 + +faceReconstruction: thirdOrder +inviscidFlux: ausm +inviscidFluxJacobian: rusanov +viscousFaceReconstruction: centralFourth +limiter: minmod + +iterations: 2000 +nonlinearIterations: 1 +outputFrequency: 1000 +outputVariables: +wallOutputVariables: +restartFrequency: 1000 + +# reference conditions +referenceDensity: 0.26 +referenceTemperature: 1150 +referenceLength: 1 + +fluids: +thermodynamicModel: caloricallyPerfect +diffusionModel: schmidt +turbulenceModel: sst2003 + +initialConditions: + +matrixSolver: lusgs +matrixSweeps: 2 +matrixRelaxation: 1 + +boundaryStates: + +#------------------------------------------------------------- +boundaryConditions: 5 +# Block 0 -- Dimensions: 122 x 93 x 2 +2 2 2 +# i-surfaces + interblock 0 0 0 92 0 1 2004 + supersonicOutflow 121 121 0 92 0 1 4 +# j-surfaces + viscousWall 0 121 0 0 0 1 3 + slipWall 0 121 92 92 0 1 2 +# k-surfaces + slipWall 0 121 0 92 0 0 1 + slipWall 0 121 0 92 1 1 1 +# Block 1 -- Dimensions: 7 x 38 x 2 +2 2 2 +# i-surfaces + interblock 6 6 0 37 0 1 1003 + supersonicInflow 0 0 0 37 0 1 5 +# j-surfaces + interblock 0 6 0 0 0 1 4002 + slipWall 0 6 37 37 0 1 2 +# k-surfaces + slipWall 0 6 0 37 0 0 1 + slipWall 0 6 0 37 1 1 1 +# Block 2 -- Dimensions: 7 x 56 x 2 +2 2 2 +# i-surfaces + interblock 6 6 0 55 0 1 1003 + inlet 0 0 0 55 0 1 6 +# j-surfaces + interblock 0 6 55 55 0 1 3001 + slipWall 0 6 0 0 0 1 7 +# k-surfaces + slipWall 0 6 0 55 0 0 1 + slipWall 0 6 0 55 1 1 1 +# Block 3 -- Dimensions: 120 x 93 x 2 +3 2 2 +# i-surfaces + interblock 0 0 55 92 0 1 2001 + interblock 0 0 0 55 0 1 2002 + interblock 119 119 0 92 0 1 1004 +# j-surfaces + viscousWall 0 119 0 0 0 1 3 + slipWall 0 119 92 92 0 1 2 +# k-surfaces + slipWall 0 119 0 92 0 0 1 + slipWall 0 119 0 92 1 1 1 +# Block 4 -- Dimensions: 120 x 93 x 2 +2 2 2 +# i-surfaces + interblock 119 119 0 92 0 1 1000 + interblock 0 0 0 92 0 1 2003 +# j-surfaces + viscousWall 0 119 0 0 0 1 3 + slipWall 0 119 92 92 0 1 2 +# k-surfaces + slipWall 0 119 0 92 0 0 1 + slipWall 0 119 0 92 1 1 1 diff --git a/testCases/supersonicMixing/supersonicMixing.xyz b/testCases/supersonicMixing/supersonicMixing.xyz new file mode 100755 index 0000000..bbb2d65 Binary files /dev/null and b/testCases/supersonicMixing/supersonicMixing.xyz differ diff --git a/testCases/thermallyPerfect/thermallyPerfect.inp b/testCases/thermallyPerfect/thermallyPerfect.inp index b21d1ef..dfd02f3 100644 --- a/testCases/thermallyPerfect/thermallyPerfect.inp +++ b/testCases/thermallyPerfect/thermallyPerfect.inp @@ -25,9 +25,9 @@ restartFrequency: 1000 # reference conditions referenceTemperature: 2000 referenceDensity: 0.4 -lengthRef: 1 +referenceLength: 1 -fluids: +fluids: thermodynamicModel: thermallyPerfect initialConditions: diff --git a/testCases/turbFlatPlate/turbFlatPlate.inp b/testCases/turbFlatPlate/turbFlatPlate.inp index a8cdb44..d8265e4 100644 --- a/testCases/turbFlatPlate/turbFlatPlate.inp +++ b/testCases/turbFlatPlate/turbFlatPlate.inp @@ -17,7 +17,7 @@ iterations: 25000 outputFrequency: 1000 outputVariables: -fluids: +fluids: #reference conditions referenceTemperature: 300.0 diff --git a/testCases/uniformFlow/uniformFlow.inp b/testCases/uniformFlow/uniformFlow.inp index 03c6338..37e4fe9 100644 --- a/testCases/uniformFlow/uniformFlow.inp +++ b/testCases/uniformFlow/uniformFlow.inp @@ -27,10 +27,10 @@ referenceDensity: 1.2256 referenceTemperature: 288 referenceLength: 1 -fluids: +fluids: thermodynamicModel: caloricallyPerfect -initialConditions: +initialConditions: matrixSolver: lusgs matrixSweeps: 2 @@ -38,7 +38,7 @@ matrixRelaxation: 1 turbulenceModel: sst2003 -boundaryStates: +boundaryStates: #------------------------------------------------------------- boundaryConditions: 10 diff --git a/testCases/viscousFlatPlate/viscousFlatPlate.inp b/testCases/viscousFlatPlate/viscousFlatPlate.inp index 63b5d16..e932385 100644 --- a/testCases/viscousFlatPlate/viscousFlatPlate.inp +++ b/testCases/viscousFlatPlate/viscousFlatPlate.inp @@ -13,7 +13,7 @@ iterations: 25000 outputFrequency: 1000 outputVariables: -fluids: +fluids: #reference conditions referenceTemperature: 288.0 diff --git a/testCases/wallLaw/wallLaw.inp b/testCases/wallLaw/wallLaw.inp index 0c0a14e..18b0e96 100644 --- a/testCases/wallLaw/wallLaw.inp +++ b/testCases/wallLaw/wallLaw.inp @@ -5,8 +5,8 @@ gridName: wallLaw decompositionMethod: cubic equationSet: rans timeIntegration: implicitEuler -cflStart: 100000 -cflMax: 100000 +cflStart: 100 +cflMax: 100 faceReconstruction: thirdOrder inviscidFlux: roe