diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..11a0635 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,21 @@ +version: 1.0.{build} +branches: + only: + - master + - develop +image: Visual Studio 2015 +configuration: release +platform: x64 +environment: + PYTHON: C:\Python35-x64 + PATH: C:\Program Files\Project\bin;C:\Program Files\Microsoft MPI\Bin;%PATH% +build_script: +- ps: >- + powershell ci\appveyor\installMPI.ps1 + + powershell ci\appveyor\buildAither.ps1 +test_script: +- cmd: >- + cd testCases + + %PYTHON%\python.exe regressionTests.py --mpirunPath=mpiexec.exe --aitherPath=aither.exe \ No newline at end of file diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000..ce2d9eb --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,2 @@ +fixes: + - "/home/travis/build/mnucci32/aither::" \ No newline at end of file diff --git a/.gitignore b/.gitignore index d530ea2..f13110e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -#Ignore temporary copy files +# Ignore temporary copy files *~ \#* -#Ignore results files +# Ignore results files *.fun *.res *.out @@ -10,7 +10,9 @@ *.resid *.p3d -#Ignore blog files +# Ignore blog files .sass-cache/ _site/ +# Ignore VS Code files +.vscode/ diff --git a/.travis.yml b/.travis.yml index b32fda5..3fd8b4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ matrix: env: - CXX_COMPILER=g++-5 - C_COMPILER=gcc-5 + - BUILD_TYPE=release - os: linux dist: trusty sudo: required @@ -35,10 +36,11 @@ matrix: sources: - ubuntu-toolchain-r-test packages: - - g++-6 gcc-6 libstdc++-6-dev + - g++-6 gcc-6 libstdc++-6-dev lcov env: - CXX_COMPILER=g++-6 - C_COMPILER=gcc-6 + - BUILD_TYPE=debug - os: linux dist: trusty sudo: required @@ -53,6 +55,7 @@ matrix: env: - CXX_COMPILER=clang++-3.8 - C_COMPILER=clang-3.8 + - BUILD_TYPE=release - os: osx osx_image: xcode8 compiler: gcc @@ -61,6 +64,7 @@ matrix: - C_COMPILER=gcc-6 - HOMEBREW_CC=gcc-6 - HOMEBREW_CXX=g++-6 + - BUILD_TYPE=release - os: osx osx_image: xcode8 compiler: clang @@ -69,6 +73,7 @@ matrix: - C_COMPILER=clang - HOMEBREW_CC=clang - HOMEBREW_CXX=clang++ + - BUILD_TYPE=release # upgrade packages before_install: @@ -82,14 +87,27 @@ before_install: # install mpi install: - - bash travis/installMPI + - bash ci/travis/installMPI -# build instructions -script: +before_script: - mkdir build - cd build - - cmake -G "Unix Makefiles" -DCMAKE_CXX_COMPILER=$CXX_COMPILER -DCMAKE_C_COMPILER=$C_COMPILER -DMPI_DIR=$TRAVIS_BUILD_DIR/openmpi -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=install .. + - if [[ "$BUILD_TYPE" == "debug" ]]; then lcov --directory . --zerocounters; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then ln -s /usr/bin/gcov-6 gcov; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then export PATH=$PWD:$PATH; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then gcov --version; fi + +# 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 -j4 - 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 \ No newline at end of file + - python3 regressionTests.py --aitherPath=$TRAVIS_BUILD_DIR/build/install/bin/aither --operatingSystem=$TRAVIS_OS_NAME --mpirunPath=$TRAVIS_BUILD_DIR/openmpi/bin/mpirun + - cd $TRAVIS_BUILD_DIR/build + +after_success: + - if [[ "$BUILD_TYPE" == "debug" ]]; then lcov --directory . --capture --rc lcov_branch_coverage=1 --output-file coverage.info; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then lcov --remove coverage.info '/usr/*' '/Applications/*' '/Library/*' --rc lcov_branch_coverage=1 --output-file coverage.info; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then lcov --rc lcov_branch_coverage=1 --list coverage.info; fi + - if [[ "$BUILD_TYPE" == "debug" ]]; then bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"; fi diff --git a/README.md b/README.md index e54722e..14e3e33 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,43 @@ # Accurate Implicit Three-dimensional Efficient RANS (AITHER) -[![Build Status](https://travis-ci.org/mnucci32/aither.svg?branch=master)](https://travis-ci.org/mnucci32/aither) +| Branch | Linux/macOS Build | Windows Build | Coverage | +|--- |--- |--- |--- | +| 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 -This code is for a 3D Navier-Stokes computational fluid dynamics solver. It is a cell centered, structured solver, using mulit-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 the cell faces. The code uses the Roe flux difference splitting scheme for the inviscid fluxes, and a central scheme for the viscous fluxes. It is second order accurate in both space and time. +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 +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 +flux difference splitting scheme for the inviscid fluxes, and a central scheme +for the viscous fluxes. It is second order accurate in both space and time. ### Current Status -The code is 2nd order accurate in space and time. Available explicit time integration methods are forward euler (1st order) and a minimum storage four stage Runge-Kutta method (2nd order). The implicit solver (LU-SGS, BLU-SGS, DPLUR, BDPLUR) is implemented for implicit time integration. Dual time stepping is implemented for time accuracy in the implicit solver. Available implicit time integrations methods come from the Beam and Warming family of methods and are the implicit euler (1st order), Crank-Nicholson (2nd order), and BDF2 (2nd order) methods. The code has been thoroughly commented. It has been made parallel using MPI. Currently the Wilcox K-Omega 2006 and SST 2003 turbulence models are available. +The code is 2nd order accurate in space and time. Available explicit time +integration methods are forward euler (1st order) and a minimum storage four +stage Runge-Kutta method (2nd order). The implicit solver (LU-SGS, BLU-SGS, +DPLUR, BDPLUR) is implemented for implicit time integration. Dual time stepping +is implemented for time accuracy in the implicit solver. Available implicit +time integrations methods come from the Beam and Warming family of methods and +are the implicit euler (1st order), Crank-Nicholson (2nd order), and BDF2 +(2nd order) methods. The code has been thoroughly commented. It has been made +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. ### To Do List -* Add SST-DES turbulence model -* Add WALE and Smagorinsky subgrid scale models for LES -* Add Couette flow regression test for isothermal wall, moving wall, periodic boundary conditions -* Add wall functions for turbulence models +* Add non-reflecting boundary conditions +* Add thermally perfect gases +* Add additional inviscid flux option (AUSM) * Add multigrid scheme for improved convergence ### Dependencies -* MPI - OpenMPI and MPICH have both been used in the past. Aither is currently developed with OpenMPI +* MPI - OpenMPI, MPICH, & MS-MPI have been used * C++ compiler with C++14 support * Cmake - Cmake only depends on a C++ compiler @@ -24,15 +45,23 @@ The code is 2nd order accurate in space and time. Available explicit time integr Aither is compiled and installed with the standard cmake process. ```bash -cmake -DCMAKE_INSTALL_PREFIX=/path/to/installation /path/to/source +cmake -DCMAKE_INSTALL_PREFIX=/path/to/installation -DCMAKE_BUILD_TYPE=release /path/to/source make make install ``` -Cmake will automatically look for an MPI package. To specify a specific installation, set *-DMPI_DIR* to the MPI installation directory. +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*. ### How To Run ```bash -mpirun -np 1 aither inputFile.inp >outputFile.out 2>errorFile.err & +mpirun -np 1 aither inputFile.inp [restartFile.rst] > outputFile.out 2> errorFile.err & ``` The restart file argument is optional. + +### Visualizing Results +Aither writes out Plot3D function files (\*.fun), as well as a Plot3D meta +files (\*.p3d) that can be visualized in [ParaView](www.paraview.org). Versions +5.3 and newer support reading the meta files. \ No newline at end of file diff --git a/ci/appveyor/buildAither.ps1 b/ci/appveyor/buildAither.ps1 new file mode 100644 index 0000000..e221507 --- /dev/null +++ b/ci/appveyor/buildAither.ps1 @@ -0,0 +1,15 @@ +function BuildAither() { + # Go to build directory and build + # Build Aither with cmake + 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 + cd .. +} + +function main() { + BuildAither +} + +main \ No newline at end of file diff --git a/ci/appveyor/installMPI.ps1 b/ci/appveyor/installMPI.ps1 new file mode 100644 index 0000000..d2046db --- /dev/null +++ b/ci/appveyor/installMPI.ps1 @@ -0,0 +1,19 @@ +function InstallMPI() { + md mpi + cd mpi + # install MPI SDK and Runtime + Write-Host "Installing Microsoft MPI SDK..." + appveyor DownloadFile http://download.microsoft.com/download/B/2/E/B2EB83FE-98C2-4156-834A-E1711E6884FB/msmpisdk.msi + Start-Process -FilePath msiexec.exe -ArgumentList "/quiet /qn /i msmpisdk.msi" -Wait + Write-Host "Microsoft MPI SDK installation complete" + 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 + cd .. +} + +function main() { + InstallMPI +} + +main \ No newline at end of file diff --git a/travis/installMPI b/ci/travis/installMPI similarity index 100% rename from travis/installMPI rename to ci/travis/installMPI diff --git a/include/boundaryConditions.hpp b/include/boundaryConditions.hpp index c8a7019..b946e98 100644 --- a/include/boundaryConditions.hpp +++ b/include/boundaryConditions.hpp @@ -28,6 +28,7 @@ one block. */ #include // array #include // string #include // ostream +#include // unique_ptr #include "mpi.h" // parallelism #include "vector3d.hpp" #include "range.hpp" @@ -38,9 +39,13 @@ using std::array; using std::string; using std::cout; using std::endl; +using std::shared_ptr; // forward class declaration class plot3dBlock; +class decomposition; +class inputState; +class input; class boundarySurface { string bcType_; // boundary condition name for surface @@ -63,8 +68,6 @@ class boundarySurface { boundarySurface(const boundarySurface&) = default; boundarySurface& operator=(const boundarySurface&) = default; - friend class boundaryConditions; - // Member functions string BCType() const {return bcType_;} int IMin() const {return data_[0];} @@ -83,7 +86,14 @@ class boundarySurface { int Max2() const; int Min1() const; int Min2() const; - int NumFaces() const; + int Ind3() const { return this->RangeDir3().Start(); } + int Min(const string &) const; + int Max(const string &) const; + int NumFaces() const { return this->NumI() * this->NumJ() * this->NumK(); } + + int NumI() const { return this->RangeI().Size(); } + int NumJ() const { return this->RangeJ().Size(); } + int NumK() const { return this->RangeK().Size(); } range RangeI() const; range RangeJ() const; @@ -94,18 +104,33 @@ class boundarySurface { int PartnerBlock() const; int PartnerSurface() const; - void UpdateTagForSplitJoin(const int&); - boundarySurface Split(const string&, const int&, const int&, - const int&, bool&, int = 0); - bool SplitDirectionIsReversed(const string&, const int&) const; + void UpdateTagForSplitJoin(const int &); + boundarySurface DependentSplit(const string &, const int &, const int &, int, + int, bool &, bool &, const int &); + void Join(const boundarySurface &, const string &, bool &); + boundarySurface Split(const string &, const int &, bool &, bool &, + const bool = true); + bool SplitDirectionIsReversed(const string &, const int &) const; + bool SplitCGridToHGrid(const string &, const int &, const int &, + const int &) const; + bool IsConnection() const { + return bcType_ == "interblock" || bcType_ == "periodic"; + } + void IncrementDirection(const string &, const int &); + + void PackBoundarySurface(char*(&), const int&, int&) const; + void UnpackBoundarySurface(char*(&), const int&, int&); + + bool operator==(const boundarySurface &) const; + bool operator!=(const boundarySurface &s) const { return !(*this == s); }; // Destructor ~boundarySurface() noexcept {} }; -/* A class to store the necessary information for the boundary_ condition patches. - A patch is a 2D surface on a block_ boundary_ that is assigned the same - boundary_ condition. */ +/* A class to store the necessary information for the boundary condition patches. + A patch is a 2D surface on a block boundary that is assigned the same + boundary condition. */ class patch { vector3d origin_; // coordinates of patch origin // Coordinates of direction 1 max, direction 2 zero @@ -114,7 +139,7 @@ class patch { vector3d corner2_; vector3d corner12_; // coordinates of direction 1/2 max // Array of booleans for 4 sides of patch (1 if borders another patch) - bool patchBorder_[4]; + array patchBorder_; int boundary_; // boundary number (1-6) int block_; // parent block number int d1Start_; // direction 1 start index @@ -124,17 +149,19 @@ class patch { int constSurf_; // index of direction 3 int rank_; // rank of block that patch belongs to int localBlock_; // position of block on processor + string bcName_; // name of bc on patch public: // Constructor patch(); patch(const int&, const int&, const int&, const int&, const int&, const int&, const int&, const int&, const plot3dBlock&, const int&, const int&, - const bool(&)[4]); + const array&, const string&); patch(const boundarySurface &surf, const plot3dBlock &blk, const int &bNum, - const bool (&border)[4], int r = 0, int l = 0) : + const array &border, int r = 0, int l = 0) : patch(surf.SurfaceType(), bNum, surf.IMin(), surf.IMax(), surf.JMin(), - surf.JMax(), surf.KMin(), surf.KMax(), blk, r, l, border) {} + surf.JMax(), surf.KMin(), surf.KMax(), blk, r, l, border, + surf.BCType()) {} // move constructor and assignment operator patch(patch&&) noexcept = default; @@ -162,6 +189,11 @@ class patch { bool Dir1EndInterBorder() const {return patchBorder_[1];} bool Dir2StartInterBorder() const {return patchBorder_[2];} bool Dir2EndInterBorder() const {return patchBorder_[3];} + string BCType() const {return bcName_;} + void Transform(const shared_ptr &); + void Translate(const vector3d &); + void Rotate(const vector3d &, const vector3d &, + const double &); // Destructor ~patch() noexcept {} @@ -206,6 +238,8 @@ class boundaryConditions { int GetSurfaceType(const int &a) const {return surfs_[a].SurfaceType();} boundarySurface GetSurface(const int &a) const {return surfs_[a];} int NumViscousFaces() const; + int NumViscousSurfaces() const; + bool IsConnection(const int &a) const {return surfs_[a].IsConnection();} int BlockDimI() const; int BlockDimJ() const; @@ -225,8 +259,17 @@ class boundaryConditions { void ResizeVecs(const int&); void ResizeVecs(const int&, const int&, const int&); - string GetBCName(const int&, const int&, const int&, const int&) const; - int GetBCTag(const int&, const int&, const int&, const int&) const; + boundarySurface GetBCSurface(const int &, const int &, const int &, + const int &) const; + string GetBCName(const int &ii, const int &jj, const int &kk, + const int &surf) const { + return this->GetBCSurface(ii, jj, kk, surf).BCType(); + } + bool BCIsConnection(const int &ii, const int &jj, const int &kk, + const int &surf) const { + const auto name = this->GetBCName(ii, jj, kk, surf); + return name == "interblock" || name == "periodic"; + } void AssignFromInput(const int&, const vector&); @@ -236,8 +279,9 @@ class boundaryConditions { const plot3dBlock&, const int&, const string&, const int&, const int&, const int&); void Join(const boundaryConditions&, const string&, vector&); + void Merge(const string &); - void BordersSurface(const int&, bool (&)[4]) const; + void BordersSurface(const int&, array&) const; void PackBC(char*(&), const int&, int&) const; void UnpackBC(char*(&), const int&, int&); @@ -246,38 +290,40 @@ class boundaryConditions { ~boundaryConditions() noexcept {} }; -/* A class to store the necessary information for the interblock boundary_ conditions. - The data_ is stored in pairs, where each pair is patch on a boundary_ that is point matched. */ -class interblock { +/* A class to store the necessary information for the connection boundary conditions. + The data is stored in pairs, where each pair is patch on a boundary that is point matched. */ +class connection { int rank_[2]; // processor location of boundaries - int block_[2]; // block_ numbers (global) - int localBlock_[2]; // local (on processor) block_ numbers + int block_[2]; // block numbers (global) + int localBlock_[2]; // local (on processor) block numbers int boundary_[2]; // boundary numbers int d1Start_[2]; // first direction start numbers for surface int d1End_[2]; // first direction end numbers for surface int d2Start_[2]; // second direction start numbers for surface int d2End_[2]; // second direction end numbers for surface int constSurf_[2]; // index of direction 3 - bool patchBorder_[8]; // borders another patch on sides of patch + array patchBorder_; // borders another patch on sides of patch // Defines how patches are oriented relative to one another (1-8) int orientation_; + bool isInterblock_; public: // Constructor - interblock() : rank_{0, 0}, block_{0, 0}, localBlock_{0, 0}, boundary_{0, 0}, - d1Start_{0, 0}, d1End_{0, 0}, d2Start_{0, 0}, d2End_{0, 0}, - constSurf_{0, 0}, patchBorder_{false, false, false, false, false, - false, false, false}, orientation_(0) {} + connection() : rank_{0, 0}, block_{0, 0}, localBlock_{0, 0}, boundary_{0, 0}, + d1Start_{0, 0}, d1End_{0, 0}, d2Start_{0, 0}, d2End_{0, 0}, + constSurf_{0, 0}, patchBorder_{false, false, false, false, false, + false, false, false}, orientation_(0), + isInterblock_(true) {} - interblock(const patch&, const patch&); + connection(const patch&, const patch&); // move constructor and assignment operator - interblock(interblock&&) noexcept = default; - interblock& operator=(interblock&&) noexcept = default; + connection(connection&&) noexcept = default; + connection& operator=(connection&&) noexcept = default; // copy constructor and assignment operator - interblock(const interblock&) = default; - interblock& operator=(const interblock&) = default; + connection(const connection&) = default; + connection& operator=(const connection&) = default; // Member functions int RankFirst() const {return rank_[0];} @@ -331,6 +377,7 @@ class interblock { bool Dir2EndInterBorderSecond() const {return patchBorder_[7];} int Orientation() const {return orientation_;} + bool IsInterblock() const {return isInterblock_;} string Direction1First() const; string Direction2First() const; @@ -344,7 +391,7 @@ class interblock { void SwapOrder(); void AdjustForSlice(const bool&, const int&); bool TestPatchMatch(const patch&, const patch&); - void GetAddressesMPI(MPI_Aint (&)[11])const; + void GetAddressesMPI(MPI_Aint (&)[12])const; void FirstSliceIndices(int&, int&, int&, int&, int&, int&, const int&) const; void SecondSliceIndices(int&, int&, int&, int&, int&, int&, const int&) const; @@ -354,88 +401,22 @@ class interblock { } // Destructor - ~interblock() noexcept {} -}; - -class decomposition { - // rank of each procBlock - // (vector size equals number of procBlocks after decomp) - vector rank_; - // parent block_ of each procBlock - // (vector size equals number of procBlocks after decomp) - vector parBlock_; - // local position of each procBlock - // (vector size equals number of procBlocks after decomp) - vector localPos_; - // lower block_ of split (vector size equals number of splits) - vector splitHistBlkLow_; - // upper block_ of split (vector size equals number of splits) - vector splitHistBlkUp_; - // index of split (vector size equals number of splits) - vector splitHistIndex_; - // direction of split (vector size equals number of splits) - vector splitHistDir_; - int numProcs_; // number of processors - - public: - // Constructor - decomposition(const int&, const int&); - decomposition() : decomposition(1, 1) {} - - // move constructor and assignment operator - decomposition(decomposition&&) noexcept = default; - decomposition& operator=(decomposition&&) noexcept = default; - - // copy constructor and assignment operator - decomposition(const decomposition&) = default; - decomposition& operator=(const decomposition&) = default; - - // Member functions - int Rank(const int &a) const {return rank_[a];} - int ParentBlock(const int &a) const {return parBlock_[a];} - int LocalPosition(const int &a) const {return localPos_[a];} - int NumProcs() const {return numProcs_;} - double IdealLoad(const vector&) const; - double MaxLoad(const vector&) const; - double MinLoad(const vector&) const; - double ProcLoad(const vector&, const int&) const; - double LoadRatio(const vector&, const int&) const; - int MostOverloadedProc(const vector&, double&) const; - int MostUnderloadedProc(const vector&, double&) const; - int NumBlocksOnProc(const int&) const; - vector NumBlocksOnAllProc() const; - void SendToProc(const int&, const int&, const int&); - void Split(const int&, const int&, const string&); - int SendWholeOrSplit(const vector&, const int&, - const int&, int&, string&) const; - int Size() const {return static_cast (rank_.size());} - - int NumSplits() const {return static_cast (splitHistDir_.size());} - int SplitHistBlkLower(const int &a) const {return splitHistBlkLow_[a];} - int SplitHistBlkUpper(const int &a) const {return splitHistBlkUp_[a];} - int SplitHistIndex(const int &a) const {return splitHistIndex_[a];} - string SplitHistDir(const int &a) const {return splitHistDir_[a];} - - void PrintDiagnostics(const vector&) const; - - // Destructor - ~decomposition() noexcept {} + ~connection() noexcept {} }; // Function declarations -vector GetInterblockBCs(const vector&, +vector GetConnectionBCs(const vector&, const vector&, - const decomposition&); + const decomposition&, const input&); ostream & operator<< (ostream &os, const boundaryConditions&); ostream & operator<< (ostream &os, const boundarySurface&); ostream & operator<< (ostream &os, const patch&); -ostream & operator<< (ostream &os, const decomposition&); -ostream & operator<< (ostream &os, const interblock&); +ostream & operator<< (ostream &os, const connection&); array GetSwapLoc(const int &, const int &, const int &, const int &, - const interblock &, const int &, const bool &); + const connection &, const int &, const bool &); #endif diff --git a/include/eos.hpp b/include/eos.hpp index b47859f..30fb6b4 100644 --- a/include/eos.hpp +++ b/include/eos.hpp @@ -59,6 +59,7 @@ class idealGas { double Pressure(const double &rho, const double &specEn) const; double PressFromEnergy(const double &rho, const double &energy, const double &vel) const; + double PressureRT(const double &rho, const double &temperature) const; double Density(const double &pressure, const double &specEn) const; double SpecEnergy(const double &pressure, const double &rho) const; double Energy(const double &specEn, const double &vel) const; @@ -68,15 +69,14 @@ class idealGas { double Gamma() const {return gamma_;} double GasConst() const {return gasConst_;} double Prandtl() const {return (4.0 * gamma_) / (9.0 * gamma_ - 5.0);} - double Temperature(const double &pressure, const double &rho) const; - // nondimensional version (R=1/gamma) + double SpecificHeat() const {return 1.0 / (gamma_ - 1.0);} double Conductivity(const double &mu) const { - return mu / (this->Prandtl() * (gamma_ - 1.0) );} - // Nondimensional version (R=1/gamma) + return mu * this->SpecificHeat() / this->Prandtl();} double TurbConductivity(const double &eddyVisc, const double &prt) const { - return eddyVisc / ( prt * (gamma_ - 1.0) );} + return eddyVisc * this->SpecificHeat() / prt;} + // nondimensional version (R=1/gamma) double DensityTP(const double &temp, const double &press) const { return press * gamma_ / temp;} diff --git a/include/input.hpp b/include/input.hpp index 9a0eca2..1ca296f 100644 --- a/include/input.hpp +++ b/include/input.hpp @@ -31,6 +31,7 @@ using std::vector; using std::string; using std::set; using std::unique_ptr; +using std::shared_ptr; // forward class declaration class turbModel; @@ -49,6 +50,7 @@ class input { double pRef_; // reference pressure double rRef_; // reference density double lRef_; // reference length + double aRef_; // reference speed of sound vector3d vRef_; // reference velocity double gamma_; // ratio of specific heats double gasConst_; // gas constant of fluid @@ -82,9 +84,16 @@ class input { int iterationStart_; // starting number for iterations set outputVariables_; // variables to output + set wallOutputVariables_; // wall variables to output vector ics_; // initial conditions - vector> bcStates_; // information for boundary conditions + vector> bcStates_; // information for boundary conditions + + // private member functions + void CheckNonlinearIterations(); + void CheckOutputVariables(); + void CheckWallOutputVariables(); + void CheckTurbulenceModel() const; public: // constructor @@ -116,17 +125,21 @@ class input { double LRef() const {return lRef_;} double TRef() const {return tRef_;} vector3d VelRef() const {return vRef_;} - double ARef(const idealGas &) const; + double ARef() const {return aRef_;} + void NondimensionalizeStateData(const idealGas &); - double Gamma() const {return gamma_;} - double R() const {return gasConst_;} + double Gamma() const { return gamma_; } + double R() const { return gasConst_; } - boundaryConditions BC(const int &ind) const {return bc_[ind];} - vector AllBC() const {return bc_;} - int NumBC() const {return bc_.size();} + boundaryConditions BC(const int &ind) const { return bc_[ind]; } + vector AllBC() const { return bc_; } + int NumBC() const { return bc_.size(); } - string TimeIntegration() const {return timeIntegration_;} - bool IsMultilevelInTime() const {return timeIntegration_ == "bdf2";} + string TimeIntegration() const { return timeIntegration_; } + bool IsMultilevelInTime() const { return timeIntegration_ == "bdf2"; } + bool NeedToStoreTimeN() const { + return this->IsImplicit() || this->TimeIntegration() == "rk4"; + } double CFL() const {return cfl_;} void CalcCFL(const int &i); @@ -147,6 +160,7 @@ class input { int OutputFrequency() const {return outputFrequency_;} int RestartFrequency() const {return restartFrequency_;} set OutputVariables() const {return outputVariables_;} + set WallOutputVariables() const {return wallOutputVariables_;} bool WriteOutput(const int &nn) const {return (nn + 1) % outputFrequency_ == 0;} bool WriteRestart(const int &nn) const { @@ -180,6 +194,7 @@ class input { 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 NumTurbEquations() const; @@ -189,22 +204,20 @@ class input { bool IsImplicit() const; bool IsViscous() const; bool IsTurbulent() const; + bool IsRANS() const; + bool IsLES() const; bool IsBlockMatrix() const; string OrderOfAccuracy() const; unique_ptr AssignTurbulenceModel() const; - void CheckNonlinearIterations(); - void CheckOutputVariables(); - void CheckTurbulenceModel() const; - double ViscousCFLCoefficient() const; int NumberGhostLayers() const; icState ICStateForBlock(const int &) const; - const unique_ptr & BCData(const int &) const; + const shared_ptr & BCData(const int &) const; bool IsWenoZ() const {return this->FaceReconstruction() == "wenoZ";} diff --git a/include/inputStates.hpp b/include/inputStates.hpp index 5047e01..dedf55a 100644 --- a/include/inputStates.hpp +++ b/include/inputStates.hpp @@ -31,12 +31,14 @@ conditions and initial conditions. using std::string; using std::vector; +using std::string; using std::ifstream; -using std::unique_ptr; +using std::shared_ptr; // this is an abstract base class class inputState { int tag_; + bool nondimensional_ = false; public: // constructor @@ -54,7 +56,9 @@ class inputState { // member functions const int Tag() const {return tag_;} void SetTag(const int &t) {tag_ = t;} + const int StartTag() const {return this->Tag();} + virtual const int EndTag() const {return this->Tag();} virtual void Print(ostream &os) const = 0; // abstract base class virtual const vector3d Velocity() const {return {0, 0, 0};} virtual const double Density() const {return 0;} @@ -69,9 +73,22 @@ class inputState { virtual bool IsIsothermal() const {return false;} virtual bool IsAdiabatic() const {return false;} virtual bool IsConstantHeatFlux() const {return false;} - - // destructor - virtual ~inputState() noexcept {} + virtual bool IsTranslation() const {return false;} + virtual bool IsRotation() const {return false;} + virtual const double Rotation() const {return 0;} + virtual const vector3d Translation() const {return {0, 0, 0};} + virtual const vector3d Axis() const {return {0, 0, 0};} + virtual const vector3d Point() const {return {0, 0, 0};} + virtual const double VonKarmen() const {return 0.0;} + virtual const double WallConstant() const {return 0.0;} + virtual bool IsWallLaw() const {return false;} + virtual void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) = 0; + bool IsNondimensional() const { return nondimensional_; } + void SetNondimensional(const bool &nd) {nondimensional_ = nd;} + + // destructor + virtual ~inputState() noexcept {} }; @@ -105,6 +122,8 @@ class icState : public inputState { const bool SpecifiedTurbulence() const {return specifiedTurbulence_;} void SetSpecifiedTurbulence() {specifiedTurbulence_ = true;} void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; // Destructor virtual ~icState() noexcept {} @@ -161,6 +180,8 @@ class stagnationInlet : public inputState { const bool SpecifiedTurbulence() const {return specifiedTurbulence_;} void SetSpecifiedTurbulence() {specifiedTurbulence_ = true;} void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; // Destructor ~stagnationInlet() noexcept {} @@ -185,6 +206,8 @@ class pressureOutlet : public inputState { // Member functions const double Pressure() const override {return pressure_;} void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; // Destructor virtual ~pressureOutlet() noexcept {} @@ -263,6 +286,8 @@ class subsonicInflow : public inputState { const bool SpecifiedTurbulence() const {return specifiedTurbulence_;} void SetSpecifiedTurbulence() {specifiedTurbulence_ = true;} void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; // Destructor ~subsonicInflow() noexcept {} @@ -274,12 +299,16 @@ class viscousWall : public inputState { vector3d velocity_ = {0.0, 0.0, 0.0}; double temperature_ = 0.0; double heatFlux_ = 0.0; + double vonKarmen_ = 0.41; + double wallConstant_ = 5.5; + string wallTreatment_ = "lowRe"; bool specifiedTemperature_ = false; bool specifiedHeatFlux_ = false; public: // constructor explicit viscousWall(string &str); + viscousWall() : inputState() {} // move constructor and assignment operator viscousWall(viscousWall&&) noexcept = default; @@ -293,6 +322,11 @@ class viscousWall : public inputState { 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_;} + const double WallConstant() const override {return wallConstant_;} + bool IsWallLaw() const override { + return (wallTreatment_ == "wallLaw") ? true : false; + } bool IsIsothermal() const override { return specifiedTemperature_ ? true : false; } @@ -303,12 +337,53 @@ class viscousWall : public inputState { return (specifiedHeatFlux_ && heatFlux_ != 0.0) ? true : false; } void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; // Destructor virtual ~viscousWall() noexcept {} }; +class periodic : public inputState { + vector3d translation_ = {0.0, 0.0, 0.0}; + vector3d axis_ = {0.0, 0.0, 0.0}; + vector3d point_ = {0.0, 0.0, 0.0}; + double rotation_ = 0.0; + int endTag_ = -1; + + public: + // constructor + explicit periodic(string &str); + + // move constructor and assignment operator + periodic(periodic&&) noexcept = default; + periodic& operator=(periodic&&) noexcept = default; + + // copy constructor and assignment operator + periodic(const periodic&) = default; + periodic& operator=(const periodic&) = default; + + // Member functions + bool IsTranslation() const override { + return translation_ != vector3d(0.0, 0.0, 0.0); + } + bool IsRotation() const override { + return axis_ != vector3d(0.0, 0.0, 0.0); + } + const vector3d Translation() const override {return translation_;} + const vector3d Axis() const override {return axis_;} + const vector3d Point() const override {return point_;} + const double Rotation() const override {return rotation_;} + const int EndTag() const override {return endTag_;} + void Print(ostream &os) const override; + void Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) override; + + // Destructor + virtual ~periodic() noexcept {} +}; + // function declarations ostream &operator<<(ostream &, const inputState &); @@ -320,6 +395,7 @@ 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 &); vector Tokenize(string, const string &, const unsigned int = 0); @@ -327,10 +403,10 @@ string Trim(const string &, const string & = " \t\r\n"); vector3d ReadVector(const string &); vector ReadICList(ifstream &, string &); vector ReadStringList(ifstream &, string &); -vector> ReadBCList(ifstream &, string &); +vector> ReadBCList(ifstream &, string &); string RemoveTrailing(const string &, const string &); auto FindBCPosition(const string &, const vector &, string &); -void AddBCToList(const string &, vector> &, string &); +void AddBCToList(const string &, vector> &, string &); void CheckICTags(const vector &, const int &); #endif diff --git a/include/macros.hpp.in b/include/macros.hpp.in index 9890564..df11fb5 100644 --- a/include/macros.hpp.in +++ b/include/macros.hpp.in @@ -26,5 +26,8 @@ #define MAJORVERSION @aither_VERSION_MAJOR@ #define MINORVERSION @aither_VERSION_MINOR@ #define PATCHNUMBER @aither_VERSION_PATCH@ +#ifdef _WIN32 +#define MPI_CXX_BOOL MPI_C_BOOL +#endif #endif diff --git a/include/multiArray3d.hpp b/include/multiArray3d.hpp index 69ccc0e..8f8450e 100644 --- a/include/multiArray3d.hpp +++ b/include/multiArray3d.hpp @@ -27,9 +27,10 @@ #include // ostream #include // vector #include // string +#include // unique_ptr #include "mpi.h" #include "vector3d.hpp" -#include "boundaryConditions.hpp" // interblock +#include "boundaryConditions.hpp" // connection #include "range.hpp" // range using std::ostream; @@ -38,6 +39,7 @@ using std::cout; using std::cerr; using std::vector; using std::string; +using std::unique_ptr; template class multiArray3d { @@ -64,7 +66,7 @@ class multiArray3d { data_((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(1, 1, 1, 0) {} + multiArray3d() : multiArray3d(0, 0, 0, 0) {} // move constructor and assignment operator multiArray3d(multiArray3d&&) noexcept = default; @@ -138,10 +140,10 @@ class multiArray3d { const string = "cell", const int = 0); void Fill(const multiArray3d &); - void PutSlice(const multiArray3d &, const interblock &, const int &); - void SwapSliceMPI(const interblock &, const int &, const MPI_Datatype &, + void PutSlice(const multiArray3d &, const connection &, const int &); + void SwapSliceMPI(const connection &, const int &, const MPI_Datatype &, const int = 1); - void SwapSlice(const interblock &, multiArray3d &); + void SwapSlice(const connection &, multiArray3d &); void Zero(const T &); void Zero(); @@ -150,7 +152,7 @@ class multiArray3d { multiArray3d GrowJ() const; multiArray3d GrowK() const; - void PackSwapUnpackMPI(const interblock &, const MPI_Datatype &, const int &, + void PackSwapUnpackMPI(const connection &, const MPI_Datatype &, const int &, const int = 1); T GetElem(const int &ii, const int &jj, const int &kk) const; @@ -1045,9 +1047,9 @@ ostream &operator<<(ostream &os, const multiArray3d &arr) { template void multiArray3d::PutSlice(const multiArray3d &array, - const interblock &inter, const int &d3) { + const connection &inter, const int &d3) { // array -- array to insert into *this - // inter -- interblock data structure defining patches and orientation + // 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 @@ -1063,7 +1065,7 @@ void multiArray3d::PutSlice(const multiArray3d &array, exit(EXIT_FAILURE); } - // adjust insertion indices if patch borders another interblock on the same + // 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; @@ -1086,12 +1088,12 @@ void multiArray3d::PutSlice(const multiArray3d &array, } /*Member function to pack an array into a buffer, swap it with its - interblock partner, and then unpack it into an array.*/ + connection partner, and then unpack it into an array.*/ template -void multiArray3d::PackSwapUnpackMPI(const interblock &inter, +void multiArray3d::PackSwapUnpackMPI(const connection &inter, const MPI_Datatype &MPI_arrData, const int &rank, const int tag) { - // inter -- interblock boundary for the swap + // inter -- connection boundary for the swap // MPI_arrData -- MPI datatype to pass data type in array // rank -- processor rank // tag -- id to send data with (default 1) @@ -1108,7 +1110,10 @@ void multiArray3d::PackSwapUnpackMPI(const interblock &inter, &tempSize); bufSize += tempSize; - auto *buffer = new char[bufSize]; // allocate buffer to pack data into + // allocate buffer to pack data into + // use unique_ptr to manage memory; use underlying pointer for MPI calls + auto unqBuffer = unique_ptr(new char[bufSize]); + auto *buffer = unqBuffer.get(); // pack data into buffer auto numI = this->NumI(); @@ -1124,14 +1129,14 @@ void multiArray3d::PackSwapUnpackMPI(const interblock &inter, MPI_COMM_WORLD); MPI_Pack(&numGhosts, 1, MPI_INT, buffer, bufSize, &position, MPI_COMM_WORLD); - MPI_Pack(&data_[0], this->Size(), MPI_arrData, buffer, + 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 interblock + if (rank == inter.RankFirst()) { // send/recv with second entry in connection MPI_Sendrecv_replace(buffer, bufSize, MPI_PACKED, inter.RankSecond(), tag, inter.RankSecond(), tag, MPI_COMM_WORLD, &status); - } else { // send/recv with first entry in interblock + } else { // send/recv with first entry in connection MPI_Sendrecv_replace(buffer, bufSize, MPI_PACKED, inter.RankFirst(), tag, inter.RankFirst(), tag, MPI_COMM_WORLD, &status); } @@ -1149,10 +1154,8 @@ void multiArray3d::PackSwapUnpackMPI(const interblock &inter, // resize slice this->SameSizeResize(numI, numJ, numK); - MPI_Unpack(buffer, bufSize, &position, &data_[0], + MPI_Unpack(buffer, bufSize, &position, &(*std::begin(data_)), this->Size(), MPI_arrData, MPI_COMM_WORLD); - - delete[] buffer; } /* Function to swap slice using MPI. This is similar to the SwapSlice @@ -1160,10 +1163,10 @@ void multiArray3d::PackSwapUnpackMPI(const interblock &inter, processors. */ template -void multiArray3d::SwapSliceMPI(const interblock &inter, const int &rank, +void multiArray3d::SwapSliceMPI(const connection &conn, const int &rank, const MPI_Datatype &MPI_arrData, const int tag) { - // inter -- interblock boundary information + // conn -- connection boundary information // rank -- processor rank // MPI_arrData -- MPI datatype for passing data in *this // tag -- id for MPI swap (default 1) @@ -1173,13 +1176,13 @@ void multiArray3d::SwapSliceMPI(const interblock &inter, const int &rank, auto js = 0, je = 0; auto ks = 0, ke = 0; - if (rank == inter.RankFirst()) { // local block first in interblock - inter.FirstSliceIndices(is, ie, js, je, ks, ke, numGhosts_); - } else if (rank == inter.RankSecond()) { // local block second in interblock - inter.SecondSliceIndices(is, ie, js, je, ks, ke, numGhosts_); + 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 interblock ranks!" << endl; + "not match either of connection ranks!" << endl; exit(EXIT_FAILURE); } @@ -1187,25 +1190,25 @@ void multiArray3d::SwapSliceMPI(const interblock &inter, const int &rank, auto slice = this->Slice({is, ie}, {js, je}, {ks, ke}); // swap state slices with partner block - slice.PackSwapUnpackMPI(inter, MPI_arrData, rank, tag); + slice.PackSwapUnpackMPI(conn, MPI_arrData, rank, tag); - // change interblocks to work with slice and ghosts - auto interAdj = inter; + // change connections to work with slice and ghosts + auto connAdj = conn; - // change interblocks to work with slice and ghosts - // block to insert into is first in interblock - if (rank == inter.RankFirst()) { - interAdj.AdjustForSlice(true, numGhosts_); - } else { // block to insert into is second in interblock, so pass swapped + // 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 - interAdj.AdjustForSlice(false, numGhosts_); + connAdj.AdjustForSlice(false, numGhosts_); } // insert state slice into procBlock - this->PutSlice(slice, interAdj, numGhosts_); + this->PutSlice(slice, connAdj, numGhosts_); } -/* Function to swap ghost cells between two blocks at an interblock +/* 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 @@ -1221,42 +1224,42 @@ Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 | | The above diagram shows the resulting values after the ghost cell swap. The -logic ensures that the ghost cells at the interblock boundary exactly match +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 interblock &inter, +void multiArray3d::SwapSlice(const connection &conn, multiArray3d &array) { - // inter -- interblock boundary information - // array -- second array involved in interblock boundary + // 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; - inter.FirstSliceIndices(is1, ie1, js1, je1, ks1, ke1, numGhosts_); + 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; - inter.SecondSliceIndices(is2, ie2, js2, je2, ks2, ke2, array.GhostLayers()); + 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 interblocks to work with slice and ghosts - interblock inter1 = inter; - interblock inter2 = inter; - inter1.AdjustForSlice(false, numGhosts_); - inter2.AdjustForSlice(true, array.GhostLayers()); + // 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, inter2, array.GhostLayers()); - array.PutSlice(slice1, inter1, numGhosts_); + this->PutSlice(slice2, conn2, array.GhostLayers()); + array.PutSlice(slice1, conn1, numGhosts_); } diff --git a/include/output.hpp b/include/output.hpp index 8cea022..040b383 100644 --- a/include/output.hpp +++ b/include/output.hpp @@ -36,6 +36,7 @@ using std::vector; using std::string; using std::ios; using std::ofstream; +using std::ifstream; using std::cout; using std::endl; using std::cerr; @@ -51,24 +52,44 @@ class sutherland; class resid; class input; class turbModel; +class primVars; // function definitions -void WriteBlockDims(ofstream &, const vector &, int = 0); +template +void WriteBlockDims(ofstream &, const vector &, int = 0); void WriteCellCenter(const string &, const vector &, - const decomposition &, const double &); + const decomposition &, const input &); +void WriteWallFaceCenter(const string &, const vector &, + const double &); void WriteFun(const vector &, const idealGas &, const sutherland &, const int &, const decomposition &, const input &, const unique_ptr &); +void WriteWallFun(const vector &, const idealGas &, + const sutherland &, const int &, const input &, + const unique_ptr &); void WriteRes(const input &, const int &); void WriteMeta(const input &, const int &); +void WriteWallMeta(const input &, const int &); void WriteRestart(const vector &, const idealGas &, const sutherland &, const int &, const decomposition &, const input &, const genArray &); -void ReadRestart(vector &, const string &, input &, - const idealGas &, const sutherland &, - const unique_ptr &, genArray &); +void ReadRestart(vector &, const string &, const decomposition &, + input &, const idealGas &, const sutherland &, + const unique_ptr &, genArray &, + const vector> &); + +multiArray3d ReadSolFromRestart(ifstream &, const input &, + const idealGas&, const sutherland &, + const unique_ptr &, + const vector &, const int &, + const int &, const int &); +multiArray3d ReadSolNm1FromRestart(ifstream &, const input &, + const idealGas&, const sutherland &, + const unique_ptr &, + const vector &, const int &, + const int &, const int &); void WriteResiduals(const input &, genArray &, const genArray &, const resid &, const double &, const int &, const int &, ostream &); diff --git a/include/parallel.hpp b/include/parallel.hpp index 9c8dc4a..e862c74 100644 --- a/include/parallel.hpp +++ b/include/parallel.hpp @@ -40,33 +40,103 @@ using std::ostream; class boundaryConditions; class procBlock; class plot3dBlock; -class interblock; -class decomposition; +class connection; class resid; class genArray; +class decomposition { + // rank of each procBlock + // (vector size equals number of procBlocks after decomp) + vector rank_; + // parent block of each procBlock + // (vector size equals number of procBlocks after decomp) + vector parBlock_; + // local position of each procBlock + // (vector size equals number of procBlocks after decomp) + vector localPos_; + // lower block of split (vector size equals number of splits) + vector splitHistBlkLow_; + // upper block of split (vector size equals number of splits) + vector splitHistBlkUp_; + // index of split (vector size equals number of splits) + vector splitHistIndex_; + // direction of split (vector size equals number of splits) + vector splitHistDir_; + int numProcs_; // number of processors + + public: + // Constructor + decomposition(const int&, const int&); + decomposition() : decomposition(1, 1) {} + + // move constructor and assignment operator + decomposition(decomposition&&) noexcept = default; + decomposition& operator=(decomposition&&) noexcept = default; + + // copy constructor and assignment operator + decomposition(const decomposition&) = default; + decomposition& operator=(const decomposition&) = default; + + // Member functions + int Rank(const int &a) const {return rank_[a];} + int ParentBlock(const int &a) const {return parBlock_[a];} + int LocalPosition(const int &a) const {return localPos_[a];} + int NumProcs() const {return numProcs_;} + double IdealLoad(const vector&) const; + double MaxLoad(const vector&) const; + double MinLoad(const vector&) const; + double ProcLoad(const vector&, const int&) const; + double LoadRatio(const vector&, const int&) const; + int MostOverloadedProc(const vector&, double&) const; + int MostUnderloadedProc(const vector&, double&) const; + int NumBlocksOnProc(const int&) const; + vector NumBlocksOnAllProc() const; + int NumBlocks() const {return rank_.size();} + void SendToProc(const int&, const int&, const int&); + void Split(const int&, const int&, const string&); + int SendWholeOrSplit(const vector&, const int&, + const int&, int&, string&) const; + int Size() const {return static_cast (rank_.size());} + + int NumSplits() const {return static_cast (splitHistDir_.size());} + int SplitHistBlkLower(const int &a) const {return splitHistBlkLow_[a];} + int SplitHistBlkUpper(const int &a) const {return splitHistBlkUp_[a];} + int SplitHistIndex(const int &a) const {return splitHistIndex_[a];} + string SplitHistDir(const int &a) const {return splitHistDir_[a];} + template + void DecompArray(vector> &) const; + void PrintDiagnostics(const vector&) const; + + // Destructor + ~decomposition() noexcept {} +}; + // function definitions +ostream & operator<< (ostream &os, const decomposition&); + decomposition ManualDecomposition(vector&, vector&, const int&); decomposition CubicDecomposition(vector&, vector&, const int&); void SendNumProcBlocks(const vector&, int&); -void SendConnections(vector&, const MPI_Datatype&); +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&, MPI_Datatype&); void FreeDataTypesMPI(MPI_Datatype&, MPI_Datatype&, 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 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 MPI_Datatype&, + const MPI_Datatype&, const input &); void MaxLinf(resid*, resid*, int*, MPI_Datatype*); @@ -74,4 +144,24 @@ void BroadcastString(string& str); void BroadcastViscFaces(const MPI_Datatype&, vector> &); + +template +void decomposition::DecompArray(vector> &arr) const { + // resize vector for split blocks + arr.resize(this->NumBlocks()); + + // split array by decomposition + for (auto ii = 0; ii < this->NumSplits(); ++ii) { + auto ind = this->SplitHistIndex(ii); + auto lower = this->SplitHistBlkLower(ii); + auto upper = this->SplitHistBlkUpper(ii); + auto dir = this->SplitHistDir(ii); + auto lowerArray = arr[lower].Slice(dir, {arr[lower].Start(dir), ind + 1}); + auto upperArray = arr[lower].Slice(dir, {ind, arr[lower].End(dir)}); + + arr[lower] = lowerArray; + arr[upper] = upperArray; + } +} + #endif diff --git a/include/plot3d.hpp b/include/plot3d.hpp index 0d5f28a..4e16af0 100644 --- a/include/plot3d.hpp +++ b/include/plot3d.hpp @@ -42,7 +42,7 @@ class plot3dBlock { coords_(coordinates) {} plot3dBlock(const int &ii, const int &jj, const int &kk) : coords_(ii, jj, kk, 0) {} - plot3dBlock() : coords_(1, 1, 1, 0) {} + plot3dBlock() : coords_(0, 0, 0, 0) {} // move constructor and assignment operator plot3dBlock(plot3dBlock&&) noexcept = default; @@ -62,11 +62,16 @@ class plot3dBlock { multiArray3d> FaceCenterJ() const; multiArray3d> FaceCenterK() const; + vector3d Centroid(const int &, const int &, const int &) const; + int NumI() const { return coords_.NumI(); } int NumJ() const { return coords_.NumJ(); } int NumK() const { return coords_.NumK(); } + int NumCellsI() const { return coords_.NumI() - 1; } + int NumCellsJ() const { return coords_.NumJ() - 1; } + int NumCellsK() const { return coords_.NumK() - 1; } int NumCells() const { - return (coords_.NumI() - 1) * (coords_.NumJ() - 1) * (coords_.NumK() - 1); + return this->NumCellsI() * this->NumCellsJ() * this->NumCellsK(); } double X(const int &ii, const int &jj, const int &kk) const { return coords_(ii, jj, kk)[0]; @@ -91,6 +96,8 @@ class plot3dBlock { //------------------------------------------------------------------------- // function declarations vector ReadP3dGrid(const string &, const double &, double &); - +double PyramidVolume(const vector3d &, const vector3d &, + const vector3d &, const vector3d &, + const vector3d &); #endif diff --git a/include/primVars.hpp b/include/primVars.hpp index a3eb7d0..c888d22 100644 --- a/include/primVars.hpp +++ b/include/primVars.hpp @@ -51,6 +51,7 @@ using std::unique_ptr; // forward class declarations class input; class turbModel; +struct wallVars; class primVars { double data_[NUMVARS]; // primative variables at cell center @@ -65,7 +66,10 @@ class primVars { : 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 double &p, const vector3d &v) + 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 idealGas &, const unique_ptr &); @@ -87,8 +91,9 @@ class primVars { double Tke() const { return data_[5]; } double Omega() const { return data_[6]; } - void NondimensionalInitialize(const idealGas&, const double&, const input&, - const sutherland&, const int&); + void NondimensionalInitialize(const idealGas &, const input &, + const sutherland &, const int &, + const unique_ptr &); bool IsZero() const; primVars Squared() const; primVars Abs() const; @@ -106,7 +111,7 @@ class primVars { void ApplyFarfieldTurbBC(const vector3d &, const double &, const double &, const sutherland &, - const idealGas &); + const idealGas &, const unique_ptr &); void LimitTurb(const unique_ptr &); double InvCellSpectralRadius(const unitVec3dMag &, @@ -195,19 +200,14 @@ class primVars { primVars GetGhostState(const string &, const vector3d &, const double &, const int &, const input &, const int &, const idealGas &, const sutherland &, - const unique_ptr &, const int = 1) const; + const unique_ptr &, wallVars &, + const int = 1) const; // destructor ~primVars() noexcept {} }; // function definitions -multiArray3d GetGhostStates( - const multiArray3d &, const string &, - const multiArray3d> &, const multiArray3d &, - const int &, const input &, const int &, const idealGas &, const sutherland &, - const unique_ptr &, const int = 1); - // member function to calculate temperature from conserved variables and // equation of state double primVars::Temperature(const idealGas &eqnState) const { diff --git a/include/procBlock.hpp b/include/procBlock.hpp index 5d65b98..7daa73a 100644 --- a/include/procBlock.hpp +++ b/include/procBlock.hpp @@ -23,15 +23,17 @@ #include #include #include +#include #include "mpi.h" // parallelism #include "vector3d.hpp" // vector3d #include "multiArray3d.hpp" // multiArray3d #include "tensor.hpp" // tensor #include "primVars.hpp" // primVars #include "genArray.hpp" // genArray -#include "boundaryConditions.hpp" // interblock, patch +#include "boundaryConditions.hpp" // connection, patch #include "macros.hpp" #include "uncoupledScalar.hpp" // uncoupledScalar +#include "wallData.hpp" using std::vector; using std::string; @@ -97,6 +99,8 @@ class procBlock { boundaryConditions bc_; // boundary conditions for block + vector wallData_; // wall variables at viscous walls + int numGhosts_; // number of layers of ghost cells surrounding block int parBlock_; // parent block number int rank_; // processor rank @@ -105,6 +109,7 @@ class procBlock { // procBlocks bool isViscous_; bool isTurbulent_; + bool isRANS_; bool storeTimeN_; bool isMultiLevelTime_; @@ -150,16 +155,18 @@ class procBlock { const int &); void SubtractFromResidual(const source &, const int &, const int &, const int &); - + vector SplitWallData(const string &, const int &); + void JoinWallData(const vector &, const string &); public: // constructors - procBlock(const double &, const plot3dBlock &, const int &, - const boundaryConditions &, const int &, const int &, const int &, - const input &, const idealGas &, const sutherland &); + procBlock(const plot3dBlock &, const int &, const boundaryConditions &, + const int &, const int &, const int &, const input &, + const idealGas &, const sutherland &, + const unique_ptr &); procBlock(const int &, const int &, const int &, const int &, const bool &, - const bool &, const bool &, const bool &); - procBlock() : procBlock(1, 1, 1, 0, false, false, false, false) {} + const bool &, const bool &, const bool &, const bool &); + procBlock() : procBlock(1, 1, 1, 0, false, false, false, false, false) {} // move constructor and assignment operator procBlock(procBlock&&) noexcept = default; @@ -212,15 +219,16 @@ class procBlock { } } - int NumGhosts() const { return numGhosts_; } - int ParentBlock() const { return parBlock_; } - int LocalPosition() const { return localPos_; } - int Rank() const { return rank_; } - int GlobalPos() const { return globalPos_; } - bool IsViscous() const { return isViscous_; } - bool IsTurbulent() const { return isTurbulent_; } + int NumGhosts() const {return numGhosts_;} + int ParentBlock() const {return parBlock_;} + int LocalPosition() const {return localPos_;} + int Rank() const {return rank_;} + int GlobalPos() const {return globalPos_;} + bool IsViscous() const {return isViscous_;} + bool IsTurbulent() const {return isTurbulent_;} + bool IsRANS() const {return isRANS_;} - boundaryConditions BC() const { return bc_; } + boundaryConditions BC() const {return bc_;} primVars State(const int &ii, const int &jj, const int &kk) const { return state_(ii, jj, kk); @@ -235,6 +243,7 @@ class procBlock { multiArray3d SliceState(const int &, const int &, const int &, const int &, const int &, const int &) const; + multiArray3d> SliceBoundaryCenters(const int &) const; void AssignSolToTimeN(const idealGas &); void AssignSolToTimeNm1(); @@ -306,6 +315,14 @@ class procBlock { double CellWidthK(const int &ii, const int &jj, const int &kk) const { return cellWidthK_(ii, jj, kk); } + double MaxCellWidth(const int &ii, const int &jj, const int &kk) const { + return std::max(std::max(cellWidthI_(ii, jj, kk), cellWidthJ_(ii, jj, kk)), + cellWidthK_(ii, jj, kk)); + } + double MinCellWidth(const int &ii, const int &jj, const int &kk) const { + return std::min(std::min(cellWidthI_(ii, jj, kk), cellWidthJ_(ii, jj, kk)), + cellWidthK_(ii, jj, kk)); + } uncoupledScalar SpectralRadius(const int &ii, const int &jj, const int &kk) const { @@ -327,17 +344,17 @@ class procBlock { } tensor VelGrad(const int &ii, const int &jj, const int &kk) const { - return velocityGrad_(ii, jj, kk); + return isViscous_ ? velocityGrad_(ii, jj, kk) : tensor(0.0); } vector3d TempGrad(const int &ii, const int &jj, const int &kk) const { - return temperatureGrad_(ii, jj, kk); + return isViscous_ ? temperatureGrad_(ii, jj, kk) : vector3d(); } vector3d TkeGrad(const int &ii, const int &jj, const int &kk) const { - return tkeGrad_(ii, jj, kk); + return isRANS_ ? tkeGrad_(ii, jj, kk) : vector3d(); } vector3d OmegaGrad(const int &ii, const int &jj, const int &kk) const { - return omegaGrad_(ii, jj, kk); + return isRANS_ ? omegaGrad_(ii, jj, kk) : vector3d(); } double Temperature(const int &ii, const int &jj, const int &kk) const { @@ -350,15 +367,15 @@ class procBlock { return isTurbulent_ ? eddyViscosity_(ii, jj, kk) : 0.0; } double F1(const int &ii, const int &jj, const int &kk) const { - return isTurbulent_ ? f1_(ii, jj, kk) : 0.0; + return isRANS_ ? f1_(ii, jj, kk) : 0.0; } double F2(const int &ii, const int &jj, const int &kk) const { - return isTurbulent_ ? f2_(ii, jj, kk) : 0.0; + return isRANS_ ? f2_(ii, jj, kk) : 0.0; } - void CalcBlockTimeStep(const input &, const double &); - void UpdateBlock(const input &, const idealGas &, const double &, - const sutherland &, const multiArray3d &, + void CalcBlockTimeStep(const input &); + void UpdateBlock(const input &, const idealGas &, const sutherland &, + const multiArray3d &, const unique_ptr &, const int &, genArray &, resid &); @@ -390,6 +407,11 @@ class procBlock { void AssignViscousGhostCellsEdge(const input &, const idealGas &, const sutherland &, const unique_ptr &); + multiArray3d GetGhostStates( + const multiArray3d &, const string &, + const multiArray3d> &, const multiArray3d &, + const boundarySurface &, const input &, const idealGas &, + const sutherland &, const unique_ptr &, const int = 1); void CalcGradsI(const int &, const int &, const int &, tensor &, vector3d &, vector3d &, @@ -432,31 +454,39 @@ class procBlock { bool AtCorner(const int &, const int &, const int &) const; bool AtEdge(const int &, const int &, const int &, string &) const; bool AtEdgeInclusive(const int &, const int &, const int &, string &) const; + bool AtGhostNonEdge(const int &, const int &, const int &, string &, + int &) const; - vector PutGeomSlice(const geomSlice &, interblock &, const int &); - void PutStateSlice(const multiArray3d &, const interblock &, + vector PutGeomSlice(const geomSlice &, connection &, const int &); + void PutStateSlice(const multiArray3d &, const connection &, const int &, const int &); procBlock Split(const string &, const int &, const int &, vector &); void Join(const procBlock &, const string &, vector &); - void SwapStateSlice(const interblock &, procBlock &); - void SwapStateSliceMPI(const interblock &, const int &, const MPI_Datatype &); - void SwapTurbSlice(const interblock &, procBlock &); - void SwapTurbSliceMPI(const interblock &, const int &); - void SwapGradientSlice(const interblock &, procBlock &); - void SwapGradientSliceMPI(const interblock &, const int &, - const MPI_Datatype &, const MPI_Datatype &); + void SwapStateSlice(const connection &, procBlock &); + void SwapStateSliceMPI(const connection &, const int &, const MPI_Datatype &); + void SwapTurbSlice(const connection &, procBlock &); + void SwapTurbSliceMPI(const connection &, const int &); + void SwapWallDistSlice(const connection &, procBlock &); + void SwapWallDistSliceMPI(const connection &, const int &); + void SwapEddyViscAndGradientSlice(const connection &, procBlock &); + void SwapEddyViscAndGradientSliceMPI(const connection &, const int &, + const MPI_Datatype &, + const MPI_Datatype &); void PackSendGeomMPI(const MPI_Datatype &, const MPI_Datatype &, - const MPI_Datatype &) const; + const MPI_Datatype &, const MPI_Datatype &) const; void RecvUnpackGeomMPI(const MPI_Datatype &, 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; + 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 MPI_Datatype &, + const MPI_Datatype &, const input &); void UpdateAuxillaryVariables(const idealGas &, const sutherland &, const bool = true); @@ -467,12 +497,62 @@ class procBlock { void DumpToFile(const string &, const string &) const; void CalcCellWidths(); - void ReadSolFromRestart(ifstream &, const input &, const idealGas &, - const sutherland &, const unique_ptr &, - const vector &); - void ReadSolNm1FromRestart(ifstream &, const input &, const idealGas &, - const sutherland &, const unique_ptr &, - const vector &); + void GetStatesFromRestart(const multiArray3d &); + void GetSolNm1FromRestart(const multiArray3d &); + + int WallDataIndex(const boundarySurface &) const; + int WallDataSize() const {return wallData_.size();} + bool HasWallData() const {return this->WallDataSize() > 0;} + boundarySurface WallSurface(const int &ii) const { + return wallData_[ii].Surface(); + } + int NumWallSurfI(const int &ii) const { return wallData_[ii].NumI(); } + int NumWallSurfJ(const int &ii) const { return wallData_[ii].NumJ(); } + int NumWallSurfK(const int &ii) const { return wallData_[ii].NumK(); } + double WallYplus(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].Yplus(ii, jj, kk); + } + double WallHeatFlux(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallHeatFlux(ii, jj, kk); + } + vector3d WallShearStress(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallShearStress(ii, jj, kk); + } + double WallTemperature(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallTemperature(ii, jj, kk); + } + double WallEddyVisc(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallEddyViscosity(ii, jj, kk); + } + double WallViscosity(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallViscosity(ii, jj, kk); + } + double WallDensity(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallDensity(ii, jj, kk); + } + double WallFrictionVelocity(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallFrictionVelocity(ii, jj, kk); + } + double WallPressure(const int &ss, const int &ii, const int &jj, + const int &kk, const idealGas &eos) const { + return wallData_[ss].WallPressure(ii, jj, kk, eos); + } + double WallTke(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallTke(ii, jj, kk); + } + double WallSdr(const int &ss, const int &ii, const int &jj, + const int &kk) const { + return wallData_[ss].WallSdr(ii, jj, kk); + } // destructor ~procBlock() noexcept {} diff --git a/include/range.hpp b/include/range.hpp index 830c35a..7198e22 100644 --- a/include/range.hpp +++ b/include/range.hpp @@ -67,6 +67,11 @@ class range { void ShrinkStart() {start_--;} void ShrinkEnd() {end_--;} + // operator overload + bool operator==(const range &r2) const { + return (start_ == r2.start_ && end_ == r2.end_) ? true : false; + } + // destructor ~range() noexcept {} }; diff --git a/include/slices.hpp b/include/slices.hpp index b83b31f..e50f82e 100644 --- a/include/slices.hpp +++ b/include/slices.hpp @@ -36,7 +36,7 @@ using std::cerr; // forward class declaration class procBlock; -class interblock; +class connection; class range; class geomSlice { diff --git a/include/source.hpp b/include/source.hpp index d677a07..d175f12 100644 --- a/include/source.hpp +++ b/include/source.hpp @@ -73,7 +73,7 @@ class source { const tensor &, const vector3d &, const vector3d &, const vector3d &, const sutherland &, const double &, const double &, - const double &); + const double &, const double &, const double &); inline source & operator+=(const source &); inline source & operator-=(const source &); diff --git a/include/turbulence.hpp b/include/turbulence.hpp index ed95517..b24c98d 100644 --- a/include/turbulence.hpp +++ b/include/turbulence.hpp @@ -24,6 +24,7 @@ #include // sqrt #include // vector #include // string +#include #include "vector3d.hpp" // vector3d #include "tensor.hpp" // tensor @@ -54,21 +55,27 @@ class turbModel { // member functions string EddyViscMethod() const {return eddyViscMethod_;} + tensor MeanStrainRate(const tensor &) const; virtual double EddyViscNoLim(const primVars &state) const; virtual double TurbPrandtlNumber() const {return 0.9;} virtual double TkeMin() const {return 1.0e-20;} virtual double OmegaMin() const {return 1.0e-20;} 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, const tensor &vGrad, const sutherland &suth, - const double &f2) const {return 0.0;} + 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, - const sutherland &suth, - const double &vol) const {return 0.0;} + const sutherland &suth, 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; @@ -98,7 +105,6 @@ class turbModel { const double &mu, const sutherland &suth, const double &dist, const double &mut, const double &f1) const {return 0.0;} - tensor BoussinesqReynoldsStress(const primVars &state, const tensor &velGrad, const sutherland &suth, @@ -107,7 +113,7 @@ class turbModel { const tensor &velGrad, const sutherland &suth, const double &mut) const; - double TkeDestruction(const primVars &state) const; + double TkeDestruction(const primVars &state, const double &phi = 1.0) const; double OmegaDestruction(const primVars &state) const; double CrossDiffusion(const primVars &state, const vector3d &kGrad, @@ -124,8 +130,6 @@ class turbModel { const double &mu, const sutherland &suth, const double &dist, const double &mut, const double & f1, const bool &positive) const; - - // abstract functions virtual squareMatrix CalcTurbSrc(const primVars &state, const tensor &velGrad, const vector3d &kGrad, @@ -133,21 +137,24 @@ class turbModel { const sutherland &suth, const double &vol, const double &mut, const double &f1, - double &ksrc, double &wsrc) const = 0; + const double &f2, const double &width, + double &ksrc, double &wsrc) const; + virtual squareMatrix TurbSrcJac(const primVars &state, + const double &beta, + const sutherland &suth, + const double &vol, + const double &phi = 1.0) const; + + // abstract functions (need one for abstract base class) virtual void EddyViscAndBlending(const primVars &state, const tensor &vGrad, const vector3d &kGrad, const vector3d &wGrad, const double &mu, const double &wallDist, - const sutherland &suth, + const sutherland &suth, const double &length, double &mut, double &f1, double &f2) const = 0; - virtual squareMatrix TurbSrcJac(const primVars &state, - const double &beta, - const sutherland &suth, - const double &vol) const = 0; - virtual void Print() const = 0; // destructor @@ -169,19 +176,13 @@ class turbNone : public turbModel { turbNone& operator=(const turbNone&) = default; // member functions - squareMatrix CalcTurbSrc(const primVars &state, const tensor &velGrad, - const vector3d &kGrad, - const vector3d &wGrad, - const sutherland &suth, const double &vol, - const double &mut, const double &f1, double &ksrc, - double &wsrc) const override; void EddyViscAndBlending(const primVars &state, const tensor &vGrad, const vector3d &kGrad, const vector3d &wGrad, const double &mu, const double &wallDist, - const sutherland &suth, + const sutherland &suth, const double &length, double &mut, double &f1, double &f2) const override {} double EddyViscNoLim(const primVars &state) const override {return 0.0;} @@ -203,9 +204,6 @@ class turbNone : public turbModel { const primVars &state, const unitVec3dMag &fArea) const override; squareMatrix InviscidDissJacobian( const primVars &state, const unitVec3dMag &fArea) const override; - squareMatrix TurbSrcJac(const primVars &state, const double &beta, - const sutherland &suth, - const double &vol) const override; double TkeMin() const override {return 0.0;} double OmegaMin() const override {return 0.0;} @@ -252,19 +250,20 @@ class turbKWWilcox : public turbModel { squareMatrix CalcTurbSrc(const primVars &, const tensor &, const vector3d &, const vector3d &, const sutherland &, const double &, - const double &, const double &, double &, - double &) const override; + const double &, const double &, const double &, + const double &, double &, double &) const override; double EddyVisc(const primVars&, const tensor &, - const sutherland &, const double &) const override; + const sutherland &, const double &, + const double &) const override; void EddyViscAndBlending(const primVars &, const tensor &, const vector3d &, const vector3d &, const double &, const double &, - const sutherland &, double &, double &, - double &) const override; + const sutherland &, const double &, double &, + double &, double &) const override; bool UseUnlimitedEddyVisc() const override {return true;} double SrcSpecRad(const primVars &, const sutherland &, - const double &) const override; + const double &, const double & = 1.0) const override; squareMatrix ViscousJacobian(const primVars &, const unitVec3dMag &, const double &, const sutherland &, @@ -283,13 +282,16 @@ class turbKWWilcox : public turbModel { const double &) const override; squareMatrix TurbSrcJac(const primVars &, const double &, - const sutherland &, const double &) const override; + const sutherland &, 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, const sutherland &) const; + double Gamma() const {return gamma_;} - double BetaStar() const {return betaStar_;} + double BetaStar() const override {return betaStar_;} double Sigma() const {return sigma_;} double SigmaStar() const {return sigmaStar_;} double SigmaD0() const {return sigmaD0_;} @@ -298,6 +300,8 @@ class turbKWWilcox : public turbModel { double SigmaK(const double &f1) const override {return this->SigmaStar();} double SigmaW(const double &f1) const override {return this->Sigma();} + double WallSigmaK() const override {return this->SigmaStar();} + double WallSigmaW() const override {return this->Sigma();} void Print() const override; @@ -320,11 +324,8 @@ class turbKWSst : public turbModel { const double kProd2Dest_ = 10.0; // private member functions - double CDkw(const primVars &, const vector3d &, - const vector3d &) const; double F1(const double &, const double &, const double &) const; double F2(const double &, const double &) const; - double BlendedCoeff(const double &, const double &, const double &) const; double Alpha1(const primVars &, const sutherland &, const double &) const; double Alpha2(const primVars &, const sutherland &, const double &, const double &) const; @@ -345,22 +346,28 @@ class turbKWSst : public turbModel { turbKWSst& operator=(const turbKWSst&) = default; // member functions - squareMatrix CalcTurbSrc(const primVars &, const tensor &, - const vector3d &, const vector3d &, - const sutherland &, const double &, - const double &, const double &, double &, - double &) const override; + double BlendedCoeff(const double &, const double &, const double &) const; + double CDkw(const primVars &, const vector3d &, + const vector3d &) const; + virtual squareMatrix CalcTurbSrc(const primVars &, const tensor &, + const vector3d &, + const vector3d &, + const sutherland &, const double &, + const double &, const double &, + const double &, const double &, double &, + double &) const override; double EddyVisc(const primVars &, const tensor &, - const sutherland &, const double &) const override; + const sutherland &, const double &, + const double &) const override; void EddyViscAndBlending(const primVars &, const tensor &, const vector3d &, const vector3d &, const double &, const double &, - const sutherland &, double &, double &, - double &) const override; + const sutherland &, const double &, double &, + double &, double &) const override; - double SrcSpecRad(const primVars &, const sutherland &, - const double &) const override; + virtual double SrcSpecRad(const primVars &, const sutherland &, + const double &, const double & = 1.0) const override; squareMatrix ViscousJacobian(const primVars &, const unitVec3dMag &, const double &, const sutherland &, @@ -378,8 +385,10 @@ class turbKWSst : public turbModel { const double &, const double &, const double &) const override; - squareMatrix TurbSrcJac(const primVars &, const double &, - const sutherland &, const double &) const override; + virtual squareMatrix TurbSrcJac(const primVars &, const double &, + const sutherland &, + const double &, + const double & = 1.0) const override; double WallBeta() const override {return beta1_;} double TurbPrandtlNumber() const override {return prt_;} @@ -395,7 +404,9 @@ class turbKWSst : public turbModel { double SigmaW2() const {return sigmaW2_;} double A1() const {return a1_;} - double BetaStar() const {return betaStar_;} + double BetaStar() const override {return betaStar_;} + double TkeProd2DestRatio() const {return kProd2Dest_;} + double TurbLengthScale(const primVars &state, const sutherland &) const; // use coefficients from 1 because they are smaller // this is used for TSL flux jacobian, so smaller will help increase @@ -406,14 +417,105 @@ class turbKWSst : public turbModel { double SigmaW(const double &f1) const override { return this->BlendedCoeff(sigmaW1_, sigmaW2_, f1); } + double WallSigmaK() const override {return sigmaK1_;} + double WallSigmaW() const override {return sigmaW1_;} + + void Print() const override; + + // destructor + 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 sutherland &suth) const; + + public: + // constructor + turbSstDes() : turbKWSst() {} + explicit turbSstDes(const string &meth) : turbKWSst(meth) {} + + // move constructor and assignment operator + turbSstDes(turbSstDes &&model) noexcept : turbKWSst(std::move(model)) {} + turbSstDes& operator=(turbSstDes&&) = default; + + // copy constructor and assignment operator + turbSstDes(const turbSstDes &model) : turbKWSst(model) {} + turbSstDes& operator=(const turbSstDes&) = default; + + + squareMatrix CalcTurbSrc(const primVars &, const tensor &, + const vector3d &, const vector3d &, + const sutherland &, const double &, + const double &, const double &, const double &, + const double &, double &, double &) const override; + + double SrcSpecRad(const primVars &, const sutherland &, + const double &, const double &) const override; + + double CDes1() const {return cdes1_;} + double CDes2() const {return cdes2_;} + double CDes(const double &f1) const { + return this->BlendedCoeff(cdes1_, cdes2_, f1); + } + bool UsePhi() const override {return true;} void Print() const override; // destructor - ~turbKWSst() noexcept {} + ~turbSstDes() noexcept {} }; +class turbWale : public turbModel { + const double cw_ = 0.544; + + // private member functions + + public: + // constructor + turbWale() : turbModel() {} + explicit turbWale(const string &meth) : turbModel(meth) {} + + // move constructor and assignment operator + turbWale(turbWale &&model) noexcept : turbModel(std::move(model)) {} + turbWale& operator=(turbWale&&) = default; + + // copy constructor and assignment operator + turbWale(const turbWale &model) : turbModel(model) {} + turbWale& operator=(const turbWale&) = default; + + double EddyVisc(const primVars &state, const tensor &vGrad, + const sutherland &suth, const double &f2, + const double &length) const override; + + void EddyViscAndBlending(const primVars &state, const tensor &vGrad, + const vector3d &kGrad, + const vector3d &wGrad, + const double &mu, const double &wallDist, + const sutherland &suth, const double &length, + double &mut, double &f1, + double &f2) const override { + f1 = 1.0; + f2 = 0.0; + mut = this->EddyVisc(state, vGrad, suth, f2, length); + } + + double Cw() const {return cw_;} + tensor SigmaD(const tensor &vGrad) const; + void Print() const override; + + // destructor + ~turbWale() noexcept {} +}; + + + // function declarations diff --git a/include/utility.hpp b/include/utility.hpp index c222e05..9232000 100644 --- a/include/utility.hpp +++ b/include/utility.hpp @@ -20,6 +20,7 @@ #include // vector #include +#include #include "mpi.h" // parallelism #include "vector3d.hpp" // vector3d #include "multiArray3d.hpp" // multiArray3d @@ -63,11 +64,11 @@ vector3d ScalarGradGG( const vector3d &, const vector3d &, const vector3d &, const double &); -void SwapGeomSlice(interblock &, procBlock &, procBlock &); +void SwapGeomSlice(connection &, procBlock &, procBlock &); void GetBoundaryConditions(vector &, const input &, const idealGas &, const sutherland &, const unique_ptr &, - vector &, const int &, + vector &, const int &, const MPI_Datatype &); vector> GetViscousFaceCenters(const vector &); @@ -77,32 +78,33 @@ void AssignSolToTimeN(vector &, const idealGas &); void AssignSolToTimeNm1(vector &); void ExplicitUpdate(vector &, const input &, const idealGas &, - const double &, const sutherland &, - const unique_ptr &, const int &, genArray &, - resid &); + const sutherland &, const unique_ptr &, + const int &, genArray &, resid &); double ImplicitUpdate(vector &, vector> &, - const input &, const idealGas &, const double &, - const sutherland &, const unique_ptr &, - const int &, genArray &, resid &, - const vector &, const int &, + const input &, const idealGas &, const sutherland &, + const unique_ptr &, const int &, genArray &, + resid &, const vector &, const int &, const MPI_Datatype &); void SwapImplicitUpdate(vector> &, - const vector &, const int &, + const vector &, const int &, const MPI_Datatype &, const int &); -void SwapTurbVars(vector &, const vector &, const int &, +void SwapTurbVars(vector &, const vector &, const int &, const int &); -void SwapGradients(vector &, const vector &, const int &, - const MPI_Datatype &, const MPI_Datatype &, const int &); +void SwapWallDist(vector &, const vector &, const int &, + const int &); +void SwapEddyViscAndGradients(vector &, const vector &, + const int &, const MPI_Datatype &, + const MPI_Datatype &, const int &); void CalcResidual(vector &, vector> &, const sutherland &, const idealGas &, const input &, const unique_ptr &, - const vector &, const int &, const MPI_Datatype &, + const vector &, const int &, const MPI_Datatype &, const MPI_Datatype &); -void CalcTimeStep(vector &, const input &, const double &); +void CalcTimeStep(vector &, const input &); // void GetSolMMinusN(vector> &, const vector &, // const vector> &, @@ -116,6 +118,8 @@ void ResizeArrays(const vector &, const input &, vector3d TauNormal(const tensor &, const vector3d &, const double &, const double &, const sutherland &); +vector3d TauShear(const tensor &, const vector3d &, + const double &, const double &, const sutherland &); vector LagrangeCoeff(const vector &, const unsigned int &, const int &, const int &); @@ -137,6 +141,9 @@ primVars BetaIntegral(const primVars &, const primVars &, const double &, primVars BetaIntegral(const primVars &, const primVars &, const double &, const double &, const double &); +tensor CalcVelGradTSL(const primVars&, const primVars&, + const vector3d&, const double&); + // --------------------------------------------------------------------------- // inline function definitions @@ -183,5 +190,67 @@ T Derivative2nd(const double &x_0, const double &x_1, const double &x_2, return (fwdDiff1stOrder - bckDiff1stOrder) / (0.25 * (x_2 + x_0) + 0.5 * x_1); } +// function to implement mathematical sign function +template +int Sign (const T &val) { + return (T(0) < val) - (val < T(0)); +} + +// function to find the root of a function using Ridder's method +template +T1 FindRoot(const T2 &func, T1 x1, T1 x2, const T1 &tol, + const int &maxIter = 100) { + // check that x1 and x2 bracket root + auto f1 = func(x1); + auto f2 = func(x2); + if (Sign(f1) == Sign(f2) && Sign(f1) != 0.0) { + cerr << "ERROR. Root is not within specified interval!" << endl; + return 0.5 * (x1 + x2); + } + + // intialize variable outside of loop so it can be accessed if routine does + // not converge + auto x4 = x1; + for (auto ii = 0; ii < maxIter; ++ii) { + auto x3 = 0.5 * (x1 + x2); + auto f3 = func(x3); + if (f3 == 0.0) { // root found + return x3; + } + + auto denom = sqrt(std::abs(f3 * f3 - f1 * f2)); + if (denom == 0.0) { + return x3; + } + auto fac = Sign(f1 - f2); + x4 = x3 + (x3 - x1) * (fac * f3) / denom; + auto f4 = func(x4); + + if (f4 == 0.0) { // root found + return x4; + } + + if (Sign(f4) != Sign(f3)) { // f4/f3 opposite sign + x1 = x3; + f1 = f3; + x2 = x4; + f2 = f4; + } else if (Sign(f4) != Sign(f1)) { // f4/f1 opposite sign + x2 = x4; + f2 = f4; + } else { + x1 = x4; + f1 = f4; + } + + if (std::abs(x2 - x1) <= tol) { + return x4; + } + } + + cerr << "ERROR: FindRoot did not converge!" << endl; + return x4; +} + #endif diff --git a/include/vector3d.hpp b/include/vector3d.hpp index 778c07f..cf7cce9 100644 --- a/include/vector3d.hpp +++ b/include/vector3d.hpp @@ -60,6 +60,8 @@ class vector3d { T& operator[](const int &a) { return data_[a]; } bool operator==(const vector3d&) const; + bool operator!=(const vector3d &v1) const {return !(*this == v1);} + bool CompareWithTol(const vector3d &v2, const double &tol = 1.0e-10) const; inline vector3d & operator+=(const vector3d &); inline vector3d & operator-=(const vector3d &); @@ -138,6 +140,7 @@ class unitVec3dMag { // member functions // operator overloads bool operator==(const unitVec3dMag&) const; + bool operator!=(const unitVec3dMag &v1) const {return !(*this == v1);} inline unitVec3dMag & operator+=(const unitVec3dMag &); inline unitVec3dMag & operator-=(const unitVec3dMag &); @@ -317,6 +320,18 @@ bool vector3d::operator==(const vector3d&v2) const { return test; } +template +bool vector3d::CompareWithTol(const vector3d &v2, const double &tol) const { + auto test = false; + auto diff = (*this) - v2; + + if (fabs(diff[0]) < tol && fabs(diff[1]) < tol && fabs(diff[2]) < tol) { + test = true; + } + return test; +} + + // Function to calculate the cross product of two vectors template vector3d vector3d::CrossProd(const vector3d&v2) const { diff --git a/include/viscousFlux.hpp b/include/viscousFlux.hpp index 1ed3b57..0bae8a2 100644 --- a/include/viscousFlux.hpp +++ b/include/viscousFlux.hpp @@ -32,7 +32,7 @@ using std::cout; using std::endl; using std::cerr; using std::ostream; -using std:: unique_ptr; +using std::unique_ptr; // forward class declarations class primVars; @@ -40,6 +40,7 @@ class idealGas; class sutherland; class turbModel; class squareMatrix; +struct wallVars; class viscousFlux { double data_[NUMVARS - 1]; // viscous flux for x-momentum equation @@ -50,11 +51,6 @@ class viscousFlux { public: // constructors viscousFlux() : data_{0.0} {} - viscousFlux(const tensor&, const sutherland&, const idealGas&, - const vector3d&, const vector3d&, - const vector3d&, const vector3d&, - const unique_ptr&, const primVars&, - const double&, const double&, const double&); // move constructor and assignment operator viscousFlux(viscousFlux&&) noexcept = default; @@ -72,6 +68,22 @@ class viscousFlux { double MomK() const { return data_[4]; } double MomO() const { return data_[5]; } + void CalcFlux(const tensor &, const sutherland &, const idealGas &, + const vector3d &, const vector3d &, + const vector3d &, const vector3d &, + const unique_ptr &, const primVars &, const double &, + const double &, const double &); + wallVars CalcWallFlux(const tensor &, const sutherland &, + const idealGas &, const vector3d &, + const vector3d &, const vector3d &, + const vector3d &, const unique_ptr &, + const primVars &, 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 &); @@ -107,14 +119,6 @@ class viscousFlux { }; // function definitions -void CalcTSLFluxJac(const double&, const double&, const idealGas&, - const vector3d&, const primVars&, const primVars&, - const double&, squareMatrix&, squareMatrix&, - const sutherland&, const double&); - -tensor CalcVelGradTSL(const primVars&, const primVars&, - const vector3d&, const double&); - // operator overload for addition viscousFlux & viscousFlux::operator+=(const viscousFlux &arr) { for (auto rr = 0; rr < NUMVARS - 1; rr++) { diff --git a/include/wallData.hpp b/include/wallData.hpp new file mode 100644 index 0000000..83b4e81 --- /dev/null +++ b/include/wallData.hpp @@ -0,0 +1,139 @@ +/* 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 WALLDATAHEADERDEF +#define WALLDATAHEADERDEF + +/* This header file contains the wallData class +*/ + +#include +#include +#include "mpi.h" +#include "multiArray3d.hpp" +#include "inputStates.hpp" +#include "boundaryConditions.hpp" +#include "range.hpp" + +using std::vector; +using std::shared_ptr; + +// forward declarations +class input; +class idealGas; +class primVars; + +// structure to hold wall variables +struct wallVars { + vector3d shearStress_ = {0.0, 0.0, 0.0}; + double heatFlux_ = 0.0; + double yplus_ = 0.0; + double temperature_ = 0.0; + double turbEddyVisc_ = 0.0; + double viscosity_ = 0.0; + double density_ = 0.0; + double frictionVelocity_ = 0.0; + double tke_ = 0.0; + double sdr_ = 0.0; + + bool SwitchToLowRe() const {return yplus_ < 10.;} +}; + +class wallData { + double inviscidForce_; + double viscousForce_; + shared_ptr bcData_; + boundarySurface surf_; + multiArray3d data_; + + public: + // constructor + wallData(const boundarySurface &surf, const shared_ptr &bc) + : inviscidForce_(0.0), + viscousForce_(0.0), + bcData_(bc), + surf_(surf), + data_(surf.NumI(), surf.NumJ(), surf.NumK(), 0) {} + wallData() : wallData(boundarySurface(), nullptr) {} + + // move constructor and assignment operator + wallData(wallData &&) = default; + wallData &operator=(wallData &&) = default; + + // copy constructor and assignment operator + wallData(const wallData &) = default; + wallData &operator=(const wallData &) = default; + + // member functions + int NumI() const { return data_.NumI(); } + int NumJ() const { return data_.NumJ(); } + int NumK() const { return data_.NumK(); } + int Size() const { return data_.Size(); } + double InviscidForce() const { return inviscidForce_; } + double ViscousForce() const { return viscousForce_; } + vector3d WallShearStress(const int &ii, const int &jj, + const int &kk) const; + double WallHeatFlux(const int &ii, const int &jj, const int &kk) const; + double Yplus(const int &ii, const int &jj, const int &kk) const; + double WallTemperature(const int &ii, const int &jj, const int &kk) const; + 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; + 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, + const idealGas &eos) const; + 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 idealGas &eos) const; + int WallVarsSize() const { return data_.Size(); } + void PackWallData(char *(&), const int &, int &, const MPI_Datatype &) const; + void PackSize(int &, const MPI_Datatype &) const; + void UnpackWallData(char *(&), const int &, int &, const MPI_Datatype &, + const input &); + const boundarySurface & Surface() const {return surf_;} + bool IsWallLaw() const {return bcData_->IsWallLaw();} + wallData Split(const string &, const int &, bool &, bool &); + void Join(const wallData &, const string &, bool &); + void Print(ostream &) const; + bool SwitchToLowRe(const int &ii, const int &jj, + const int &kk, const bool &raw = false) const { + return (*this)(ii, jj, kk, raw).SwitchToLowRe(); + } + + // operator overloads + wallVars &operator()(const int &ii, const int &jj, const int &kk, + const bool &raw = false) { + return raw ? data_(ii, jj, kk) + : data_(ii - surf_.IMin(), jj - surf_.JMin(), kk - surf_.KMin()); + } + const wallVars &operator()(const int &ii, const int &jj, const int &kk, + const bool &raw = false) const { + return raw ? data_(ii, jj, kk) + : data_(ii - surf_.IMin(), jj - surf_.JMin(), kk - surf_.KMin()); + } + + // destructor + ~wallData() noexcept {} +}; + +// function definitions +ostream &operator<<(ostream &os, const wallData &wd); +ostream &operator<<(ostream &os, const wallVars &wv); + +#endif diff --git a/include/wallLaw.hpp b/include/wallLaw.hpp new file mode 100644 index 0000000..87df6a2 --- /dev/null +++ b/include/wallLaw.hpp @@ -0,0 +1,128 @@ +/* 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 WALLLAWHEADERDEF +#define WALLLAWHEADERDEF + +/* This defines the classes for the turbulent wall law implementation */ +#include + +#include "vector3d.hpp" +#include "tensor.hpp" +#include "primVars.hpp" + +using std::unique_ptr; + +// forward class declaration +class idealGas; +class sutherland; +class turbModel; +struct wallVars; + +class wallLaw { + const bool isRANS_; + const double vonKarmen_; + const double wallConst_; + const double wallDist_; + const primVars state_; + + double yplus0_; + double beta_; + double gamma_; + double q_; + double phi_; + double yplusWhite_; + double uStar_; + double uplus_; + double tW_; + double rhoW_; + double muW_; + double mutW_; + double kW_; + double recoveryFactor_; + + // private member functions + void UpdateConstants(const double &); + void UpdateGamma(const idealGas &); + void CalcYplusWhite(); + double CalcHeatFlux(const idealGas &) const; + void SetWallVars(const double &, const idealGas &, const sutherland &); + void EddyVisc(const idealGas &, const sutherland &); + void CalcVelocities(const double &, const double &); + void CalcTurbVars(const unique_ptr &, const idealGas &, + const sutherland &, double &, double &); + double CalcYplusRoot(const double &) const; + double ShearStressMag() const {return uStar_ * uStar_ * rhoW_;}; + void CalcRecoveryFactor(const idealGas &); + double CalcWallTemperature(const idealGas &, const double &) const; + + public: + // constructor + wallLaw(const double &k, const double &c, const primVars &s, const double &d, + const bool &isRANS) + : isRANS_(isRANS), + vonKarmen_(k), + wallConst_(c), + wallDist_(d), + state_(s), + yplus0_(std::exp(-k * c)), + beta_(0.0), + gamma_(0.0), + q_(0.0), + phi_(0.0), + yplusWhite_(0.0), + uStar_(0.0), + uplus_(0.0), + tW_(0.0), + rhoW_(0.0), + muW_(0.0), + mutW_(0.0), + kW_(0.0), + recoveryFactor_(0.0) {} + + // move constructor and assignment operator + wallLaw(wallLaw&&) = default; + wallLaw& operator=(wallLaw&&) = default; + + // copy constructor and assignment operator + wallLaw(const wallLaw&) = default; + wallLaw& operator=(const wallLaw&) = default; + + // member functions + double VonKarmen() const { return vonKarmen_; } + double WallConstant() const { return wallConst_; } + wallVars AdiabaticBCs(const vector3d &, const vector3d &, + const idealGas &, const sutherland &, + const unique_ptr &, const bool &); + wallVars HeatFluxBCs(const vector3d &, const vector3d &, + const idealGas &, const sutherland &, + const unique_ptr &, const double &, + const bool &); + wallVars IsothermalBCs(const vector3d &, const vector3d &, + const idealGas &, const sutherland &, + const unique_ptr &, const double &, + const bool &); + + // destructor + ~wallLaw() noexcept {} +}; + + +// function declarations + + + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b99ed17..17bca92 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 5) +set (aither_VERSION_MINOR 6) set (aither_VERSION_PATCH 0) message (STATUS "Cmake version ${CMAKE_VERSION}") @@ -49,6 +49,8 @@ set(sources uncoupledScalar.cpp utility.cpp viscousFlux.cpp + wallData.cpp + wallLaw.cpp ) # create targets for executable and libraries @@ -72,11 +74,32 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() # set additional c++ flags for all build types -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native -O3 -DNDEBUG") -set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native") -set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -O0 -ggdb -pg") +if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} /O2 /DNDEBUG") +else() + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native -O3 -DNDEBUG") +endif() + +# release build type +if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS}") +else() + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMPILER_SPEC_FLAGS} -Wall -pedantic -march=native") +endif() + +# debug build type +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 -set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -pg") +if (${CMAKE_SYSTEM_NAME} MATCHES "WINDOWS") + set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} /PROFILE") +else() + set (CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS} ${COMPILER_SPEC_FLAGS} -pg") +endif() # set compiler flags based on release type if (CMAKE_BUILD_TYPE MATCHES "release") diff --git a/src/boundaryConditions.cpp b/src/boundaryConditions.cpp index a0a8882..9f2730e 100644 --- a/src/boundaryConditions.cpp +++ b/src/boundaryConditions.cpp @@ -23,6 +23,9 @@ #include "boundaryConditions.hpp" #include "vector3d.hpp" // vector3d #include "plot3d.hpp" // plot3dBlock +#include "parallel.hpp" // decomposition +#include "inputStates.hpp" // inputState +#include "input.hpp" // input using std::cout; using std::endl; @@ -40,10 +43,7 @@ boundaryConditions::boundaryConditions(const int &i, const int &j, numSurfJ_ = j; numSurfK_ = k; const auto length = numSurfI_ + numSurfJ_ + numSurfK_; - - boundarySurface bcSurf_; - vector dumVec(length, bcSurf_); - surfs_ = dumVec; + surfs_ = vector(length, boundarySurface()); } // Operator overload for << - allows use of cout, cerr, etc. @@ -81,55 +81,17 @@ void boundaryConditions::ResizeVecs(const int &i, const int &j, const int &k) { surfs_.resize(i + j + k); } -// Member function to return the boundary condition type given the -// i,j,k face coordinates and the surface type -string boundaryConditions::GetBCName(const int &i, const int &j, const int &k, - const int &surf) const { - // ii -- i coordinate - // jj -- j coordinate - // kk -- k coordinate - // surf -- boundary condition surface type [1-6] - - auto iStart = 0; - auto iEnd = 0; - - // i-surfaces search between 0 and number of i-surfaces - if (surf == 1 || surf == 2) { - iStart = 0; - iEnd = this->NumSurfI(); - // j-surfaces search between end of i-surfaces and end of j-surfaces - } else if (surf == 3 || surf == 4) { - iStart = this->NumSurfI(); - iEnd = iStart + this->NumSurfJ(); - // k-surfaces search between end of j-surfaces and end of k-surfaces - } else if (surf == 5 || surf == 6) { - iStart = this->NumSurfI() + this->NumSurfJ(); - iEnd = iStart + this->NumSurfK(); - } else { - cerr << "ERROR: Surface type " << surf << " is not recognized!" << endl; - } - - string bcName = "undefined"; - - // Determine which boundary condition should be applied - for (auto nn = iStart; nn < iEnd; nn++) { - // Determine which boundary given i, j, k coordinates apply to - if ((i >= this->GetIMin(nn) && i <= this->GetIMax(nn) && - j >= this->GetJMin(nn) && j <= this->GetJMax(nn) && - k >= this->GetKMin(nn) && k <= this->GetKMax(nn))) { - bcName = this->GetBCTypes(nn); - break; - } - } - - return bcName; +bool boundarySurface::operator==(const boundarySurface &surf) const { + auto isEqualType = surf.bcType_ == bcType_; + auto isEqualData = std::equal(std::begin(data_), std::end(data_), surf.data_); + return isEqualType && isEqualData; } - -// Member function to return the boundary condition tag given the +// Member function to return the boundary condition type given the // i,j,k face coordinates and the surface type -int boundaryConditions::GetBCTag(const int &i, const int &j, const int &k, - const int &surf) const { +boundarySurface boundaryConditions::GetBCSurface(const int &i, const int &j, + const int &k, + const int &surf) const { // ii -- i coordinate // jj -- j coordinate // kk -- k coordinate @@ -154,7 +116,7 @@ int boundaryConditions::GetBCTag(const int &i, const int &j, const int &k, cerr << "ERROR: Surface type " << surf << " is not recognized!" << endl; } - auto bcTag = -1; + boundarySurface surface; // Determine which boundary condition should be applied for (auto nn = iStart; nn < iEnd; nn++) { @@ -162,14 +124,15 @@ int boundaryConditions::GetBCTag(const int &i, const int &j, const int &k, if ((i >= this->GetIMin(nn) && i <= this->GetIMax(nn) && j >= this->GetJMin(nn) && j <= this->GetJMax(nn) && k >= this->GetKMin(nn) && k <= this->GetKMax(nn))) { - bcTag = this->GetTag(nn); + surface = this->GetSurface(nn); break; } } - return bcTag; + return surface; } + // Member function to fill one "row" of the vectors with data that has been // read in from the input file. This function is called from // input::ReadInput(). It is necessary so that the private data can be @@ -189,11 +152,11 @@ void boundaryConditions::AssignFromInput(const int &surfCounter, /* Member function to determine of what sides of a boundary condition surface border another boundarySurface. This is necessary to complete the ghost cell swap properly. The function alters an array of 4 bools, which return true if - the boundary surface borders an interblock on the side that they represent. + the boundary surface borders an connection on the side that they represent. The order of the 4 bools is as follows [direction 1 start, direction 1 end, direction 2 start, direction 2 end].*/ void boundaryConditions::BordersSurface(const int &ii, - bool (&border)[4]) const { + array &border) const { // ii -- index of surface to test for border matches // border -- array of bools to show if boundarySurface is bordered // by another boundarySurface on any of its 4 sides @@ -201,10 +164,10 @@ void boundaryConditions::BordersSurface(const int &ii, // Get surface to test for borders const auto surf = this->GetSurface(ii); - // Check that given boundarySurface is interblock - if (surf.BCType() != "interblock") { - cerr << "ERROR: Error in boundaryConditions::BordersInterblock(). " - << "Given index does not point to an interblock boundarySurface!" + // Check that given boundarySurface is connection + if (!surf.IsConnection()) { + cerr << "ERROR: Error in boundaryConditions::BordersSurface(). " + << "Given index does not point to an connection boundarySurface!" << endl; cerr << surf << endl; exit(EXIT_FAILURE); @@ -242,10 +205,11 @@ void boundaryConditions::BordersSurface(const int &ii, } // Operator overload for << - allows use of cout, cerr, etc. -ostream &operator<<(ostream &os, const interblock &bc) { +ostream &operator<<(ostream &os, const connection &bc) { // os -- ostream to print to - // bc -- interblock to print + // bc -- connection to print + os << "Is Interblock: " << bc.IsInterblock() << endl; os << "Ranks: " << bc.RankFirst() << ", " << bc.RankSecond() << endl; os << "Blocks: " << bc.BlockFirst() << ", " << bc.BlockSecond() << endl; @@ -289,13 +253,13 @@ ostream &operator<<(ostream &os, const interblock &bc) { return os; } -// Constructor to take in two patches and fill an interblock. +// Constructor to take in two patches and fill a connection. // The orientation is left at the default value 0. -interblock::interblock(const patch &p1, const patch &p2) { +connection::connection(const patch &p1, const patch &p2) { // p1 -- patch 1 // p2 -- patch 2 - // Fill interblock + // Fill connection rank_[0] = p1.Rank(); rank_[1] = p2.Rank(); @@ -333,11 +297,13 @@ interblock::interblock(const patch &p1, const patch &p2) { patchBorder_[7] = p2.Dir2EndInterBorder(); orientation_ = 0; // default value (real values 1-8) + isInterblock_ = (p1.BCType() == "interblock" && p2.BCType() == "interblock") + ? true : false; } -// Function to swap the order of an interblock so the 2nd entry +// Function to swap the order of an connection so the 2nd entry // in the pair will be the first, and vice versa -void interblock::SwapOrder() { +void connection::SwapOrder() { swap(rank_[0], rank_[1]); swap(block_[0], block_[1]); swap(localBlock_[0], localBlock_[1]); @@ -362,103 +328,120 @@ void interblock::SwapOrder() { } } -range interblock::Dir1RangeFirst() const { +range connection::Dir1RangeFirst() const { return {d1Start_[0], d1End_[0]}; } -range interblock::Dir1RangeSecond() const { +range connection::Dir1RangeSecond() const { return {d1Start_[1], d1End_[1]}; } -range interblock::Dir2RangeFirst() const { +range connection::Dir2RangeFirst() const { return {d2Start_[0], d2End_[0]}; } -range interblock::Dir2RangeSecond() const { +range connection::Dir2RangeSecond() const { return {d2Start_[1], d2End_[1]}; } -/* Function to go through the boundary conditions and pair the interblock +/* Function to go through the boundary conditions and pair the connection BCs together and determine their orientation.*/ -vector GetInterblockBCs(const vector &bc, +vector GetConnectionBCs(const vector &bc, const vector &grid, - const decomposition &decomp) { + const decomposition &decomp, + const input &inp) { // bc -- vector of boundaryConditions for all blocks // grid -- vector of plot3Dblocks for entire computational mesh // decomp -- decomposition of grid onto processors + // inp -- input variables - // Isolate only the interblock BCs and their associated data + // Isolate only the connection BCs and their associated data // from all of the BCs - // Outer vector for each interblock BC, inner vector for - // information about interblock - vector isolatedInterblocks; + // Outer vector for each connection BC, inner vector for + // information about connection + vector isolatedConnections; // Block number of bc, rank of block, local position on processor - // (different from rankParPos because it holds block number instead - // of parent block number) vector> numRankPos; - vector surfaceNums; // surface number of interblock + vector surfaceNums; // surface number of connection // loop over all blocks for (auto ii = 0U; ii < bc.size(); ii++) { // Loop over number of surfaces in block for (auto jj = 0; jj < bc[ii].NumSurfaces(); jj++) { - // If boundary condition is interblock, store data - if (bc[ii].GetBCTypes(jj) == "interblock") { + // If boundary condition is connection, store data + if (bc[ii].IsConnection(jj)) { // block number of bc, rank, local position boundarySurface of bc const array temp = {static_cast(ii), decomp.Rank(ii), decomp.LocalPosition(ii)}; numRankPos.push_back(temp); - isolatedInterblocks.push_back(bc[ii].GetSurface(jj)); + isolatedConnections.push_back(bc[ii].GetSurface(jj)); surfaceNums.push_back(jj); } } } // ---------------------------------------------------------------------- - // Intialize vector of interblocks to return - // Size is halved because each interblock pairs with another - vector connections(isolatedInterblocks.size() / 2); + // Intialize vector of connections to return + // Size is halved because each connection pairs with another + vector connections(isolatedConnections.size() / 2); - // Loop over isolated interblocks + // Loop over isolated connections // ii counts by two because after a pair is found, that data is swapped // to ii+1. This allows the next search to avoid the matched pair - for (auto ii = 0U; ii < isolatedInterblocks.size(); ii += 2) { + for (auto ii = 0U; ii < isolatedConnections.size(); ii += 2) { // Loop over possible matches - for (auto jj = ii + 1U; jj < isolatedInterblocks.size(); jj++) { - // Blocks and boundary surfaces between interblocks match - // blocks between interblock BCs match - if (isolatedInterblocks[ii].PartnerBlock() == numRankPos[jj][0] && - isolatedInterblocks[ii].PartnerSurface() == - isolatedInterblocks[jj].SurfaceType()) { + for (auto jj = ii + 1U; jj < isolatedConnections.size(); jj++) { + // Blocks and boundary surfaces between connections match + // blocks between connection BCs match + // or both are periodic + if ((isolatedConnections[ii].PartnerBlock() == numRankPos[jj][0] && + isolatedConnections[ii].PartnerSurface() == + isolatedConnections[jj].SurfaceType()) || + (isolatedConnections[ii].BCType() == "periodic" && + isolatedConnections[jj].BCType() == "periodic")) { // Determine if surface borders any other surfaces - bool border[4] = {false, false, false, false}; + array border = {false, false, false, false}; bc[numRankPos[ii][0]].BordersSurface(surfaceNums[ii], border); // Get current patch - const patch cPatch(isolatedInterblocks[ii], grid[numRankPos[ii][0]], - numRankPos[ii][0], border, numRankPos[ii][1], - numRankPos[ii][2]); + patch cPatch(isolatedConnections[ii], grid[numRankPos[ii][0]], + numRankPos[ii][0], border, numRankPos[ii][1], + numRankPos[ii][2]); + if (cPatch.BCType() == "periodic") { + const auto &bcData = inp.BCData(isolatedConnections[ii].Tag()); + if (bcData->StartTag() == isolatedConnections[ii].Tag()) { + // need to transform data if surface is startTag + cPatch.Transform(bcData); + } + } // Determine if surface borders any other surfaces bc[numRankPos[jj][0]].BordersSurface(surfaceNums[jj], border); // Get new patch (possible match) - const patch nPatch(isolatedInterblocks[jj], grid[numRankPos[jj][0]], - numRankPos[jj][0], border, numRankPos[jj][1], - numRankPos[jj][2]); + patch nPatch(isolatedConnections[jj], grid[numRankPos[jj][0]], + numRankPos[jj][0], border, numRankPos[jj][1], + numRankPos[jj][2]); + if (nPatch.BCType() == "periodic") { + const auto &bcData = inp.BCData(isolatedConnections[jj].Tag()); + if (bcData->StartTag() == isolatedConnections[jj].Tag()) { + // need to transform data if surface is startTag + nPatch.Transform(bcData); + } + } // Test for match - interblock match(cPatch, nPatch); + connection match(cPatch, nPatch); if (match.TestPatchMatch(cPatch, nPatch)) { // match found - connections[ii / 2] = match; // store interblock pair + connections[ii / 2] = match; // store connection pair - // Swap matched interblock BC to top portion of vector so + // Swap matched connection BC to top portion of vector so // it is not searched again - swap(isolatedInterblocks[jj], isolatedInterblocks[ii + 1]); + swap(isolatedConnections[jj], isolatedConnections[ii + 1]); swap(numRankPos[jj], numRankPos[ii + 1]); swap(surfaceNums[jj], surfaceNums[ii + 1]); - break; // exit innermost loop and search for next interblock match + break; // exit innermost loop and search for next connection match } } } @@ -468,7 +451,7 @@ vector GetInterblockBCs(const vector &bc, } /* 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 interblock to contain the + match it uses the patches to modify the given connection to contain the information on this match. Each patch is on a constant i, j, or k surface and is a 4 sided rectangle. @@ -476,7 +459,7 @@ vector GetInterblockBCs(const vector &bc, up with the vertexes on the other patch. Only 3 vertexes need to match, so only 3 are tested for. If there is a match the patches can be oriented in 8 different ways with respect to each other. The orientation is stored in the - interblock that is modified. + connection that is modified. Patch 1 Patch 2 Description __________________ __________________ @@ -544,26 +527,31 @@ D1 is j, and D2 is k. On a constant j-patch, D1 is k, and D2 is i, etc. O is the origin which is always at the minimim of D1 and D2 on the patch. C1 is the corner where D1 is at a max, and D2 is zero. C2 is the corner where D2 is at a max, and D1 is zero. C12 is the corner where both D1 and D2 are at a max.*/ -bool interblock::TestPatchMatch(const patch &p1, const patch &p2) { +bool connection::TestPatchMatch(const patch &p1, const patch &p2) { // p1 -- first patch // p2 -- second patch auto match = false; // initialize match to false + // test if bc types are the same + if (p1.BCType() != p2.BCType()) { + return match; + } + // Determine if there is a potential match by comparing origins - if (p1.Origin() == p2.Origin()) { // origins match ----------------------- - // If origin_ matches origin_, corner 1 can only be at corner 1 or 2 - if (p1.Corner1() == p2.Corner1()) { // corner 1s match + if (p1.Origin().CompareWithTol(p2.Origin())) { // origins match ------------ + // If origin matches origin, corner 1 can only be at corner 1 or 2 + if (p1.Corner1().CompareWithTol(p2.Corner1())) { // corner 1s match // If all 3 corners match, same orientation - if (p1.Corner2() == p2.Corner2()) { // corner 2s match + if (p1.Corner2().CompareWithTol(p2.Corner2())) { // corner 2s match orientation_ = 1; match = true; } else { // no match return match; } - } else if (p1.Corner1() == p2.Corner2()) { // corner 1 matches corner 2 + } else if (p1.Corner1().CompareWithTol(p2.Corner2())) { // match 1/2 // If origins match and 1 matches 2, 2 must match 1 - if (p1.Corner2() == p2.Corner1()) { // corner 2 matches corner 1 + if (p1.Corner2().CompareWithTol(p2.Corner1())) { // corner 2 matches corner 1 orientation_ = 2; match = true; } else { // no match @@ -572,19 +560,19 @@ bool interblock::TestPatchMatch(const patch &p1, const patch &p2) { } else { // no match return match; } - } else if (p1.Origin() == p2.Corner1()) { // origin_ matches corner 1 ------- - // If origin_ matches corner1_, corner 1 can only be at corner 12 or origin_ - if (p1.Corner1() == p2.Origin()) { + } else if (p1.Origin().CompareWithTol(p2.Corner1())) { // origin match corner 1 + // If origin matches corner1, corner 1 can only be at corner 12 or origin + if (p1.Corner1().CompareWithTol(p2.Origin())) { // Corner 2 must match 12 for match - if (p1.Corner2() == p2.Corner12()) { + if (p1.Corner2().CompareWithTol(p2.Corner12())) { orientation_ = 3; match = true; } else { // no match return match; } - } else if (p1.Corner1() == p2.Corner12()) { - // Corner 2 must match origin_ for match - if (p1.Corner2() == p2.Origin()) { + } else if (p1.Corner1().CompareWithTol(p2.Corner12())) { + // Corner 2 must match origin for match + if (p1.Corner2().CompareWithTol(p2.Origin())) { orientation_ = 4; match = true; } else { // no match @@ -593,19 +581,19 @@ bool interblock::TestPatchMatch(const patch &p1, const patch &p2) { } else { // no match return match; } - } else if (p1.Origin() == p2.Corner2()) { // origin_ matches corner 2 ------ - // If origin_ matches corner2_, corner 1 can only be at corner 12 or origin_ - if (p1.Corner1() == p2.Origin()) { + } else if (p1.Origin().CompareWithTol(p2.Corner2())) { // origin match corner 2 + // If origin matches corner2, corner 1 can only be at corner 12 or origin + if (p1.Corner1().CompareWithTol(p2.Origin())) { // Corner 2 must match 12 for match - if (p1.Corner2() == p2.Corner12()) { + if (p1.Corner2().CompareWithTol(p2.Corner12())) { orientation_ = 5; match = true; } else { // no match return match; } - } else if (p1.Corner1() == p2.Corner12()) { + } else if (p1.Corner1().CompareWithTol(p2.Corner12())) { // Corner 2 must match origin_ for match - if (p1.Corner2() == p2.Origin()) { + if (p1.Corner2().CompareWithTol(p2.Origin())) { orientation_ = 6; match = true; } else { // no match @@ -614,19 +602,19 @@ bool interblock::TestPatchMatch(const patch &p1, const patch &p2) { } else { // no match return match; } - } else if (p1.Origin() == p2.Corner12()) { // origin_ matches opposite corner - // If origin matches corner12, corner 1 can only be at corner 1 or corner 2 - if (p1.Corner1() == p2.Corner1()) { + } else if (p1.Origin().CompareWithTol(p2.Corner12())) { // origin match 12 + // If origin matches corner 12, corner 1 can only be at corner 1 or corner 2 + if (p1.Corner1().CompareWithTol(p2.Corner1())) { // Corner 2 must match 2 for match - if (p1.Corner2() == p2.Corner2()) { + if (p1.Corner2().CompareWithTol(p2.Corner2())) { orientation_ = 7; match = true; } else { // no match return match; } - } else if (p1.Corner1() == p2.Corner2()) { + } else if (p1.Corner1().CompareWithTol(p2.Corner2())) { // Corner 2 must match corner 1 for match - if (p1.Corner2() == p2.Corner2()) { + if (p1.Corner2().CompareWithTol(p2.Corner2())) { orientation_ = 8; match = true; } else { // no match @@ -642,8 +630,8 @@ bool interblock::TestPatchMatch(const patch &p1, const patch &p2) { return match; } -/* Member function to adjust the interblock for use with a geomSlice */ -void interblock::AdjustForSlice(const bool &blkFirst, const int &numG) { +/* Member function to adjust the connection for use with a geomSlice */ +void connection::AdjustForSlice(const bool &blkFirst, const int &numG) { // blkFirst -- boolean that is true if block to insert into is first // numG -- number of ghost cells in block @@ -670,9 +658,9 @@ void interblock::AdjustForSlice(const bool &blkFirst, const int &numG) { d2Start_[0] = this->Dir2StartFirst() - numG; } -// Member function to get the addresses of an interblock to create +// Member function to get the addresses of an connection to create // an MPI_Datatype -void interblock::GetAddressesMPI(MPI_Aint (&disp)[11]) const { +void connection::GetAddressesMPI(MPI_Aint (&disp)[12]) const { // Get addresses of each field MPI_Get_address(&rank_[0], &disp[0]); MPI_Get_address(&block_[0], &disp[1]); @@ -685,11 +673,12 @@ void interblock::GetAddressesMPI(MPI_Aint (&disp)[11]) const { MPI_Get_address(&constSurf_[0], &disp[8]); MPI_Get_address(&patchBorder_[0], &disp[9]); MPI_Get_address(&orientation_, &disp[10]); + MPI_Get_address(&isInterblock_, &disp[11]); } // Function to return which direction (i,j,k) is direction 1 in the -// first partner in the interblock -string interblock::Direction1First() const { +// first partner in the connection +string connection::Direction1First() const { string dir = ""; if (this->BoundaryFirst() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "j"; @@ -703,8 +692,8 @@ string interblock::Direction1First() const { } // Function to return which direction (i,j,k) is direction 1 in the second -// partner in the interblock -string interblock::Direction1Second() const { +// partner in the connection +string connection::Direction1Second() const { string dir = ""; if (this->BoundarySecond() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "j"; @@ -718,8 +707,8 @@ string interblock::Direction1Second() const { } // Function to return which direction (i,j,k) is direction 2 in the first -// partner in the interblock -string interblock::Direction2First() const { +// partner in the connection +string connection::Direction2First() const { string dir = ""; if (this->BoundaryFirst() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "k"; @@ -733,8 +722,8 @@ string interblock::Direction2First() const { } // Function to return which direction (i,j,k) is direction 2 in the second -// partner in the interblock -string interblock::Direction2Second() const { +// partner in the connection +string connection::Direction2Second() const { string dir = ""; if (this->BoundarySecond() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "k"; @@ -748,8 +737,8 @@ string interblock::Direction2Second() const { } // function to return which direction (i,j,k) is direction 3 in the first -// partner in the interblock -string interblock::Direction3First() const { +// partner in the connection +string connection::Direction3First() const { string dir = ""; if (this->BoundaryFirst() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "i"; @@ -763,8 +752,8 @@ string interblock::Direction3First() const { } // Function to return which direction (i,j,k) is direction 3 in the second -// partner in the interblock -string interblock::Direction3Second() const { +// partner in the connection +string connection::Direction3Second() const { string dir = ""; if (this->BoundarySecond() <= 2) { // dir 3 is i, dir 1 is j, dir 2 is k dir = "i"; @@ -777,46 +766,46 @@ string interblock::Direction3Second() const { return dir; } -/* Member function to update the interblock border matching portion of the first - partner in an interblock. An index between 1-4 representing the 4 sides of +/* Member function to update the connection border matching portion of the first + partner in an connection. An index between 1-4 representing the 4 sides of the - interblock surface are passed to the function, and it ensures that the - interblockBorder variable at that position reads true. This is used during + connection surface are passed to the function, and it ensures that the + connectionBorder variable at that position reads true. This is used during the first PutGeomSlice ghost cell exchange to locate a "t" intersection of blocks and ensure that they are treated properly. */ -void interblock::UpdateBorderFirst(const int &a) { +void connection::UpdateBorderFirst(const int &a) { // a -- position in patchBorder_ to update (0-3) - // (dir 1 start, dir1 end, dir2 start, dir2 end) if (a >= 0 && a <= 3) { patchBorder_[a] = true; } else { - cerr << "ERROR: Error in interblock::UpdateBorderFirst(). " + cerr << "ERROR: Error in connection::UpdateBorderFirst(). " << "Position to update is out of range. Choose between 0-3. " << "Position input was " << a << endl; exit(EXIT_FAILURE); } } -/* Member function to update the interblock border matching portion of the +/* Member function to update the connection border matching portion of the second - partner in an interblock. An index between 1-4 representing the 4 sides of + partner in an connection. An index between 1-4 representing the 4 sides of the - interblock surface are passed to the function, and it ensures that the - interblockBorder variable at that position reads true. This is used during + connection surface are passed to the function, and it ensures that the + connectionBorder variable at that position reads true. This is used during the first PutGeomSlice ghost cell exchange to locate a "t" intersection of blocks and ensure that they are treated properly. */ -void interblock::UpdateBorderSecond(const int &a) { +void connection::UpdateBorderSecond(const int &a) { // a -- position in patchBorder_ to update (0-3) - // (dir 1 start, dir1 end, dir2 start, dir2 end) if (a >= 0 && a <= 3) { patchBorder_[a + 4] = true; } else { - cerr << "ERROR: Error in interblock::UpdateBorderSecond(). " + cerr << "ERROR: Error in connection::UpdateBorderSecond(). " << "Position to update is out of range. Choose between 0-3. " << "Position input was " << a << endl; exit(EXIT_FAILURE); @@ -824,8 +813,8 @@ void interblock::UpdateBorderSecond(const int &a) { } // member function to get the indices of a slice for purposes of swapping -// for the first block in an interblock -void interblock::FirstSliceIndices(int &is1, int &ie1, int &js1, int &je1, +// for the first block in an connection +void connection::FirstSliceIndices(int &is1, int &ie1, int &js1, int &je1, int &ks1, int &ke1, const int &numGhosts1) const { // is1 -- starting i index for first slice @@ -885,15 +874,16 @@ void interblock::FirstSliceIndices(int &is1, int &ie1, int &js1, int &je1, je1 = this->Dir2EndFirst() + numGhosts1; } else { - cerr << "ERROR: Error in interblock::FirstSliceIndices(). Surface boundary " + cerr << "ERROR: Error in connection::FirstSliceIndices(). Surface boundary " << this->BoundaryFirst() << " is not recognized!" << endl; + cerr << "connection is: " << (*this) << endl; exit(EXIT_FAILURE); } } // member function to get the indices of a slice for purposes of swapping -// for the first block in an interblock -void interblock::SecondSliceIndices(int &is2, int &ie2, int &js2, int &je2, +// for the first block in an connection +void connection::SecondSliceIndices(int &is2, int &ie2, int &js2, int &je2, int &ks2, int &ke2, const int &numGhosts2) const { // is2 -- starting i index for second slice @@ -953,7 +943,7 @@ void interblock::SecondSliceIndices(int &is2, int &ie2, int &js2, int &je2, je2 = this->Dir2EndSecond() + numGhosts2; } else { - cerr << "ERROR: Error in interblock::SecondSliceIndices(). " << + cerr << "ERROR: Error in connection::SecondSliceIndices(). " << "Surface boundary " << this->BoundarySecond() << " is not recognized!" << endl; exit(EXIT_FAILURE); @@ -963,14 +953,25 @@ void interblock::SecondSliceIndices(int &is2, int &ie2, int &js2, int &je2, // member function to determine the number of faces with a viscous wall BC int boundaryConditions::NumViscousFaces() const { auto nFaces = 0; - for (auto ii = 0; ii < this->NumSurfaces(); ii++) { - if (this->GetBCTypes(ii) == "viscousWall") { - nFaces += surfs_[ii].NumFaces(); + for (auto &surf : surfs_) { + if (surf.BCType() == "viscousWall") { + nFaces += surf.NumFaces(); } } return nFaces; } +// member function to determine the number of viscousWall boundarySurfaces +int boundaryConditions::NumViscousSurfaces() const { + auto nSurfs = 0; + for (auto &surf : surfs_) { + if (surf.BCType() == "viscousWall") { + nSurfs++; + } + } + return nSurfs; +} + int boundaryConditions::BlockDimI() const { auto dim = 0; for (auto ii = 0; ii < this->NumSurfaces(); ii++) { @@ -995,7 +996,8 @@ int boundaryConditions::BlockDimK() const { return dim; } -/* Member function to split boundary_ conditions along a given direction at a + +/* 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, @@ -1005,632 +1007,378 @@ boundaryConditions boundaryConditions::Split(const string &dir, const int &ind, // 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) - // numBlk -- block_ number that (*this) is assocatied with - // newBlkNum -- block_ number for upper split + // numBlk -- block number that (*this) is associated with + // newBlkNum -- block number for upper split // aSurf -- vector of any interblocks that are split, - // because their partners will need to be altered for the split as - // well - - const auto indNG = ind; - - auto bound1 = (*this); // lower boundaryConditions - auto bound2 = (*this); // upper boundaryConditions - - // Initialize vector of surfaces that will be altered by this split - vector alteredSurf; - - // If a surface in entirely on one side of the split, it should be removed - // from the other side - these variables keep track of the surfaces to remove - vector del1, del2; - // Reserved for maximum number of deletions - del1.reserve(this->NumSurfaces()); - // Reserved for maximum number of deletions - del2.reserve(this->NumSurfaces()); - - if (dir == "i") { // split along i-plane - // Initialize deletion numbers to 0 - auto del1I = 0; - auto del1J = 0; - auto del1K = 0; - auto del2I = 0; - auto del2J = 0; - auto del2K = 0; - - auto numInterL = 0; - auto numInterU = 0; - - // Loop over all surfaces - for (auto ii = 0; ii < this->NumSurfaces(); ii++) { - if (ii < this->NumSurfI()) { // i-surface - if (this->GetSurface(ii).SurfaceType() == 1) { // lower i surface - // No change to lower bc at lower i surface - - // At lower i surface, upper bc is now interface - // lower surface matches with upper surface - const auto tag = 2000 + numBlk; - bound2.surfs_[ii].bcType_ = "interblock"; // bcType - bound2.surfs_[ii].data_[0] = this->GetIMin(ii); // imin - bound2.surfs_[ii].data_[1] = this->GetIMax(ii); // imax - bound2.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound2.surfs_[ii].data_[2] = 0; // jmin - bound2.surfs_[ii].data_[3] = this->BlockDimJ(); // jmax - bound2.surfs_[ii].data_[4] = 0; // kmin - bound2.surfs_[ii].data_[5] = this->BlockDimK(); // kmax - - if (numInterL > 0) { - del2.push_back(ii); - del2I++; - } - numInterL++; - } else { // upper surface - // At upper i surface, lower bc is now interface - // upper surface matches with lower surface - const auto tag = 1000 + newBlkNum; - bound1.surfs_[ii].bcType_ = "interblock"; // bcType - bound1.surfs_[ii].data_[0] = indNG; // imin - bound1.surfs_[ii].data_[1] = indNG; // imax - bound1.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound1.surfs_[ii].data_[2] = 0; // jmin - bound1.surfs_[ii].data_[3] = this->BlockDimJ(); // jmax - bound1.surfs_[ii].data_[4] = 0; // kmin - bound1.surfs_[ii].data_[5] = this->BlockDimK(); // kmax - - if (numInterU > 0) { - del1.push_back(ii); - del1I++; - } - - numInterU++; - - // At upper i surface, upper bc is same as original, - // but indices are adjusted for new block_ size - bound2.surfs_[ii].data_[0] = this->GetIMax(ii) - indNG; // imin - bound2.surfs_[ii].data_[1] = this->GetIMax(ii) - indNG; // imax + // because their partners will need to be altered for the split too - // At upper i surface, if bc is interblock, store boundarySurface - // because partner block_ BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } - } - } else { // j-surface or k-surface - // At j/k surface, if bc is interblock, store boundarySurface - // because partner block BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } + if (!(dir == "i" || dir == "j" || dir == "k")) { + cerr << "ERROR: Error in boundaryConditions::Split(). Direction " << dir + << " is not recognized. Choose i, j, or k" << endl; + } - // This surface is only present in the upper split - if (this->GetIMin(ii) >= indNG) { - bound2.surfs_[ii].data_[0] = this->GetIMin(ii) - indNG; // imin - bound2.surfs_[ii].data_[1] = this->GetIMax(ii) - indNG; // imax - // Can delete it from lower split - del1.push_back(ii); - if (ii >= this->NumSurfI() && - ii < this->NumSurfI() + this->NumSurfJ()) { // j-surface - del1J++; - } else { // k-surface - del1K++; - } - } else if (this->GetIMax(ii) > indNG) { // surf straddles the split - bound1.surfs_[ii].data_[1] = indNG; // imax - bound2.surfs_[ii].data_[0] = 0; // imin - bound2.surfs_[ii].data_[1] = this->GetIMax(ii) - indNG; // imax - } else { // surf only present in the lower split - delete from upper - del2.push_back(ii); - if (ii >= this->NumSurfI() && - ii < this->NumSurfI() + this->NumSurfJ()) { // j-surface - del2J++; - } else { // k-surface - del2K++; - } - } - } - } + boundaryConditions lower(0, 0, 0); + boundaryConditions upper(0, 0, 0); - // Delete unnecessary boundaries and change number of surfaces in i,j,k - // to appropriate number + aSurf = vector(0); - // need to delete from bottom of vector so indices are preserved - // need to cast to int because value must be negative for termination - for (auto ii = static_cast(del1.size()) - 1; ii >= 0; --ii) { - bound1.surfs_.erase(bound1.surfs_.begin() + del1[ii]); - } - bound1.numSurfI_ -= del1I; - bound1.numSurfJ_ -= del1J; - bound1.numSurfK_ -= del1K; + auto insertedSplit = false; + for (auto &lowSurf : surfs_) { + auto surfDir = lowSurf.Direction3(); - for (auto ii = static_cast(del2.size()) - 1; ii >= 0; --ii) { - bound2.surfs_.erase(bound2.surfs_.begin() + del2[ii]); + if (lowSurf.IsConnection() && !(dir == "i" && lowSurf.SurfaceType() == 1) && + !(dir == "j" && lowSurf.SurfaceType() == 3) && + !(dir == "k" && lowSurf.SurfaceType() == 5)) { + aSurf.push_back(lowSurf); } - bound2.numSurfI_ -= del2I; - bound2.numSurfJ_ -= del2J; - bound2.numSurfK_ -= del2K; - - } else if (dir == "j") { // split along j-plane - // Initialize deletion numbers to 0 - auto del1I = 0; - auto del1J = 0; - auto del1K = 0; - auto del2I = 0; - auto del2J = 0; - auto del2K = 0; - - auto numInterL = 0; - auto numInterU = 0; - - // Loop over all surfaces - for (auto ii = 0; ii < this->NumSurfaces(); ii++) { - if (ii >= this->NumSurfI() && - ii < this->NumSurfI() + this->NumSurfJ()) { // j-surface - if (this->GetSurface(ii).SurfaceType() == 3) { // lower j surface - // No change to lower bc at lower j surface - - // At lower j surface, upper bc is now interface - // lower surface matches with upper surface - const auto tag = 4000 + numBlk; - bound2.surfs_[ii].bcType_ = "interblock"; // bctype - bound2.surfs_[ii].data_[2] = this->GetJMin(ii); // jmin - bound2.surfs_[ii].data_[3] = this->GetJMax(ii); // jmax - bound2.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound2.surfs_[ii].data_[0] = 0; // imin - bound2.surfs_[ii].data_[1] = this->BlockDimI(); // imax - bound2.surfs_[ii].data_[4] = 0; // kmin - bound2.surfs_[ii].data_[5] = this->BlockDimK(); // kmax - - if (numInterL > 0) { - del2.push_back(ii); - del2J++; - } - numInterL++; - } else { - // At upper j surface, lower bc is now interface - // upper surface matches with lower - const auto tag = 3000 + newBlkNum; - bound1.surfs_[ii].bcType_ = "interblock"; // bctype - bound1.surfs_[ii].data_[2] = indNG; // jmin - bound1.surfs_[ii].data_[3] = indNG; // jmax - bound1.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound1.surfs_[ii].data_[0] = 0; // imin - bound1.surfs_[ii].data_[1] = this->BlockDimI(); // imax - bound1.surfs_[ii].data_[4] = 0; // kmin - bound1.surfs_[ii].data_[5] = this->BlockDimK(); // kmax - - if (numInterU > 0) { - del1.push_back(ii); - del1J++; - } - numInterU++; - // At upper j surface, upper bc is same as original, but indices - // are adjusted for new block size - bound2.surfs_[ii].data_[2] = this->GetJMax(ii) - indNG; // jmin - bound2.surfs_[ii].data_[3] = this->GetJMax(ii) - indNG; // jmax - - // At upper j surface, if bc is interblock, store boundarySurface - // because partner block_ BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } - } - } else { // i-surface or k-surface - // At i/k surface, if bc is interblock, store boundarySurface - // because partner block BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } - - if (this->GetJMin(ii) >= indNG) { // surf is only in the upper split - bound2.surfs_[ii].data_[2] = this->GetJMin(ii) - indNG; // jmin - bound2.surfs_[ii].data_[3] = this->GetJMax(ii) - indNG; // jmax - // can delete from lower split - del1.push_back(ii); - if (ii < this->NumSurfI()) { // i-surface - del1I++; - } else { // k-surface - del1K++; - } - } else if (this->GetJMax(ii) > indNG) { // surf straddles the split - bound1.surfs_[ii].data_[3] = indNG; // jmax - bound2.surfs_[ii].data_[2] = 0; // jmin - bound2.surfs_[ii].data_[3] = this->GetJMax(ii) - indNG; // jmax - } else { // surface is only in the lower split - can delete from upper - del2.push_back(ii); - if (ii < this->NumSurfI()) { // i-surface - del2I++; - } else { // k-surface - del2K++; - } - } + // this block is only executed once, to insert the interface surface for the + // lower and upper splits + if (!insertedSplit && dir == surfDir) { //--------------------------------- + if (dir == "i") { + // For upper block, at lower i surface, bc is now interblock + // lower surface matches with upper surface + const auto upTag = 2000 + numBlk; + boundarySurface upSurf("interblock", 0, 0, 0, this->BlockDimJ(), 0, + this->BlockDimK(), upTag); + + // For lower block, at upper i surface, bc is now interblock + // upper surface matches with lower surface + const auto lowTag = 1000 + newBlkNum; + // There should only be one surface between the split blocks + boundarySurface lowerSurf("interblock", ind, ind, 0, this->BlockDimJ(), + 0, this->BlockDimK(), lowTag); + + lower.surfs_.push_back(lowerSurf); + lower.numSurfI_++; + upper.surfs_.push_back(upSurf); + upper.numSurfI_++; + } else if (dir == "j") { + // For upper block, at lower j surface, bc is now interblock + // lower surface matches with upper surface + const auto upTag = 4000 + numBlk; + boundarySurface upSurf("interblock", 0, this->BlockDimI(), 0, 0, 0, + this->BlockDimK(), upTag); + + // For lower block, at upper j surface, bc is now interblock + // upper surface matches with lower surface + const auto lowTag = 3000 + newBlkNum; + // There should only be one surface between the split blocks + boundarySurface lowerSurf("interblock", 0, this->BlockDimI(), ind, ind, + 0, this->BlockDimK(), lowTag); + + lower.surfs_.push_back(lowerSurf); + lower.numSurfJ_++; + upper.surfs_.push_back(upSurf); + upper.numSurfJ_++; + } else { + // For upper block, at lower k surface, bc is now interblock + // lower surface matches with upper surface + const auto upTag = 6000 + numBlk; + boundarySurface upSurf("interblock", 0, this->BlockDimI(), 0, + this->BlockDimJ(), 0, 0, upTag); + + // For lower block, at upper k surface, bc is now interblock + // upper surface matches with lower surface + const auto lowTag = 5000 + newBlkNum; + // There should only be one surface between the split blocks + boundarySurface lowerSurf("interblock", 0, this->BlockDimI(), 0, + this->BlockDimJ(), ind, ind, lowTag); + + lower.surfs_.push_back(lowerSurf); + lower.numSurfK_++; + upper.surfs_.push_back(upSurf); + upper.numSurfK_++; } - } - - // Delete unnecessary boundaries - and set number of surfaces (i, j, k) - // to appropriate number - - // need to delete from bottom of vector so indices are preserved - // need to cast to int because value must be negative for termination - for (auto ii = static_cast(del1.size()) - 1; ii >= 0; --ii) { - bound1.surfs_.erase(bound1.surfs_.begin() + del1[ii]); - } - bound1.numSurfI_ -= del1I; - bound1.numSurfJ_ -= del1J; - bound1.numSurfK_ -= del1K; - - for (auto ii = static_cast(del2.size()) - 1; ii >= 0; --ii) { - bound2.surfs_.erase(bound2.surfs_.begin() + del2[ii]); - } - bound2.numSurfI_ -= del2I; - bound2.numSurfJ_ -= del2J; - bound2.numSurfK_ -= del2K; - - } else if (dir == "k") { // split along k-plane - // Initialize deletion numbers to 0 - auto del1I = 0; - auto del1J = 0; - auto del1K = 0; - auto del2I = 0; - auto del2J = 0; - auto del2K = 0; - - auto numInterL = 0; - auto numInterU = 0; - - // Loop over all surfaces - for (auto ii = 0; ii < this->NumSurfaces(); ii++) { - if (ii >= this->NumSurfI() + this->NumSurfJ()) { // k-surface - if (this->GetSurface(ii).SurfaceType() == 5) { // lower k surface - // No change to lower bc at lower k surface - - // At lower k surface, upper bc is now interface - // lower surface matches with upper - const auto tag = 6000 + numBlk; - bound2.surfs_[ii].bcType_ = "interblock"; // bctype - bound2.surfs_[ii].data_[4] = this->GetKMin(ii); // kmin - bound2.surfs_[ii].data_[5] = this->GetKMax(ii); // kmax - bound2.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound2.surfs_[ii].data_[0] = 0; // imin - bound2.surfs_[ii].data_[1] = this->BlockDimI(); // imax - bound2.surfs_[ii].data_[2] = 0; // jmin - bound2.surfs_[ii].data_[3] = this->BlockDimJ(); // jmax - - if (numInterL > 0) { - del2.push_back(ii); - del2K++; - } - numInterL++; - } else { - // At upper k surface, lower bc is now interface - // upper surface matches with lower - const auto tag = 5000 + newBlkNum; - bound1.surfs_[ii].bcType_ = "interblock"; // bctype - bound1.surfs_[ii].data_[4] = indNG; // kmin - bound1.surfs_[ii].data_[5] = indNG; // kmax - bound1.surfs_[ii].data_[6] = tag; // tag - - // There should only be one surface between the split blocks - bound1.surfs_[ii].data_[0] = 0; // imin - bound1.surfs_[ii].data_[1] = this->BlockDimI(); // imax - bound1.surfs_[ii].data_[2] = 0; // jmin - bound1.surfs_[ii].data_[3] = this->BlockDimJ(); // jmax - - if (numInterU > 0) { - del1.push_back(ii); - del1K++; - } - numInterU++; - - // At upper k surface, upper bc is same as original, - // but indices are adjusted for new block_ size - bound2.surfs_[ii].data_[4] = this->GetKMax(ii) - indNG; // kmin - bound2.surfs_[ii].data_[5] = this->GetKMax(ii) - indNG; // kmax - - // At upper k surface, if bc is interblock, store boundarySurface - // because partner block_ BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } - } - } else { // i-surface or j-surface - // At i/j surface, if bc is interblock, store boundarySurface because - // partner block_ BC will need to be updated - if (this->GetBCTypes(ii) == "interblock") { - alteredSurf.push_back(this->GetSurface(ii)); - } - - if (this->GetKMin(ii) >= indNG) { // surface is only in upper split - bound2.surfs_[ii].data_[4] = this->GetKMin(ii) - indNG; // kmin - bound2.surfs_[ii].data_[5] = this->GetKMax(ii) - indNG; // kmax - // Can delete from lower surface - del1.push_back(ii); - if (ii < this->NumSurfI()) { // i-surface - del1I++; - } else { // j-surface - del1J++; - } - } else if (this->GetKMax(ii) > indNG) { // surf straddles the split - bound1.surfs_[ii].data_[5] = indNG; // kmax - bound2.surfs_[ii].data_[4] = 0; // kmin - bound2.surfs_[ii].data_[5] = this->GetKMax(ii) - indNG; // kmax - } else { // surface is only in the lower split - can delete from upper - del2.push_back(ii); - if (ii < this->NumSurfI()) { // i-surface - del2I++; - } else { // j-surface - del2J++; - } - } + insertedSplit = true; + } //----------------------------------------------------------------------- + + 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_++; + } + } 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_++; } } - - // Delete unnecessary boundaries and set surface numbers (i,j,k) to - // appropriate value - - // need to delete from bottom of vector so indices are preserved - // need to cast to int because value must be negative for termination - for (auto ii = static_cast(del1.size()) - 1; ii >= 0; --ii) { - bound1.surfs_.erase(bound1.surfs_.begin() + del1[ii]); - } - bound1.numSurfI_ -= del1I; - bound1.numSurfJ_ -= del1J; - bound1.numSurfK_ -= del1K; - - for (auto ii = static_cast(del2.size()) - 1; ii >= 0; --ii) { - bound2.surfs_.erase(bound2.surfs_.begin() + del2[ii]); - } - bound2.numSurfI_ -= del2I; - bound2.numSurfJ_ -= del2J; - bound2.numSurfK_ -= del2K; - - } else { - cerr << "ERROR: Error in boundaryCondition::Split(). Direction " << dir - << " is not recognized! Choose either i, j, or k." << endl; - exit(EXIT_FAILURE); } - (*this) = bound1; // assign lower split to (*this) - aSurf = alteredSurf; // assign vector of altered surfaces - return bound2; + (*this) = lower; + return upper; } /* Member function to split the surfaces of a boundaryCondtions accordingly when - one of its interblock partners has been altered. The interblock partner may - have been split, its block_ number updated, or both. In order to correctly - match up the dependents of the interblock must be updated for the split.*/ + 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_ + // surf -- boundarySurface of partner block // part -- plot3dBlock that surf is assigned to // self -- plot3dBlock that (*this) is assigned to - // sblk -- block_ number of self + // 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 + // lblk -- lower block number in partner split + // ublk -- upper block number in partner split - // dummy value used because interblock is only used to test for match - bool border[4] = {false, false, false, false}; + // 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 - const patch candidate(this->GetSurface(ii), self, sblk, border); + auto lowSurf = this->GetSurface(ii); + const patch candidate(lowSurf, self, sblk, border); - interblock match(candidate, partner); + connection match(candidate, partner); if (match.TestPatchMatch(candidate, partner)) { // match found - auto lowSurf = this->GetSurface(ii); // get match surface - // 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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "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 + 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 + } 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 + } 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; + "Direction " + << dir << " is not recognized." << endl; cerr << "Please choose i, j, or k." << endl; exit(EXIT_FAILURE); } } // split matched surface - auto split = false; // flag to tell if surface was split (or just if - // block_ number updated) - const auto upSurf = lowSurf.Split(candDir, candInd, lblk, ublk, split, - match.Orientation()); - - // assign boundarySurface back into boundaryConditions, if surface wasn't - // split partner block was updated - surfs_[ii] = lowSurf; - - // 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 - // boundary_ conditions + auto split = false, low = false; + const auto upSurf = lowSurf.DependentSplit( + candDir, candInd, sblk, lblk, ublk, split, low, match.Orientation()); + + // assign boundarySurface back into boundaryConditions, if surface + // wasn't split partner block was updated + if (!split && !low) { + surfs_[ii] = upSurf; + } else { + surfs_[ii] = lowSurf; + } + + // 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_++; @@ -1647,22 +1395,22 @@ void boundaryConditions::DependentSplit(const boundarySurface &surf, } /* Member function to join 2 boundaryConditions. It assumes that the calling -instance is the "lower" boundary_ condition and the input instance -is the "upper" boundary_ condition. +instance is the "lower" boundary condition and the input instance +is the "upper" boundary condition. */ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, vector &aSurf) { // bc -- boundary_ condition (upper) to join // dir -- direction of join plane - // aSurf -- vector of interblocks whose partners will need to be altered by + // aSurf -- vector of connections whose partners will need to be altered by // the join - vector alteredSurf; // initialize vector of boundary_ + vector alteredSurf; // initialize vector of boundary // surfaces whose partners will need to // be altered by the join if (dir == "i") { // split along i-plane - // total number of i surfaces in joined block_ will be equal to the lower i + // total number of i surfaces in joined block will be equal to the lower i // surfaces from lower bc plus the upper i surfaces from the upper bc auto numI = 0; for (auto ii = 0; ii < this->NumSurfI(); ii++) { @@ -1676,7 +1424,7 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, } } - // total number of j surfaces in joined block_ will be equal to all j + // total number of j surfaces in joined block will be equal to all j // surfaces from lower bc plus the j surfaces from the upper bc that only // reside in the upper bc const auto numJ = this->NumSurfJ() + bc.NumSurfJ(); @@ -1703,9 +1451,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, // insert all i upper surfaces from upper bc for (auto ii = 0; ii < bc.NumSurfI(); ii++) { if (bc.GetSurface(ii).SurfaceType() == 2) { // upper i surface - // at upper i surface, if bc is interblock, store boundarySurface + // at upper i surface, if bc is connection, store boundarySurface // because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1730,9 +1478,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = bc.NumSurfI(); ii < bc.NumSurfI() + bc.NumSurfJ(); ii++) { - // at j surface for upper block, if bc is interblock, store + // at j surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1756,9 +1504,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = bc.NumSurfI() + bc.NumSurfJ(); ii < bc.NumSurfaces(); ii++) { - // at k surface for upper block, if bc is interblock, store + // at k surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1820,9 +1568,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, // insert all j upper surfaces from upper bc for (auto ii = bc.NumSurfI(); ii < bc.NumSurfI() + bc.NumSurfJ(); ii++) { if (bc.GetSurface(ii).SurfaceType() == 4) { // upper j surface - // at j upper surface for upper block, if bc is interblock, store + // at j upper surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1846,9 +1594,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = 0; ii < bc.NumSurfI(); ii++) { - // at i surface for upper block, if bc is interblock, store + // at i surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1871,9 +1619,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = bc.NumSurfI() + bc.NumSurfJ(); ii < bc.NumSurfaces(); ii++) { - // at k surface for upper block, if bc is interblock, store + // at k surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1935,9 +1683,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, // insert all k upper surfaces from upper bc for (auto ii = bc.NumSurfI() + bc.NumSurfJ(); ii < bc.NumSurfaces(); ii++) { if (bc.GetSurface(ii).SurfaceType() == 6) { // upper k surface - // at upper k surface for upper block, if bc is interblock, store + // at upper k surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1961,9 +1709,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = 0; ii < bc.NumSurfI(); ii++) { - // at i surface for upper block_, if bc is interblock, store + // at i surface for upper block_, if bc is connection, store // boundarySurface because partner block_ BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -1986,9 +1734,9 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, cc++; } for (auto ii = bc.NumSurfI(); ii < bc.NumSurfI() + bc.NumSurfJ(); ii++) { - // at j surface for upper block, if bc is interblock, store + // at j surface for upper block, if bc is connection, store // boundarySurface because partner block BC will need to be updated - if (bc.GetBCTypes(ii) == "interblock") { + if (bc.IsConnection(ii)) { alteredSurf.push_back(bc.GetSurface(ii)); } @@ -2006,12 +1754,39 @@ void boundaryConditions::Join(const boundaryConditions &bc, const string &dir, (*this) = newBC; } else { - cerr << "ERROR: Error in procBlock::Join(). Direction " << dir + cerr << "ERROR: Error in boundaryConditions::Join(). Direction " << dir << " is not recognized! Choose either i, j, or k." << endl; exit(EXIT_FAILURE); } aSurf = alteredSurf; + this->Merge(dir); +} + +void boundaryConditions::Merge(const string &dir) { + vector del; + for (auto &surf1 : surfs_) { + auto ind = 0; + for (auto &surf2 : surfs_) { + auto joined = false; + surf1.Join(surf2, dir, joined); + if (joined) { + del.push_back(ind); + if (surf1.Direction3() == "i") { + numSurfI_--; + } else if (surf1.Direction3() == "j") { + numSurfJ_--; + } else { + numSurfK_--; + } + } + ind++; + } + } + + for (auto ii = static_cast(del.size()) - 1; ii >= 0; --ii) { + surfs_.erase(std::begin(surfs_) + del[ii]); + } } // constructor when passed no arguements @@ -2036,13 +1811,14 @@ patch::patch() { patchBorder_[1] = false; patchBorder_[2] = false; patchBorder_[3] = false; + bcName_ = "undefined"; } // constructor with arguements passed patch::patch(const int &bound, const int &b, const int &d1s, const int &d1e, const int &d2s, const int &d2e, const int &d3s, const int &d3e, const plot3dBlock &blk, const int &r, const int &l, - const bool (&border)[4]) { + const array &border, const string &name) { // bound -- boundary number which patch is on (1-6) // b -- parent block number // d1s -- direction 1 starting index @@ -2053,7 +1829,8 @@ patch::patch(const int &bound, const int &b, const int &d1s, const int &d1e, // blk -- plot3dBlock that patch is on // r -- rank of block // l -- local position of block - // border -- flags indicating if patch borders an interblock bc on sides 1/2 + // border -- flags indicating if patch borders an connection bc on sides 1/2 + // name -- bc name boundary_ = bound; block_ = b; @@ -2063,6 +1840,7 @@ patch::patch(const int &bound, const int &b, const int &d1s, const int &d1e, patchBorder_[1] = border[1]; patchBorder_[2] = border[2]; patchBorder_[3] = border[3]; + bcName_ = name; if (bound == 1 || bound == 2) { // patch on i-surface - dir1 = j, dir2 = k d1Start_ = d2s; @@ -2134,11 +1912,72 @@ patch::patch(const int &bound, const int &b, const int &d1s, const int &d1e, } } +// member function to transform patch based on given bc data +// this is used for periodic boundaries +void patch::Transform(const shared_ptr &bcData) { + if (bcData->IsTranslation()) { + const auto translation = bcData->Translation(); + this->Translate(translation); + } else if (bcData->IsRotation()) { + const auto axis = bcData->Axis(); + const auto point = bcData->Point(); + const auto rotation = bcData->Rotation(); + this->Rotate(axis, point, rotation); + } else { + cerr << "ERROR. BC data for transformation is not translation or rotation!" + << endl; + exit(EXIT_FAILURE); + } +} + +// member function to transform patch based on given translation +// this is used for periodic boundaries +void patch::Translate(const vector3d &translate) { + origin_ += translate; + corner1_ += translate; + corner2_ += translate; + corner12_ += translate; +} + +// member function to transform patch based on given rotation +// this is used for periodic boundaries +void patch::Rotate(const vector3d &axis, const vector3d &point, + const double &rotation) { + // lambda function to rotate given point + auto rotate = [&axis, &point, &rotation] (vector3d &pr) { + auto p0 = pr; + pr[0] = (point[0] * (pow(axis[1], 2.) + pow(axis[2], 2.)) - axis[0] * + (point[1] * axis[1] + point[2] * axis[2] - axis.DotProd(p0))) * + (1. - cos(rotation)) + p0[0] * cos(rotation) + + (-point[2] * axis[1] + point[1] * axis[2] - axis[2] * p0[1] + + axis[1] * p0[2]) * sin(rotation); + + pr[1] = (point[1] * (pow(axis[0], 2.) + pow(axis[2], 2.)) - axis[1] * + (point[0] * axis[0] + point[2] * axis[2] - axis.DotProd(p0))) * + (1. - cos(rotation)) + p0[1] * cos(rotation) + + (point[2] * axis[0] - point[0] * axis[2] + axis[2] * p0[0] - + axis[0] * p0[2]) * sin(rotation); + + pr[2] = (point[2] * (pow(axis[0], 2.) + pow(axis[1], 2.)) - axis[2] * + (point[0] * axis[0] + point[1] * axis[1] - axis.DotProd(p0))) * + (1. - cos(rotation)) + p0[2] * cos(rotation) + + (-point[1] * axis[0] + point[0] * axis[1] - axis[1] * p0[0] + + axis[0] * p0[1]) * sin(rotation); + }; + + rotate(origin_); + rotate(corner1_); + rotate(corner2_); + rotate(corner12_); +} + + // operator overload for << - allows use of cout, cerr, etc. ostream &operator<<(ostream &os, const patch &p) { // os -- ostream to print to // p -- patch to print + os << "BC Type: " << p.BCType() << endl; os << "Boundary: " << p.Boundary() << endl; os << "Block: " << p.Block() << endl; os << "Direction 1 Start: " << p.Dir1Start() << endl; @@ -2147,7 +1986,7 @@ ostream &operator<<(ostream &os, const patch &p) { os << "Direction 2 End: " << p.Dir2End() << endl; os << "Constant Surface: " << p.ConstSurface() << endl; os << "Rank: " << p.Rank() << endl; - os << "Borders Interblock: " << p.Dir1StartInterBorder() << ", " + os << "Borders Connection: " << p.Dir1StartInterBorder() << ", " << p.Dir1EndInterBorder() << ", " << p.Dir2StartInterBorder() << ", " << p.Dir2EndInterBorder() << endl; os << "Origin: " << p.Origin() << endl; @@ -2166,14 +2005,6 @@ void boundaryConditions::PackBC(char *(&sendBuffer), const int &sendBufSize, // sendBufSize -- size of buffer // position -- location within buffer - // get string lengths for each boundary_ condition to be sent, so processors - // unpacking know how much data to unpack for each string - vector strLength(this->NumSurfaces()); - for (auto jj = 0U; jj < strLength.size(); jj++) { - // +1 for c_str end character - strLength[jj] = this->GetBCTypes(jj).size() + 1; - } - // pack surface numbers MPI_Pack(&numSurfI_, 1, MPI_INT, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); @@ -2181,20 +2012,10 @@ void boundaryConditions::PackBC(char *(&sendBuffer), const int &sendBufSize, MPI_COMM_WORLD); MPI_Pack(&numSurfK_, 1, MPI_INT, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); - // pack non-string data from boundarySurface - for (auto jj = 0; jj < this->NumSurfaces(); jj++) { - MPI_Pack(&surfs_[jj].data_[0], 7, MPI_INT, sendBuffer, sendBufSize, - &position, MPI_COMM_WORLD); - } - // pack string size - MPI_Pack(&strLength[0], strLength.size(), MPI_INT, sendBuffer, sendBufSize, - &position, MPI_COMM_WORLD); - // pack boundary condtion names - for (auto jj = 0; jj < this->NumSurfaces(); jj++) { - MPI_Pack(surfs_[jj].bcType_.c_str(), - surfs_[jj].bcType_.size() + 1, MPI_CHAR, sendBuffer, - sendBufSize, &position, - MPI_COMM_WORLD); // +1 for c_str end character + + // pack boundary surfaces + for (auto &surf : surfs_) { + surf.PackBoundarySurface(sendBuffer, sendBufSize, position); } } @@ -2215,28 +2036,78 @@ void boundaryConditions::UnpackBC(char *(&recvBuffer), const int &recvBufSize, // resize boundaryCondition this->ResizeVecs(this->NumSurfaces()); - // allocate vector for string lengths - vector strLength(this->NumSurfaces()); - // unpack boundary condition surface data (non-string) into appropriate - // vectors - for (auto jj = 0; jj < this->NumSurfaces(); jj++) { - MPI_Unpack(recvBuffer, recvBufSize, &position, &surfs_[jj].data_[0], - 7, MPI_INT, MPI_COMM_WORLD); // unpack bc surfaces + // unpack boundary surfaces + for (auto &surf : surfs_) { + surf.UnpackBoundarySurface(recvBuffer, recvBufSize, position); } - MPI_Unpack(recvBuffer, recvBufSize, &position, &strLength[0], - strLength.size(), MPI_INT, MPI_COMM_WORLD); // unpack string sizes +} + +/*Member function to pack a boundarySurface into a buffer so that in can be + * sent with MPI.*/ +void boundarySurface::PackBoundarySurface(char *(&sendBuffer), + const int &sendBufSize, + int &position) const { + // sendBuffer -- buffer to pack data into + // sendBufSize -- size of buffer + // position -- location within buffer + + // pack non-string data from boundarySurface + MPI_Pack(&data_[0], 7, MPI_INT, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + + // pack string size + auto strLength = bcType_.size() + 1; // +1 for c_str end character + MPI_Pack(&strLength, 1, MPI_INT, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + // pack boundary condtion name + // +1 for c_str end character + MPI_Pack(bcType_.c_str(), bcType_.size() + 1, MPI_CHAR, sendBuffer, + sendBufSize, &position, MPI_COMM_WORLD); +} + +/*Member function to unpack data from a buffer into a boundarySurface. Used + * with MPI receive*/ +void boundarySurface::UnpackBoundarySurface(char *(&recvBuffer), + const int &recvBufSize, + int &position) { + // recvBuffer -- buffer to unpack data from + // recvBufSize -- size of buffer + // position -- location within buffer + + // unpack boundary condition surface data (non-string) + MPI_Unpack(recvBuffer, recvBufSize, &position, &data_[0], 7, MPI_INT, + MPI_COMM_WORLD); + + // unpack string sizes + auto strLength = 0; + MPI_Unpack(recvBuffer, recvBufSize, &position, &strLength, 1, MPI_INT, + MPI_COMM_WORLD); + // unpack boundary condition names - for (auto jj = 0U; jj < strLength.size(); jj++) { - auto *nameBuf = new char[strLength[jj]]; // allocate buffer to store BC - // name - MPI_Unpack(recvBuffer, recvBufSize, &position, &nameBuf[0], strLength[jj], - MPI_CHAR, MPI_COMM_WORLD); // unpack bc types - string bcName(nameBuf, strLength[jj] - 1); // create string of bc name (-1 - // to exclude c_str end - // character) - surfs_[jj].bcType_ = bcName; - delete[] nameBuf; // deallocate bc name buffer + // allocate buffer to store BC name + auto nameBuf = unique_ptr(new char[strLength]); + MPI_Unpack(recvBuffer, recvBufSize, &position, nameBuf.get(), strLength, + MPI_CHAR, MPI_COMM_WORLD); + // create string of bc name (-1 to exclude c_str end character) + string bcName(nameBuf.get(), strLength - 1); + bcType_ = bcName; +} + +void boundarySurface::IncrementDirection(const string &dir, const int &inc) { + if (dir == "i") { // increment i-surface + data_[0] += inc; + data_[1] += inc; + } else if (dir == "j") { // increment j-surface + data_[2] += inc; + data_[3] += inc; + } else if (dir == "k") { // increment k-surface + data_[4] += inc; + data_[5] += inc; + } else { + cerr << "ERROR. In boundarySurface::IncrementDirection() direction " << dir + << " is not recognized!" << endl; + exit(EXIT_FAILURE); } } @@ -2274,18 +2145,17 @@ int boundarySurface::SurfaceType() const { return surf; } -// member function to determine the partner block_ of an interblock -// boundarySurface. The partner block_ is where the surface gets its ghost cells +// member function to determine the partner block of an interblock +// boundarySurface. The partner block is where the surface gets its ghost cells // from. int boundarySurface::PartnerBlock() const { if (bcType_ != "interblock") { - cerr << "ERROR: Partner blocks are only associated with interblock " - "boundaries. Current boundary_ is " << bcType_ << endl; - exit(EXIT_FAILURE); + // partner block only defined for interblock + return -1; + } else { + const auto subtract = this->PartnerSurface() * 1000; + return this->Tag() - subtract; } - - const auto subtract = this->PartnerSurface() * 1000; - return this->Tag() - subtract; } // member function to determine the partner surface of an interblock @@ -2293,33 +2163,32 @@ int boundarySurface::PartnerBlock() const { // cells from. int boundarySurface::PartnerSurface() const { if (bcType_ != "interblock") { - cerr << "ERROR: Partner blocks are only associated with interblock " - "boundaries. Current boundary_ is " << bcType_ << endl; - exit(EXIT_FAILURE); - } - - auto surf = 0; - - if (this->Tag() < 2000) { - surf = 1; // i-lower surface - } else if (this->Tag() < 3000) { - surf = 2; // i-upper surface - } else if (this->Tag() < 4000) { - surf = 3; // j-lower surface - } else if (this->Tag() < 5000) { - surf = 4; // j-upper surface - } else if (this->Tag() < 6000) { - surf = 5; // k-lower surface - } else if (this->Tag() < 7000) { - surf = 6; // k-upper surface + // partner surface only defined for interblock + return -1; } else { - cerr << "ERROR: Error in boundarySurface::PartnerSurface(). Tag does not " - "fit in range. Tag must be between 1000 and 6999." << endl; - cerr << (*this) << endl; - exit(EXIT_FAILURE); - } + auto surf = 0; + + if (this->Tag() < 2000) { + surf = 1; // i-lower surface + } else if (this->Tag() < 3000) { + surf = 2; // i-upper surface + } else if (this->Tag() < 4000) { + surf = 3; // j-lower surface + } else if (this->Tag() < 5000) { + surf = 4; // j-upper surface + } else if (this->Tag() < 6000) { + surf = 5; // k-lower surface + } else if (this->Tag() < 7000) { + surf = 6; // k-upper surface + } else { + cerr << "ERROR: Error in boundarySurface::PartnerSurface(). Tag does not " + "fit in range. Tag must be between 1000 and 6999." << endl; + cerr << (*this) << endl; + exit(EXIT_FAILURE); + } - return surf; + return surf; + } } // member function to return a string corresponding to which direction (i,j,k) @@ -2426,18 +2295,28 @@ int boundarySurface::Min2() const { return m; } -// member function to return the number of faces this boundary surface is -// applied to -int boundarySurface::NumFaces() const { - auto nFaces = 0; - if (this->SurfaceType() <= 2) { // i-surface - nFaces = (this->JMax() - this->JMin()) * (this->KMax() - this->KMin()); - } else if (this->SurfaceType() <= 4) { // j-surface - nFaces = (this->IMax() - this->IMin()) * (this->KMax() - this->KMin()); - } else { // k-surface - nFaces = (this->IMax() - this->IMin()) * (this->JMax() - this->JMin()); +int boundarySurface::Min(const string &dir) const { + auto ind = 0; + if (dir == "i") { + ind = this->IMin(); + } else if (dir == "j") { + ind = this->JMin(); + } else { + ind = this->KMin(); } - return nFaces; + return ind; +} + +int boundarySurface::Max(const string &dir) const { + auto ind = 0; + if (dir == "i") { + ind = this->IMax(); + } else if (dir == "j") { + ind = this->JMax(); + } else { + ind = this->KMax(); + } + return ind; } range boundarySurface::RangeI() const { @@ -2496,144 +2375,239 @@ ostream &operator<<(ostream &os, const boundarySurface &bcSurf) { return os; } -// member funtion to updat the tag of an interblock to partner with the block_ +// member funtion to updat the tag of an interblock to partner with the block // input to the function void boundarySurface::UpdateTagForSplitJoin(const int &nBlk) { if (bcType_ != "interblock") { cerr << "ERROR: Only tags associated with interblock boundaries need to be " - "updated. Current boundary_ is " << bcType_ << endl; + "updated. Current boundary is " << bcType_ << endl; exit(EXIT_FAILURE); } data_[6] = this->PartnerSurface() * 1000 + nBlk; } -// member function to split a boundary_ surface. The calling instance retains +// member function to split a boundarySurface. The calling instance retains // the lower portion of the split, and the returned instance retains the upper -// portion +// portion. This is used to split non-connections boundarySurface boundarySurface::Split(const string &dir, const int &ind, - const int &lBlk, const int &uBlk, - bool &split, int orientation) { + bool &split, bool &low, + const bool relToSplit) { // dir -- direction to split the surface in // ind -- index at which to split the surface - // lBlk -- lower block_ number of split - // uBlk -- upper block_ number of split - // split -- flag to determine whether block_ was split or just tag updated, if - // no split, upper surface returned is meaningless - // orientation -- if called from DependentSplit, orientation of partner split - - const auto indNG = ind; - - auto surf1 = (*this); // lower surface - auto surf2 = (*this); // upper surface - - split = true; // initialize split flag - // flag to determine if the split direction is reversed - used to determine - // which block_ should match lower/upper surfaces - // surf1 and surf2 have same orientation, so if reversed for 1, reversed for 2 - const auto isReversed = surf1.SplitDirectionIsReversed(dir, orientation); - - if (dir == "i") { // split along i-plane - if (this->SurfaceType() == 1 || this->SurfaceType() == 2 || - indNG <= 0) { - // cannot split an i-surface along i-plane, just update block - surf1.UpdateTagForSplitJoin(uBlk); + // split -- flag to determine whether surface was split + // low -- flag that is true if unsplit surface is on lower side of split + // relToSplit -- flag (default true) to make upper surface indices relative + // to split index + + auto lower = (*this); // lower surface + auto upper = (*this); // upper surface + + if (dir == "i" && this->Direction3() != "i") { + if (this->IMin() >= ind) { + // this surface is only present in the upper split + if (relToSplit) { + upper.data_[0] -= ind; // imin + upper.data_[1] -= ind; // imax + } split = false; - } else { // j or k surface - if (this->IMin() >= indNG) { - // this surface is only present in the upper split - surf1.data_[0] = this->IMin() - indNG + 1 + this->IMin(); // imin - surf1.data_[1] = this->IMax() - indNG + 1 + this->IMin(); // imax - isReversed ? surf1.UpdateTagForSplitJoin(lBlk) - : surf1.UpdateTagForSplitJoin(uBlk); - split = false; - } else if (this->IMax() >= indNG) { // this surface straddles the split - surf2.data_[0] = indNG; // imin - isReversed ? surf2.UpdateTagForSplitJoin(lBlk) - : surf2.UpdateTagForSplitJoin(uBlk); - - surf1.data_[1] = indNG; // imax - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - } else { // this surface is only present in the lower split - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - split = false; + low = false; + lower = boundarySurface(); + } else if (this->IMax() > ind) { // this surface straddles the split + upper.data_[0] = ind; // imin + if (relToSplit) { + upper.data_[0] -= ind; // imin + upper.data_[1] -= ind; // imax } + lower.data_[1] = ind; // imax + split = true; + } else { // this surface is only present in the lower split + upper = boundarySurface(); + split = false; + low = true; } - - } else if (dir == "j") { // split along j-plane - if (this->SurfaceType() == 3 || this->SurfaceType() == 4 || - indNG <= 0) { - // cannot split a j-surface along j-plane, just update block - surf1.UpdateTagForSplitJoin(uBlk); + } else if (dir == "j" && this->Direction3() != "j") { + if (this->JMin() >= ind) { + // this surface is only present in the upper split + if (relToSplit) { + upper.data_[2] -= ind; // jmin + upper.data_[3] -= ind; // jmax + } split = false; - } else { // i or k surface - if (this->JMin() >= indNG) { - // this surface is only present in the upper split - surf1.data_[2] = this->JMin() - indNG + 1 + this->JMin(); // jmin - surf1.data_[3] = this->JMax() - indNG + 1 + this->JMin(); // jmax - isReversed ? surf1.UpdateTagForSplitJoin(lBlk) - : surf1.UpdateTagForSplitJoin(uBlk); - split = false; - } else if (this->JMax() >= indNG) { // this surface straddles the split - surf2.data_[2] = indNG; // jmin - isReversed ? surf2.UpdateTagForSplitJoin(lBlk) - : surf2.UpdateTagForSplitJoin(uBlk); - - surf1.data_[3] = indNG; // jmax - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - } else { // this surface is only present in the lower split - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - split = false; + low = false; + lower = boundarySurface(); + } else if (this->JMax() > ind) { // this surface straddles the split + upper.data_[2] = ind; // jmin + if (relToSplit) { + upper.data_[2] -= ind; // jmin + upper.data_[3] -= ind; // jmax } + lower.data_[3] = ind; // jmax + split = true; + } else { // this surface is only present in the lower split + upper = boundarySurface(); + split = false; + low = true; } - - } else if (dir == "k") { // split along k-plane - if (this->SurfaceType() == 5 || this->SurfaceType() == 6 || - indNG <= 0) { - // cannot split a k-surface along k-plane, just update block - surf1.UpdateTagForSplitJoin(uBlk); + } else if (dir == "k" && this->Direction3() != "k") { + if (this->KMin() >= ind) { // surface only present in the upper split + if (relToSplit) { + upper.data_[4] -= ind; // kmin + upper.data_[5] -= ind; // kmax + } + split = false; + low = false; + lower = boundarySurface(); + } else if (this->KMax() > ind) { // this surface straddles the split + upper.data_[4] = ind; // kmin + if (relToSplit) { + upper.data_[4] -= ind; // kmin + upper.data_[5] -= ind; // kmax + } + lower.data_[5] = ind; // kmax + split = true; + } else { // this surface is only present in the lower split + upper = boundarySurface(); split = false; - } else { // i or j surface - if (this->KMin() >= - indNG) { // this surface is only present in the upper split - surf1.data_[4] = this->KMin() - indNG + 1 + this->KMin(); // kmin - surf1.data_[5] = this->KMax() - indNG + 1 + this->KMin(); // kmax - isReversed ? surf1.UpdateTagForSplitJoin(lBlk) - : surf1.UpdateTagForSplitJoin(uBlk); - split = false; - } else if (this->KMax() >= indNG) { // this surface straddles the split - surf2.data_[4] = indNG; // kmin - isReversed ? surf2.UpdateTagForSplitJoin(lBlk) - : surf2.UpdateTagForSplitJoin(uBlk); - - surf1.data_[5] = indNG; // kmax - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - } else { // this surface is only present in the lower split - isReversed ? surf1.UpdateTagForSplitJoin(uBlk) - : surf1.UpdateTagForSplitJoin(lBlk); - split = false; + low = true; + } + } else { // not split; dir and surface dir are the same + split = false; + if (ind >= this->Ind3()) { + low = true; + upper = boundarySurface(); + } else { + low = false; + lower = boundarySurface(); + if (dir == "i" && relToSplit) { + upper.data_[0] -= ind; // imin + upper.data_[1] -= ind; // imax + } else if (dir == "j" && relToSplit) { + upper.data_[2] -= ind; // jmin + upper.data_[3] -= ind; // jmax + } else if (dir == "k" && relToSplit) { + upper.data_[4] -= ind; // kmin + upper.data_[5] -= ind; // kmax } } + } + + (*this) = lower; + return upper; +} +void boundarySurface::Join(const boundarySurface &upper, const string &dir, + bool &joined) { + // can only join if surfaces are same direction and have same index, and + // bc type is the same, tag is the same, and lower max index equals upper + // min index + if (this->Direction3() == upper.Direction3() && + this->Ind3() == upper.Ind3() && this->BCType() == upper.BCType() && + this->Tag() == upper.Tag() && this->Max(dir) == upper.Min(dir) && + *this != upper) { + // only join if the transverse (not dir 3 or split dir) ranges are equal + const auto transDirIs1 = this->Direction2() == dir; + const auto lowTransRange = + transDirIs1 ? this->RangeDir1() : this->RangeDir2(); + const auto upTransRange = + transDirIs1 ? upper.RangeDir1() : upper.RangeDir2(); + if (lowTransRange == upTransRange) { + if (dir == "i") { + data_[1] = upper.IMax(); // change imax + } else if (dir == "j") { + data_[3] = upper.JMax(); // change jmax + } else { + data_[5] = upper.KMax(); // change kmax + } + joined = true; + } else { + joined = false; + } } else { - cerr << "ERROR: Error in boundarySurface::Split(). Direction " << dir - << " is not recognized! Choose either i, j, or k." << endl; - exit(EXIT_FAILURE); + joined = false; + } +} + +// 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) { + // dir -- direction to split the surface in + // ind -- index at which to split the surface + // sBlk -- block number that *this surface belongs to + // lBlk -- lower block number of split + // uBlk -- upper block number of split + // split -- flag to determine whether block was split or just tag updated, if + // no split, upper surface returned is meaningless + // low -- flag to determine if unsplit surface is on lower side of split + // orientation -- orientation of connection + + // flag to determine if the split direction is reversed - used to determine + // which block should match lower/upper surfaces; lower and upper have same + // orientation, so if reversed for one, reversed for both + const auto isReversed = this->SplitDirectionIsReversed(dir, orientation); + // flag to determine if c-grid is being split to h-grid + const auto splitCgrid = this->SplitCGridToHGrid(dir, sBlk, lBlk, uBlk); + + auto upper = this->Split(dir, ind, split, low, false); + + if (splitCgrid) { + if (split) { + // if c-grid split, partner block should not be self + if (sBlk == lBlk) { + lBlk = uBlk; + } else { + uBlk = lBlk; + } + } else if (low) { + // if c-grid split & 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 + if (sBlk == uBlk) { + uBlk = lBlk; + } + } + } else if (isReversed) { + std::swap(lBlk, uBlk); + } + + if (split) { + upper.UpdateTagForSplitJoin(uBlk); + this->UpdateTagForSplitJoin(lBlk); + } else if (low) { + this->UpdateTagForSplitJoin(lBlk); + } else { + upper.UpdateTagForSplitJoin(uBlk); } - (*this) = surf1; // return lower surface as (*this) - return surf2; + return upper; +} + +// member function to determine if a c-grid is being split in such a way that +// the c-grid turns into an h-grid +bool boundarySurface::SplitCGridToHGrid(const string &dir, const int &sblk, + const int &lblk, + const int &ublk) const { + auto splitCgrid = false; + if ((sblk == lblk) || (sblk == ublk)) { + // to split c-grid, self index must be one of split indices + if (this->Direction3() != dir) { + // to break c-grid topology, split must be done on direction other than + // direction of c-grid interface bc + splitCgrid = true; + } + } + return splitCgrid; } /*member function to determine if the split direction is reversed. A "reversed" -split direction occurs when the two patches that make an interblock have their -split direction -running in opposite directions. +split direction occurs when the two patches that make an connection have their +split direction running in opposite directions. ______ ______ | | | | | | 1 | \/ | 2 | @@ -2642,10 +2616,9 @@ split-> |______| |______| | |^ | | |______|| |______| -As you can see, the index for the split would be different in block_ 1 vs block_ +As you can see, the index for the split would be different in block 1 vs block 2 because the direction of the increasing index is reversed. This situation is a -"reversed" split -direction. This function finds cases such as these. +"reversed" split direction. This function finds cases such as these. */ bool boundarySurface::SplitDirectionIsReversed(const string &dir, const int &orientation) const { @@ -2655,17 +2628,16 @@ bool boundarySurface::SplitDirectionIsReversed(const string &dir, auto isReversed = false; // find out if split direction is 1, 2, or 3 - if (this->Direction1() == - dir) { // split direction is direction 1 - reverse if dir 1 is reversed - // (relative to partner, taking into account D1/D2 swap) + if (this->Direction1() == dir) { + // split direction is direction 1 - reverse if dir 1 is reversed + // (relative to partner, taking into account D1/D2 swap) isReversed = (orientation == 3 || orientation == 5 || orientation == 7 || orientation == 8) ? true : false; - } else if (this->Direction2() == dir) { // split direction is direction 2 - - // reverse if dir 2 is reversed - // (relative to partner, taking - // into account D1/D2 swap) + } else if (this->Direction2() == dir) { + // split direction is direction 2 - reverse if dir 2 is reversed + // (relative to partner, taking into account D1/D2 swap) isReversed = (orientation == 4 || orientation == 6 || orientation == 7 || orientation == 8) ? true @@ -2675,7 +2647,8 @@ bool boundarySurface::SplitDirectionIsReversed(const string &dir, isReversed = false; } else { cerr << "ERROR: Error in boundarySurface::SplitDirectionIsReversed(). " - "Direction " << dir << " does not match i, j, or k!" << endl; + "Direction " + << dir << " does not match i, j, or k!" << endl; exit(EXIT_FAILURE); } @@ -2683,26 +2656,26 @@ bool boundarySurface::SplitDirectionIsReversed(const string &dir, } /* Function to return an array of location indicies for ghost cells at an -interblock boundary. The array is formatted as shown below: +connection boundary. The array is formatted as shown below: array = [i j k] The array will contain 3 entries corresponding to the i, j, and k locations of -either the first or second pair in the interblock, depending on what is +either the first or second pair in the connection, depending on what is specified in the 'first' variable. The indices returned will correspond to cell locations and will take into account the orientation of the patches that -comprise the interblock with relation to each other. +comprise the connection with relation to each other. */ array GetSwapLoc(const int &l1, const int &l2, const int &l3, - const int &numGhosts, const interblock &inter, + const int &numGhosts, const connection &inter, const int &d3, const bool &first) { // l1 -- index of direction 1 within slice to insert // l2 -- index of direction 2 within slice to insert // l3 -- index of direction 3 within slice to insert // numGhosts -- number of layers of ghost cells - // inter -- interblock boundary condition - // d3 -- length of normal direction of interblock - // first -- flag for first or second block in interblock match + // inter -- connection boundary condition + // d3 -- length of normal direction of connection + // first -- flag for first or second block in connection match // preallocate array to return array loc = {0, 0, 0}; diff --git a/src/eos.cpp b/src/eos.cpp index 9d01b92..3a3c0b1 100644 --- a/src/eos.cpp +++ b/src/eos.cpp @@ -34,6 +34,11 @@ double idealGas::PressFromEnergy(const double &rho, const double &energy, return (gamma_ - 1.0) * rho * (energy - 0.5 * vel * vel); } +double idealGas::PressureRT(const double &rho, + const double &temperature) const { + return temperature * rho / gamma_; +} + double idealGas::Density(const double &pressure, const double &specEn) const { return pressure / ((gamma_ - 1.0) * specEn); diff --git a/src/fluxJacobian.cpp b/src/fluxJacobian.cpp index a3bf44a..2f1af38 100644 --- a/src/fluxJacobian.cpp +++ b/src/fluxJacobian.cpp @@ -75,10 +75,10 @@ bool fluxJacobian::IsScalar() const { } // function to take the inverse of a flux jacobian -void fluxJacobian::Inverse(const bool &isTurbulent) { +void fluxJacobian::Inverse(const bool &isRANS) { flowJacobian_.Inverse(); - if (isTurbulent) { + if (isRANS) { turbJacobian_.Inverse(); } } @@ -122,7 +122,7 @@ void fluxJacobian::RusanovFluxJacobian(const primVars &state, this->InvFluxJacobian(state, eos, area, inp, turb); // compute turbulent dissipation if necessary - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { // multiply by 0.5 b/c averaging with convection matrix dissipation.turbJacobian_ = 0.5 * turb->InviscidDissJacobian(state, area); } @@ -201,7 +201,7 @@ void fluxJacobian::InvFluxJacobian(const primVars &state, flowJacobian_ *= 0.5 * area.Mag(); // turbulent jacobian here - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { // multiply by 0.5 b/c averaging with dissipation matrix turbJacobian_ = 0.5 * turb->InviscidConvJacobian(state, area); } @@ -289,7 +289,7 @@ void fluxJacobian::DelPrimativeDelConservative(const primVars &state, flowJacobian_(4, 4) = gammaMinusOne; // turbulent jacobian here - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { turbJacobian_(0, 0) = invRho; turbJacobian_(1, 1) = invRho; } @@ -371,7 +371,7 @@ void fluxJacobian::ApproxTSLJacobian(const primVars &state, flowJacobian_ = flowJacobian_.MatMult(prim2Cons.flowJacobian_); // calculate turbulent jacobian if necessary - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { turbJacobian_ = fac * turb->ViscousJacobian(state, area, lamVisc, suth, dist, turbVisc, f1); // Don't need to multiply by prim2Cons b/c jacobian is already wrt @@ -512,7 +512,7 @@ genArray OffDiagonal(const primVars &offDiag, const primVars &diag, // always use flux change off diagonal with roe method offDiagonal = RoeOffDiagonal(offDiag, diag, update, fArea, mu, mut, f1, dist, eos, suth, turb, - inp.IsViscous(), inp.IsTurbulent(), + inp.IsViscous(), inp.IsRANS(), positive); } else { cerr << "ERROR: Error in OffDiagonal(), inviscid flux jacobian method of " @@ -532,7 +532,7 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, const idealGas &eos, const sutherland &suth, const unique_ptr &turb, - const bool &isViscous, const bool &isTurbulent, + const bool &isViscous, const bool &isRANS, const bool &positive) { // offDiag -- primative variables at off diagonal // diag -- primative variables at diagonal @@ -546,7 +546,7 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, // suth -- sutherland's law for viscosity // turb -- turbulence model // isViscous -- flag to determine if simulation is viscous - // isTurbulent -- flag to determine if simulation is turbulent + // isRANS -- flag to determine if simulation is turbulent // positive -- flag to determine whether to add or subtract dissipation // DEBUG -- redo this whole function to not use the flux change and instead @@ -574,7 +574,7 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, offDiag.ViscFaceSpectralRadius(fArea, eos, suth, dist, mu, mut, turb)); - if (isTurbulent) { + if (isRANS) { specRad.AddToTurbVariable(turb->ViscFaceSpecRad(offDiag, fArea, mu, suth, dist, mut, f1)); } @@ -585,30 +585,30 @@ genArray RoeOffDiagonal(const primVars &offDiag, const primVars &diag, } void fluxJacobian::MultiplyOnDiagonal(const double &val, - const bool &isTurbulent) { + const bool &isRANS) { // val -- value to multiply along diagonal - // isTurbulent -- flag identifiying if simulation is turbulent + // isRANS -- flag identifiying if simulation is turbulent for (auto ii = 0; ii < flowJacobian_.Size(); ii++) { flowJacobian_(ii, ii) *= val; } - if (isTurbulent) { + if (isRANS) { for (auto ii = 0; ii < turbJacobian_.Size(); ii++) { turbJacobian_(ii, ii) *= val; } } } -void fluxJacobian::AddOnDiagonal(const double &val, const bool &isTurbulent) { +void fluxJacobian::AddOnDiagonal(const double &val, const bool &isRANS) { // val -- value to multiply along diagonal - // isTurbulent -- flag identifiying if simulation is turbulent + // isRANS -- flag identifiying if simulation is turbulent for (auto ii = 0; ii < flowJacobian_.Size(); ii++) { flowJacobian_(ii, ii) += val; } - if (isTurbulent) { + if (isRANS) { for (auto ii = 0; ii < turbJacobian_.Size(); ii++) { turbJacobian_(ii, ii) += val; } diff --git a/src/input.cpp b/src/input.cpp index 33305c9..3bc6537 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -53,6 +53,7 @@ input::input(const string &name, const string &resName) : simName_(name), pRef_ = -1.0; rRef_ = -1.0; lRef_ = 1.0; + aRef_ = 0.0; vRef_ = {1.0, 0.0, 0.0}; gamma_ = 1.4; gasConst_ = 287.058; @@ -89,6 +90,7 @@ input::input(const string &name, const string &resName) : simName_(name), // default to primative variables outputVariables_ = {"density", "vel_x", "vel_y", "vel_z", "pressure"}; + wallOutputVariables_ = {}; // keywords in the input file that the parser is looking for to define // variables @@ -122,6 +124,7 @@ input::input(const string &name, const string &resName) : simName_(name), "decompositionMethod", "turbulenceModel", "outputVariables", + "wallOutputVariables", "initialConditions", "boundaryStates", "boundaryConditions"}; @@ -393,6 +396,33 @@ void input::ReadInput(const int &rank) { numChars += vars.length(); if (numChars >= 50) { // if more than 50 chars, go to next line cout << endl << " "; + numChars = 0U; + } + } + count++; + } + cout << endl; + } + } else if (key == "wallOutputVariables") { + // clear default variables from set + wallOutputVariables_.clear(); + auto specifiedVars = ReadStringList(inFile, tokens[1]); + for (auto &vars : specifiedVars) { + wallOutputVariables_.insert(vars); + } + if (rank == ROOTP) { + cout << key << ": <"; + auto count = 0U; + auto numChars = 0U; + for (auto &vars : wallOutputVariables_) { + if (count == wallOutputVariables_.size() - 1) { + cout << vars << ">" << endl; + } else { + cout << vars << ", "; + numChars += vars.length(); + if (numChars >= 50) { // if more than 50 chars, go to next line + cout << endl << " "; + numChars = 0U; } } count++; @@ -489,6 +519,7 @@ void input::ReadInput(const int &rank) { // input file sanity checks this->CheckNonlinearIterations(); this->CheckOutputVariables(); + this->CheckWallOutputVariables(); this->CheckTurbulenceModel(); if (rank == ROOTP) { @@ -508,20 +539,17 @@ void input::CalcCFL(const int &ii) { // member function to determine number of turbulence equations int input::NumTurbEquations() const { - auto numEqns = 0; - if (this->IsTurbulent()) { - numEqns = 2; - } - return numEqns; + return (this->IsRANS()) ? 2 : 0; } // member function to determine number of equations to solver for int input::NumEquations() const { auto numEqns = 0; - if ((equationSet_ == "euler") || - (equationSet_ == "navierStokes")) { + if (equationSet_ == "euler" || + equationSet_ == "navierStokes" || + equationSet_ == "largeEddySimulation") { numEqns = this->NumFlowEquations(); - } else if (equationSet_ == "rans") { + } else if (this->IsRANS()) { numEqns = this->NumFlowEquations() + this->NumTurbEquations(); } else { cerr << "ERROR: Equations set is not recognized. Cannot determine number " @@ -544,8 +572,7 @@ bool input::IsImplicit() const { // member function to determine of method is vicous or inviscid bool input::IsViscous() const { - if (equationSet_ == "navierStokes" || - equationSet_ == "rans") { + if (equationSet_ == "navierStokes" || this->IsTurbulent()) { return true; } else { return false; @@ -554,13 +581,23 @@ bool input::IsViscous() const { // member function to determine of method is turbulent bool input::IsTurbulent() const { - if (equationSet_ == "rans") { + if (this->IsRANS() || this->IsLES()) { return true; } else { return false; } } +// member function to determine if simulation is RANS +bool input::IsRANS() const { + return (equationSet_ == "rans") ? true : false; +} + +// member function to determine if simulation is LES +bool input::IsLES() const { + return (equationSet_ == "largeEddySimulation") ? true : false; +} + // member function to determine if solution should use a block matrix bool input::IsBlockMatrix() const { if (this->IsImplicit() && (matrixSolver_ == "bdplur" || @@ -598,6 +635,10 @@ unique_ptr input::AssignTurbulenceModel() const { turb = unique_ptr{std::make_unique()}; } else if (turbModel_ == "sst2003") { turb = unique_ptr{std::make_unique()}; + } else if (turbModel_ == "sstdes") { + turb = unique_ptr{std::make_unique()}; + } else if (turbModel_ == "wale") { + turb = unique_ptr{std::make_unique()}; } else { cerr << "ERROR: Error in input::AssignTurbulenceModel(). Turbulence model " << turbModel_ << " is not recognized!" << endl; @@ -631,39 +672,70 @@ void input::CheckNonlinearIterations() { // member function to check validity of the requested output variables void input::CheckOutputVariables() { - for (auto var : outputVariables_) { - if (!this->IsTurbulent()) { // can't have turbulent varibles output - if (var == "tke" || var == "sdr" || var == "viscosityRatio" || - var.find("tkeGrad_") != string::npos || + auto oVars = outputVariables_; + for (auto &var : oVars) { + if (!this->IsRANS()) { // can't have RANS variables output + if (var == "tke" || var == "sdr" || var.find("tkeGrad_") != string::npos || var.find("sdrGrad_") != string::npos || var == "resid_tke" || - var == "resid_sdr") { + var == "resid_sdr" || var == "f1" || var == "f2") { + cerr << "WARNING: Variable " << var << + " is not available for non-RANS simulations." << endl; + outputVariables_.erase(var); + } + } + + if (!this->IsTurbulent()) { // can't have turbulent variables output + if (var == "viscosityRatio" || var == "turbulentViscosity") { cerr << "WARNING: Variable " << var << " is not available for laminar simulations." << endl; outputVariables_.erase(var); } + } - if (!this->IsViscous()) { // can't have viscous variables output - if (var.find("velGrad_") != string::npos - || var.find("tempGrad_") != string::npos) { - cerr << "WARNING: Variable " << var << - " is not available for inviscid simulations." << endl; - outputVariables_.erase(var); - } + if (!this->IsViscous()) { // can't have viscous variables output + if (var.find("velGrad_") != string::npos + || var.find("tempGrad_") != string::npos || var == "viscosity") { + cerr << "WARNING: Variable " << var << + " is not available for inviscid simulations." << endl; + outputVariables_.erase(var); } } } } +// member function to check validity of the requested output variables +void input::CheckWallOutputVariables() { + auto oVars = wallOutputVariables_; + for (auto &var : oVars) { + if (!this->IsViscous()) { // can't have viscous variables output + if (var == "yplus" || var == "heatFlux") { + cerr << "WARNING: Wall variable " << var << + " is not available for inviscid simulations." << endl; + outputVariables_.erase(var); + } + } + } +} + + // member function to check that turbulence model makes sense with equation set void input::CheckTurbulenceModel() const { - if (equationSet_ == "rans" && turbModel_ == "none") { - cerr << "ERROR: If solving RANS equations, must specify turbulence model!" - << endl; + if (this->IsTurbulent() && turbModel_ == "none") { + cerr << "ERROR: If solving RANS or LES equations, must specify turbulence " + << "model!" << endl; exit(EXIT_FAILURE); } - if (equationSet_ != "rans" && turbModel_ != "none") { - cerr << "ERROR: Turbulence models are only valid for the RANS equation set!" - << endl; + if (!this->IsTurbulent() && turbModel_ != "none") { + cerr << "ERROR: Turbulence models are only valid for the RANS and LES " + << "equation sets!" << endl; + exit(EXIT_FAILURE); + } + if (this->IsRANS() && turbModel_ == "wale") { + cerr << "ERROR: Equation set is RANS, but turbulence model is not!" << endl; + exit(EXIT_FAILURE); + } + if (this->IsTurbulent() && !this->IsRANS() && turbModel_ != "wale") { + cerr << "ERROR: Equation set is LES, but turbulence model is not!" << endl; exit(EXIT_FAILURE); } } @@ -689,17 +761,21 @@ bool input::MatrixRequiresInitialization() const { } int input::NumberGhostLayers() const { + auto layers = 0; if (this->UsingConstantReconstruction()) { - return 1; + layers = 1; } else if (this->UsingMUSCLReconstruction()) { - return 2; + layers = 2; } else if (this->UsingHigherOrderReconstruction()) { - return 3; + layers = 3; } else { cerr << "ERROR: Problem with face reconstruction. Not using any of the " << "supported methods!" << endl; exit(EXIT_FAILURE); } + + auto viscLayers = (this->ViscousFaceReconstruction() == "centralFourth") ? 2 : 1; + return std::max(layers, viscLayers); } // member function to get the initial condition state for a given parent block @@ -730,9 +806,10 @@ icState input::ICStateForBlock(const int &block) const { } // member function to return boundary condition data index for a given tag -const unique_ptr & input::BCData(const int &tag) const { +const shared_ptr & input::BCData(const int &tag) const { for (auto &bcData : bcStates_) { - if (bcData->Tag() == tag) { + // for non-periodic bcs tag = startTag = endTag + if (bcData->Tag() == tag || bcData->EndTag() == tag) { return bcData; } } @@ -742,7 +819,12 @@ const unique_ptr & input::BCData(const int &tag) const { exit(EXIT_FAILURE); } -// member function to return reference speed of sound -double input::ARef(const idealGas &eos) const { - return eos.SoS(pRef_, rRef_); -} +void input::NondimensionalizeStateData(const idealGas &eos) { + aRef_ = eos.SoS(pRef_, rRef_); + for (auto &state : bcStates_) { + state->Nondimensionalize(rRef_, tRef_, lRef_, aRef_); + } + for (auto &ic : ics_) { + ic.Nondimensionalize(rRef_, tRef_, lRef_, aRef_); + } +} \ No newline at end of file diff --git a/src/inputStates.cpp b/src/inputStates.cpp index 6862b50..548b095 100644 --- a/src/inputStates.cpp +++ b/src/inputStates.cpp @@ -134,6 +134,10 @@ void viscousWall::Print(ostream &os) const { } else if (specifiedHeatFlux_) { os << "; heatFlux=" << this->HeatFlux(); } + os << "; wallTreatment=" << wallTreatment_; + if (this->IsWallLaw()) { + os << "; vonKarmen=" << vonKarmen_ << "; wallConstant=" << wallConstant_; + } os << ")"; } @@ -142,6 +146,22 @@ ostream &operator<<(ostream &os, const viscousWall &bc) { return os; } +void periodic::Print(ostream &os) const { + os << "periodic(startTag=" << this->StartTag() << "; endTag=" << this->EndTag(); + if (this->IsTranslation()) { + os << "; translation=[" << this->Translation() << "]"; + } else if (this->IsRotation()) { + os << "; axis=[" << this->Axis() << "]; point=[" << this->Point() + << "]; rotation=" << this->Rotation(); + } + os << ")"; +} + +ostream &operator<<(ostream &os, const periodic &bc) { + bc.Print(os); + return os; +} + // function to trim leading and trailing whitespace from a string, and also // remove data after a comment @@ -179,8 +199,8 @@ vector Tokenize(string str, const string &delimiter, auto reachedMax = false; auto pos = str.find(delimiter); while (pos != string::npos && !reachedMax) { - auto token = str.substr(0, pos); - tokens.push_back(Trim(token)); + auto token = Trim(str.substr(0, pos)); + if (!token.empty()) {tokens.push_back(token);} // treat consecutive delimiters as single delimiter auto end = str.find_first_not_of(delimiter, pos); str.erase(0, end); @@ -189,7 +209,8 @@ vector Tokenize(string str, const string &delimiter, } pos = str.find(delimiter); } - tokens.push_back(Trim(str)); + auto token = Trim(str); + if (!token.empty()) {tokens.push_back(token);} return tokens; } @@ -295,6 +316,16 @@ icState::icState(string &str, const string name) { } } +void icState::Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) { + if (!this->IsNondimensional()) { + velocity_ /= aRef; + density_ /= rRef; + pressure_ /= rRef * aRef * aRef; + this->SetNondimensional(true); + } +} + // construct stagnation inlet from string stagnationInlet::stagnationInlet(string &str) { const auto start = str.find("(") + 1; @@ -334,7 +365,7 @@ stagnationInlet::stagnationInlet(string &str) { t0_ = stod(RemoveTrailing(param[1], ",")); t0Count++; } else if (param[0] == "direction") { - direction_ = ReadVector(RemoveTrailing(param[1], ",")); + direction_ = ReadVector(RemoveTrailing(param[1], ",")).Normalize(); directionCount++; } else if (param[0] == "turbulenceIntensity") { this->SetSpecifiedTurbulence(); @@ -370,6 +401,17 @@ stagnationInlet::stagnationInlet(string &str) { } } +void stagnationInlet::Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, + const double &aRef) { + if (!this->IsNondimensional()) { + direction_.Normalize(); + p0_ /= rRef * aRef * aRef; + t0_ /= tRef; + this->SetNondimensional(true); + } +} + // construct pressureOutlet from string pressureOutlet::pressureOutlet(string &str, const string name) { const auto start = str.find("(") + 1; @@ -420,6 +462,14 @@ pressureOutlet::pressureOutlet(string &str, const string name) { } } +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; @@ -491,6 +541,15 @@ subsonicInflow::subsonicInflow(string &str) { } } +void subsonicInflow::Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) { + if (!this->IsNondimensional()) { + velocity_ /= aRef; + density_ /= rRef; + this->SetNondimensional(true); + } +} + // construct viscousWall from string viscousWall::viscousWall(string &str) { const auto start = str.find("(") + 1; @@ -513,6 +572,9 @@ viscousWall::viscousWall(string &str) { auto velocityCount = 0; auto temperatureCount = 0; auto heatFluxCount = 0; + auto wallTreatmentCount = 0; + auto vonKarmenCount = 0; + auto wallConstantCount = 0; for (auto &token : tokens) { auto param = Tokenize(token, "="); @@ -532,6 +594,15 @@ viscousWall::viscousWall(string &str) { specifiedHeatFlux_ = true; heatFlux_ = stod(RemoveTrailing(param[1], ",")); heatFluxCount++; + } else if (param[0] == "vonKarmen") { + vonKarmen_ = stod(RemoveTrailing(param[1], ",")); + vonKarmenCount++; + } else if (param[0] == "wallConstant") { + wallConstant_ = stod(RemoveTrailing(param[1], ",")); + wallConstantCount++; + } else if (param[0] == "wallTreatment") { + wallTreatment_ = RemoveTrailing(param[1], ","); + wallTreatmentCount++; } else if (param[0] == "tag") { this->SetTag(stoi(RemoveTrailing(param[1], ","))); tagCount++; @@ -550,9 +621,11 @@ viscousWall::viscousWall(string &str) { exit(EXIT_FAILURE); } // optional variables - if (velocityCount > 1 || temperatureCount > 1 || heatFluxCount > 1) { - cerr << "ERROR. For viscousWall, velocity, heatFlux, and temperature can " - << "only be specified once." << endl; + if (velocityCount > 1 || temperatureCount > 1 || heatFluxCount > 1 || + wallTreatmentCount > 1 || vonKarmenCount > 1 || wallConstantCount > 1) { + cerr << "ERROR. For viscousWall, velocity, heatFlux, temperature, " + << "wallTreatment, vonKarmen, and wallConstant can only be specified " + << "once." << endl; exit(EXIT_FAILURE); } if (specifiedHeatFlux_ && specifiedTemperature_) { @@ -560,6 +633,133 @@ viscousWall::viscousWall(string &str) { << endl; exit(EXIT_FAILURE); } + if (wallTreatment_ != "lowRe" && wallTreatment_ != "wallLaw") { + cerr << "ERROR. wallTreatment " << wallTreatment_ << " is not recognized!" + << endl; + cerr << "Choose lowRe or wallLaw" << endl; + exit(EXIT_FAILURE); + } +} + +void viscousWall::Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) { + if (!this->IsNondimensional()) { + velocity_ /= aRef; + temperature_ /= tRef; + heatFlux_ /= pow(aRef / lRef, 3.0); + this->SetNondimensional(true); + } +} + +// construct periodic from string +periodic::periodic(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 != "periodic") { + 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 startTagCount = 0; + auto endTagCount = 0; + auto translationCount = 0; + auto axisCount = 0; + auto pointCount = 0; + auto rotationCount = 0; + auto specifiedTranslation = false; + auto specifiedAxis = false; + auto specifiedPoint = false; + auto specifiedRotation = false; + + for (auto &token : tokens) { + auto param = Tokenize(token, "="); + if (param.size() != 2) { + cerr << "ERROR. Problem with state condition parameter " << token << endl; + exit(EXIT_FAILURE); + } + + if (param[0] == "translation") { + translation_ = ReadVector(RemoveTrailing(param[1], ",")); + specifiedTranslation = true; + translationCount++; + } else if (param[0] == "axis") { + axis_ = ReadVector(RemoveTrailing(param[1], ",")).Normalize(); + specifiedAxis = true; + axisCount++; + } else if (param[0] == "point") { + point_ = ReadVector(RemoveTrailing(param[1], ",")); + specifiedPoint = true; + pointCount++; + } else if (param[0] == "rotation") { + rotation_ = stod(RemoveTrailing(param[1], ",")); + specifiedRotation = true; + rotationCount++; + } else if (param[0] == "startTag") { + this->SetTag(stoi(RemoveTrailing(param[1], ","))); + startTagCount++; + } else if (param[0] == "endTag") { + endTag_ = stoi(RemoveTrailing(param[1], ",")); + endTagCount++; + } else { + cerr << "ERROR. periodic specifier " << param[0] + << " is not recognized!" << endl; + exit(EXIT_FAILURE); + } + } + + // sanity checks + // required variables + if (startTagCount != 1 || endTagCount != 1) { + cerr << "ERROR. For periodic startTag and endTag must be specified, and " + << "only specified once." << endl; + exit(EXIT_FAILURE); + } + if (this->StartTag() == this->EndTag()) { + cerr << "ERROR. For periodic startTag and endTag must be unique." << endl; + exit(EXIT_FAILURE); + } + // optional variables + if (translationCount > 1 || axisCount > 1 || rotationCount > 1 || + pointCount > 1) { + cerr << "ERROR. For periodic, translation, axis, rotation, and point can " + << "only be specified once." << endl; + exit(EXIT_FAILURE); + } + if (specifiedTranslation && + (specifiedAxis || specifiedRotation || specifiedPoint)) { + cerr << "ERROR. For periodic can only specify translation OR rotation." + << endl; + exit(EXIT_FAILURE); + } + if ((specifiedAxis && !(specifiedRotation && specifiedPoint)) || + (specifiedPoint && !(specifiedRotation && specifiedAxis)) || + (specifiedRotation && !(specifiedAxis && specifiedPoint))) { + cerr << "ERROR. For periodic rotation must specify axis, point, & rotation." + << endl; + exit(EXIT_FAILURE); + } +} + +void periodic::Nondimensionalize(const double &rRef, const double &tRef, + const double &lRef, const double &aRef) { + if (!this->IsNondimensional()) { + if (this->IsTranslation()) { + translation_ /= lRef; + } else { + axis_.Normalize(); + } + point_ /= lRef; + this->SetNondimensional(true); + } } void CheckICTags(const vector &ics, const int &tag) { @@ -635,23 +835,25 @@ auto FindBCPosition(const string &str, const vector &names, return pos; } -void AddBCToList(const string &type, vector> &bcList, +void AddBCToList(const string &type, vector> &bcList, string &list) { - unique_ptr bc(nullptr); + shared_ptr bc(nullptr); if (type == "characteristic") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "stagnationInlet") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "pressureOutlet") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "subsonicInflow") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "subsonicOutflow") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "supersonicInflow") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; } else if (type == "viscousWall") { - bc = unique_ptr{std::make_unique(list)}; + bc = shared_ptr{std::make_shared(list)}; + } else if (type == "periodic") { + bc = shared_ptr{std::make_shared(list)}; } else { cerr << "ERROR. BC state " << type << " is not recognized!" << endl; exit(EXIT_FAILURE); @@ -669,10 +871,11 @@ void AddBCToList(const string &type, vector> &bcList, } // function to read boundary condition list from string -vector> ReadBCList(ifstream &inFile, string &str) { - vector> bcList; +vector> ReadBCList(ifstream &inFile, string &str) { + vector> bcList; vector bcNames {"characteristic", "stagnationInlet", "pressureOutlet", - "subsonicInflow", "subsonicOutflow", "supersonicInflow", "viscousWall"}; + "subsonicInflow", "subsonicOutflow", "supersonicInflow", "viscousWall", + "periodic"}; auto openList = false; do { auto start = openList ? 0 : str.find("<"); @@ -729,8 +932,7 @@ vector ReadStringList(ifstream &inFile, string &str) { openList = (end == string::npos) ? true : false; // test for argument on current line - // if < or > is alone on a line, should not look for icState - auto argPos = str.find_first_not_of(" \t,"); + auto argPos = str.find_first_not_of(" \t\r\n,"); if (argPos != string::npos) { // there is an argument in current line string list; if (listOpened && openList) { // list opened on current line, remains open diff --git a/src/main.cpp b/src/main.cpp index 26da0e3..adaaa96 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -97,71 +97,75 @@ int main(int argc, char *argv[]) { BroadcastString(restartFile); auto totalCells = 0.0; - input inputVars(inputFile, restartFile); + input inp(inputFile, restartFile); decomposition decomp; auto numProcBlock = 0; // Parse input file - inputVars.ReadInput(rank); + inp.ReadInput(rank); // Get equation of state - const idealGas eos(inputVars.Gamma(), inputVars.R()); + const idealGas eos(inp.Gamma(), inp.R()); // Initialize sutherland's law for viscosity - const sutherland suth(inputVars.TRef(), inputVars.RRef(), inputVars.LRef(), - inputVars.PRef(), inputVars.VelRef(), eos); + const sutherland suth(inp.TRef(), inp.RRef(), inp.LRef(), inp.PRef(), + inp.VelRef(), eos); - // Get reference speed of sound - const auto aRef = inputVars.ARef(eos); + // Nondimensionalize BC and IC state data + inp.NondimensionalizeStateData(eos); // Get turbulence model - const auto turb = inputVars.AssignTurbulenceModel(); + const auto turb = inp.AssignTurbulenceModel(); vector mesh; - vector connections; + vector connections; vector stateBlocks; vector> viscFaces; genArray residL2First(0.0); // l2 norm residuals to normalize by if (rank == ROOTP) { - cout << "Number of equations: " << inputVars.NumEquations() << endl << endl; + cout << "Number of equations: " << inp.NumEquations() << endl << endl; // Read grid - mesh = ReadP3dGrid(inputVars.GridName(), inputVars.LRef(), totalCells); + mesh = ReadP3dGrid(inp.GridName(), inp.LRef(), totalCells); + vector> gridSizes(mesh.size()); + for (auto ii = 0U; ii < mesh.size(); ++ii) { + gridSizes[ii] = {mesh[ii].NumCellsI(), mesh[ii].NumCellsJ(), + mesh[ii].NumCellsK()}; + } // Get BCs for blocks - auto bcs = inputVars.AllBC(); + auto bcs = inp.AllBC(); // Decompose grid - if (inputVars.DecompMethod() == "manual") { + if (inp.DecompMethod() == "manual") { decomp = ManualDecomposition(mesh, bcs, numProcs); - } else if (inputVars.DecompMethod() == "cubic") { + } else if (inp.DecompMethod() == "cubic") { decomp = CubicDecomposition(mesh, bcs, numProcs); } else { - cerr << "ERROR: Domain decomposition method " << inputVars.DecompMethod() + cerr << "ERROR: Domain decomposition method " << inp.DecompMethod() << " is not recognized!" << endl; exit(EXIT_FAILURE); } - // Get interblock BCs - connections = GetInterblockBCs(bcs, mesh, decomp); + // Get connection BCs + connections = GetConnectionBCs(bcs, mesh, decomp, inp); // Initialize the whole mesh with ICs and assign ghost cells geometry stateBlocks.resize(mesh.size()); for (auto ll = 0U; ll < mesh.size(); ll++) { - stateBlocks[ll] = procBlock(aRef, mesh[ll], decomp.ParentBlock(ll), - bcs[ll], ll, decomp.Rank(ll), - decomp.LocalPosition(ll), inputVars, eos, - suth); + stateBlocks[ll] = procBlock(mesh[ll], decomp.ParentBlock(ll), bcs[ll], ll, + decomp.Rank(ll), decomp.LocalPosition(ll), + inp, eos, suth, turb); stateBlocks[ll].AssignGhostCellsGeom(); } // if restart, get data from restart file - if (inputVars.IsRestart()) { - ReadRestart(stateBlocks, restartFile, inputVars, eos, suth, turb, - residL2First); + if (inp.IsRestart()) { + ReadRestart(stateBlocks, restartFile, decomp, inp, eos, suth, turb, + residL2First, gridSizes); } - // Swap geometry for interblock BCs + // Swap geometry for connection BCs for (auto &conn : connections) { SwapGeomSlice(conn, stateBlocks[conn.BlockFirst()], stateBlocks[conn.BlockSecond()]); @@ -180,28 +184,28 @@ int main(int argc, char *argv[]) { // Set MPI datatypes MPI_Datatype MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_interblock, MPI_DOUBLE_5INT, MPI_vec3dMag, MPI_uncoupledScalar, - MPI_tensorDouble; + MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, MPI_uncoupledScalar, + MPI_tensorDouble, MPI_wallData; SetDataTypesMPI(MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_interblock, MPI_DOUBLE_5INT, MPI_vec3dMag, - MPI_uncoupledScalar, MPI_tensorDouble); + MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, + MPI_uncoupledScalar, MPI_tensorDouble, MPI_wallData); // 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_cellData, MPI_vec3d, MPI_vec3dMag, + MPI_wallData, inp); // Update auxillary variables (temperature, viscosity, etc), cell widths - for (auto ll = 0U; ll < localStateBlocks.size(); ll++) { - localStateBlocks[ll].UpdateAuxillaryVariables(eos, suth, false); - localStateBlocks[ll].UpdateUnlimTurbEddyVisc(turb, false); - localStateBlocks[ll].CalcCellWidths(); + for (auto &block : localStateBlocks) { + block.UpdateAuxillaryVariables(eos, suth, false); + block.CalcCellWidths(); } // Send connections to all processors - SendConnections(connections, MPI_interblock); + SendConnections(connections, MPI_connection); // Broadcast viscous face centers to all processors BroadcastViscFaces(MPI_vec3d, viscFaces); @@ -233,6 +237,7 @@ int main(int argc, char *argv[]) { if (tree.Size() > 0) { CalcWallDistance(localStateBlocks, tree); + SwapWallDist(localStateBlocks, connections, rank, inp.NumberGhostLayers()); } MPI_Barrier(MPI_COMM_WORLD); @@ -246,21 +251,22 @@ int main(int argc, char *argv[]) { //----------------------------------------------------------------------- // Allocate array for flux jacobian vector> mainDiagonal(numProcBlock); - if (inputVars.IsImplicit()) { - ResizeArrays(localStateBlocks, inputVars, mainDiagonal); + 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_uncoupledScalar, MPI_vec3d, MPI_tensorDouble, MPI_wallData, + inp); ofstream resFile; if (rank == ROOTP) { // Open residual file - if (inputVars.IsRestart()) { - resFile.open(inputVars.SimNameRoot() + ".resid", ios::app); + if (inp.IsRestart()) { + resFile.open(inp.SimNameRoot() + ".resid", ios::app); } else { - resFile.open(inputVars.SimNameRoot() + ".resid", ios::out); + resFile.open(inp.SimNameRoot() + ".resid", ios::out); } if (resFile.fail()) { cerr << "ERROR: Could not open residual file!" << endl; @@ -268,62 +274,61 @@ int main(int argc, char *argv[]) { } // Write out cell centers grid file - WriteCellCenter(inputVars.GridName(), stateBlocks, decomp, inputVars.LRef()); + WriteCellCenter(inp.GridName(), stateBlocks, decomp, inp); // Write out initial results - WriteFun(stateBlocks, eos, suth, inputVars.IterationStart(), decomp, - inputVars, turb); - WriteMeta(inputVars, inputVars.IterationStart()); + WriteFun(stateBlocks, eos, suth, inp.IterationStart(), decomp, + inp, turb); + WriteMeta(inp, inp.IterationStart()); } // ---------------------------------------------------------------------- // ----------------------- Start Main Loop ------------------------------ // ---------------------------------------------------------------------- // loop over time - for (auto nn = 0; nn < inputVars.Iterations(); nn++) { + for (auto nn = 0; nn < inp.Iterations(); nn++) { MPI_Barrier(MPI_COMM_WORLD); // Calculate cfl number - inputVars.CalcCFL(nn); + inp.CalcCFL(nn); // Store time-n solution, for time integration methods that require it - if (inputVars.IsImplicit() || inputVars.TimeIntegration() == "rk4") { + if (inp.NeedToStoreTimeN()) { AssignSolToTimeN(localStateBlocks, eos); - if (!inputVars.IsRestart() && nn == 0) { + if (!inp.IsRestart() && inp.IsMultilevelInTime() && nn == 0) { AssignSolToTimeNm1(localStateBlocks); } } // loop over nonlinear iterations - for (auto mm = 0; mm < inputVars.NonlinearIterations(); mm++) { + for (auto mm = 0; mm < inp.NonlinearIterations(); mm++) { // Get boundary conditions for all blocks - GetBoundaryConditions(localStateBlocks, inputVars, eos, suth, turb, + GetBoundaryConditions(localStateBlocks, inp, eos, suth, turb, connections, rank, MPI_cellData); // Calculate residual (RHS) - CalcResidual(localStateBlocks, mainDiagonal, suth, eos, inputVars, + CalcResidual(localStateBlocks, mainDiagonal, suth, eos, inp, turb, connections, rank, MPI_tensorDouble, MPI_vec3d); // Calculate time step - CalcTimeStep(localStateBlocks, inputVars, aRef); + CalcTimeStep(localStateBlocks, inp); // Initialize residual variables genArray residL2(0.0); // l2 norm residuals resid residLinf; // linf residuals auto matrixResid = 0.0; - if (inputVars.IsImplicit()) { - matrixResid = ImplicitUpdate(localStateBlocks, mainDiagonal, - inputVars, eos, aRef, suth, turb, mm, - residL2, residLinf, connections, rank, - MPI_cellData); + if (inp.IsImplicit()) { + matrixResid = ImplicitUpdate(localStateBlocks, mainDiagonal, inp, eos, + suth, turb, mm, residL2, residLinf, + connections, rank, MPI_cellData); } else { // explicit time integration - ExplicitUpdate(localStateBlocks, inputVars, eos, aRef, suth, turb, mm, - residL2, residLinf); + ExplicitUpdate(localStateBlocks, inp, eos, suth, turb, mm, residL2, + residLinf); } // ---------------------------------------------------------------------- // Get residuals from all processors - residL2.GlobalReduceMPI(rank, inputVars.NumEquations()); + residL2.GlobalReduceMPI(rank, inp.NumEquations()); residLinf.GlobalReduceMPI(rank, MPI_DOUBLE_5INT, MPI_MAX_LINF); // Get matrix residuals from all processors @@ -340,34 +345,35 @@ int main(int argc, char *argv[]) { residL2.SquareRoot(); // Finish calculation of matrix residual - matrixResid = sqrt(matrixResid/(totalCells * inputVars.NumEquations())); + matrixResid = sqrt(matrixResid/(totalCells * inp.NumEquations())); // Print out run information - WriteResiduals(inputVars, residL2First, residL2, residLinf, matrixResid, - nn + inputVars.IterationStart(), mm, resFile); + WriteResiduals(inp, residL2First, residL2, residLinf, matrixResid, + nn + inp.IterationStart(), mm, resFile); } } // loop for nonlinear iterations --------------------------------------- // write out function file - if (inputVars.WriteOutput(nn) || inputVars.WriteRestart(nn)) { + if (inp.WriteOutput(nn) || inp.WriteRestart(nn)) { // Send/recv solutions GetProcBlocks(stateBlocks, localStateBlocks, rank, MPI_cellData, - MPI_uncoupledScalar, MPI_vec3d, MPI_tensorDouble); + MPI_uncoupledScalar, MPI_vec3d, MPI_tensorDouble, + MPI_wallData, inp); - if (rank == ROOTP && inputVars.WriteOutput(nn)) { + if (rank == ROOTP && inp.WriteOutput(nn)) { cout << "writing out function file at iteration " - << nn + inputVars.IterationStart()<< endl; + << nn + inp.IterationStart()<< endl; // Write out function file - WriteFun(stateBlocks, eos, suth, (nn + inputVars.IterationStart() + 1), - decomp, inputVars, turb); - WriteMeta(inputVars, (nn + inputVars.IterationStart() + 1)); + WriteFun(stateBlocks, eos, suth, (nn + inp.IterationStart() + 1), + decomp, inp, turb); + WriteMeta(inp, (nn + inp.IterationStart() + 1)); } - if (rank == ROOTP && inputVars.WriteRestart(nn)) { + if (rank == ROOTP && inp.WriteRestart(nn)) { cout << "writing out restart file at iteration " - << nn + inputVars.IterationStart()<< endl; + << nn + inp.IterationStart()<< endl; // Write out restart file - WriteRestart(stateBlocks, eos, suth, (nn + inputVars.IterationStart() + 1), - decomp, inputVars, residL2First); + WriteRestart(stateBlocks, eos, suth, (nn + inp.IterationStart() + 1), + decomp, inp, residL2First); } } } // loop for time step ----------------------------------------------------- @@ -386,8 +392,8 @@ int main(int argc, char *argv[]) { // Free datatypes previously created FreeDataTypesMPI(MPI_vec3d, MPI_cellData, MPI_procBlockInts, - MPI_interblock, MPI_DOUBLE_5INT, MPI_vec3dMag, - MPI_uncoupledScalar, MPI_tensorDouble); + MPI_connection, MPI_DOUBLE_5INT, MPI_vec3dMag, + MPI_uncoupledScalar, MPI_tensorDouble, MPI_wallData); MPI_Finalize(); diff --git a/src/output.cpp b/src/output.cpp index fe170c7..0923de2 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -32,9 +32,10 @@ #include "procBlock.hpp" // procBlock #include "inviscidFlux.hpp" // inviscidFlux #include "input.hpp" // inputVars -#include "boundaryConditions.hpp" // decomposition +#include "parallel.hpp" // decomposition #include "resid.hpp" // resid #include "genArray.hpp" // genArray +#include "utility.hpp" using std::cout; using std::endl; @@ -54,7 +55,7 @@ using std::unique_ptr; // function declarations // function to write out cell centers of grid in plot3d format void WriteCellCenter(const string &gridName, const vector &vars, - const decomposition &decomp, const double &LRef) { + const decomposition &decomp, const input &inp) { // recombine procblocks into original configuration auto recombVars = Recombine(vars, decomp); @@ -74,16 +75,77 @@ void WriteCellCenter(const string &gridName, const vector &vars, WriteBlockDims(outFile, recombVars); // write out x, y, z coordinates of cell centers - for (auto ll = 0U; ll < recombVars.size(); ll++) { // loop over all blocks + for (auto &blk : recombVars) { // loop over all blocks for (auto nn = 0; nn < 3; nn++) { // loop over dimensions (3) - for (auto kk = recombVars[ll].StartK(); kk < recombVars[ll].EndK(); - kk++) { - for (auto jj = recombVars[ll].StartJ(); jj < recombVars[ll].EndJ(); - jj++) { - for (auto ii = recombVars[ll].StartI(); ii < recombVars[ll].EndI(); - ii++) { + for (auto kk = blk.StartK(); kk < blk.EndK(); kk++) { + for (auto jj = blk.StartJ(); jj < blk.EndJ(); jj++) { + for (auto ii = blk.StartI(); ii < blk.EndI(); ii++) { // get the cell center coordinates (dimensionalized) - auto dumVec = recombVars[ll].Center(ii, jj, kk) * LRef; + auto dumVec = blk.Center(ii, jj, kk) * inp.LRef(); + + // for a given block, first write out all x coordinates, then all y + // coordinates, then all z coordinates + auto dumDouble = dumVec[nn]; + // write to file + outFile.write(reinterpret_cast(&dumDouble), + sizeof(dumDouble)); + } + } + } + } + } + // close output file + outFile.close(); + + if (inp.NumWallVarsOutput() > 0) { + WriteWallFaceCenter(gridName, recombVars, inp.LRef()); + } +} + +// function to write out wall face centers of grid in plot3d format +void WriteWallFaceCenter(const string &gridName, const vector &vars, + const double &LRef) { + // open binary output file + const string fEnd = "_wall_center"; + const string fPostfix = ".xyz"; + const auto writeName = gridName + fEnd + fPostfix; + ofstream outFile(writeName, ios::out | ios::binary); + + // check to see if file opened correctly + if (outFile.fail()) { + cerr << "ERROR: Grid file " << writeName << " did not open correctly!!!" + << endl; + exit(EXIT_FAILURE); + } + + // get wall face centers + auto numWallSurfs = 0; + for (auto &var : vars) { + numWallSurfs += var.BC().NumViscousSurfaces(); + } + vector>> wallCenters; + wallCenters.reserve(numWallSurfs); + + for (auto &var : vars) { + const auto bc = var.BC(); + for (auto jj = 0; jj < bc.NumSurfaces(); ++jj) { + if (bc.GetBCTypes(jj) == "viscousWall") { + auto wall = var.SliceBoundaryCenters(jj); + wallCenters.push_back(wall); + } + } + } + + WriteBlockDims(outFile, wallCenters); + + // write out x, y, z coordinates of cell centers + for (auto &wBlk : wallCenters) { // loop over all blocks + for (auto nn = 0; nn < 3; nn++) { // loop over dimensions (3) + for (auto kk = wBlk.StartK(); kk < wBlk.EndK(); kk++) { + for (auto jj = wBlk.StartJ(); jj < wBlk.EndJ(); jj++) { + for (auto ii = wBlk.StartI(); ii < wBlk.EndI(); ii++) { + // get the cell center coordinates (dimensionalized) + auto dumVec = wBlk(ii, jj, kk) * LRef; // for a given block, first write out all x coordinates, then all y // coordinates, then all z coordinates @@ -101,6 +163,7 @@ void WriteCellCenter(const string &gridName, const vector &vars, outFile.close(); } + //---------------------------------------------------------------------- // function to write out variables in function file format void WriteFun(const vector &vars, const idealGas &eqnState, @@ -126,44 +189,42 @@ void WriteFun(const vector &vars, const idealGas &eqnState, WriteBlockDims(outFile, recombVars, inp.NumVarsOutput()); - // define reference speed of sound - const auto refSoS = inp.ARef(eqnState); - // write out variables - for (auto ll = 0U; ll < recombVars.size(); ll++) { // loop over all blocks + auto ll = 0; + for (auto &blk : recombVars) { // loop over all blocks // loop over the number of variables to write out for (auto &var : inp.OutputVariables()) { // write out dimensional variables -- loop over physical cells - for (auto kk = recombVars[ll].StartK(); kk < recombVars[ll].EndK(); kk++) { - for (auto jj = recombVars[ll].StartJ(); jj < recombVars[ll].EndJ(); jj++) { - for (auto ii = recombVars[ll].StartI(); ii < recombVars[ll].EndI(); ii++) { + for (auto kk = blk.StartK(); kk < blk.EndK(); kk++) { + for (auto jj = blk.StartJ(); jj < blk.EndJ(); jj++) { + for (auto ii = blk.StartI(); ii < blk.EndI(); ii++) { auto value = 0.0; if (var == "density") { - value = recombVars[ll].State(ii, jj, kk).Rho(); + value = blk.State(ii, jj, kk).Rho(); value *= inp.RRef(); } else if (var == "vel_x") { - value = recombVars[ll].State(ii, jj, kk).U(); - value *= refSoS; + value = blk.State(ii, jj, kk).U(); + value *= inp.ARef(); } else if (var == "vel_y") { - value = recombVars[ll].State(ii, jj, kk).V(); - value *= refSoS; + value = blk.State(ii, jj, kk).V(); + value *= inp.ARef(); } else if (var == "vel_z") { - value = recombVars[ll].State(ii, jj, kk).W(); - value *= refSoS; + value = blk.State(ii, jj, kk).W(); + value *= inp.ARef(); } else if (var == "pressure") { - value = recombVars[ll].State(ii, jj, kk).P(); - value *= inp.RRef() * refSoS * refSoS; + value = blk.State(ii, jj, kk).P(); + value *= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "mach") { - auto vel = recombVars[ll].State(ii, jj, kk).Velocity(); - value = vel.Mag() / recombVars[ll].State(ii, jj, kk).SoS(eqnState); + auto vel = blk.State(ii, jj, kk).Velocity(); + value = vel.Mag() / blk.State(ii, jj, kk).SoS(eqnState); } else if (var == "sos") { - value = recombVars[ll].State(ii, jj, kk).SoS(eqnState); - value *= refSoS; + value = blk.State(ii, jj, kk).SoS(eqnState); + value *= inp.ARef(); } else if (var == "dt") { - value = recombVars[ll].Dt(ii, jj, kk); - value /= refSoS * inp.LRef(); + value = blk.Dt(ii, jj, kk); + value /= inp.ARef() * inp.LRef(); } else if (var == "temperature") { - value = recombVars[ll].Temperature(ii, jj, kk); + value = blk.Temperature(ii, jj, kk); value *= inp.TRef(); } else if (var == "rank") { value = vars[SplitBlockNumber(recombVars, decomp, @@ -172,102 +233,112 @@ void WriteFun(const vector &vars, const idealGas &eqnState, value = vars[SplitBlockNumber(recombVars, decomp, ll, ii, jj, kk)].GlobalPos(); } else if (var == "viscosityRatio") { - value = recombVars[ll].IsTurbulent() ? - recombVars[ll].EddyViscosity(ii, jj, kk) / - recombVars[ll].Viscosity(ii, jj, kk) + value = blk.IsTurbulent() ? + blk.EddyViscosity(ii, jj, kk) / + blk.Viscosity(ii, jj, kk) : 0.0; + } else if (var == "turbulentViscosity") { + value = blk.EddyViscosity(ii, jj, kk); + value *= suth.MuRef(); + } else if (var == "viscosity") { + value = blk.Viscosity(ii, jj, kk); + value *= suth.MuRef(); } else if (var == "tke") { - value = recombVars[ll].State(ii, jj, kk).Tke(); - value *= refSoS * refSoS; + value = blk.State(ii, jj, kk).Tke(); + value *= inp.ARef() * inp.ARef(); } else if (var == "sdr") { - value = recombVars[ll].State(ii, jj, kk).Omega(); - value *= refSoS * refSoS * inp.RRef() / suth.MuRef(); + value = blk.State(ii, jj, kk).Omega(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / suth.MuRef(); + } else if (var == "f1") { + value = blk.F1(ii, jj, kk); + } else if (var == "f2") { + value = blk.F2(ii, jj, kk); } else if (var == "wallDistance") { - value = recombVars[ll].WallDist(ii, jj, kk); + value = blk.WallDist(ii, jj, kk); value *= inp.LRef(); } else if (var == "velGrad_ux") { - value = recombVars[ll].VelGrad(ii, jj, kk).XX(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).XX(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_vx") { - value = recombVars[ll].VelGrad(ii, jj, kk).XY(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).XY(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_wx") { - value = recombVars[ll].VelGrad(ii, jj, kk).XZ(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).XZ(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_uy") { - value = recombVars[ll].VelGrad(ii, jj, kk).YX(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).YX(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_vy") { - value = recombVars[ll].VelGrad(ii, jj, kk).YY(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).YY(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_wy") { - value = recombVars[ll].VelGrad(ii, jj, kk).YZ(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).YZ(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_uz") { - value = recombVars[ll].VelGrad(ii, jj, kk).ZX(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).ZX(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_vz") { - value = recombVars[ll].VelGrad(ii, jj, kk).ZY(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).ZY(); + value *= inp.ARef() / inp.LRef(); } else if (var == "velGrad_wz") { - value = recombVars[ll].VelGrad(ii, jj, kk).ZZ(); - value *= refSoS / inp.LRef(); + value = blk.VelGrad(ii, jj, kk).ZZ(); + value *= inp.ARef() / inp.LRef(); } else if (var == "tempGrad_x") { - value = recombVars[ll].TempGrad(ii, jj, kk).X(); + value = blk.TempGrad(ii, jj, kk).X(); value *= inp.TRef() / inp.LRef(); } else if (var == "tempGrad_y") { - value = recombVars[ll].TempGrad(ii, jj, kk).Y(); + value = blk.TempGrad(ii, jj, kk).Y(); value *= inp.TRef() / inp.LRef(); } else if (var == "tempGrad_z") { - value = recombVars[ll].TempGrad(ii, jj, kk).Z(); + value = blk.TempGrad(ii, jj, kk).Z(); value *= inp.TRef() / inp.LRef(); } else if (var == "tkeGrad_x") { - value = recombVars[ll].TkeGrad(ii, jj, kk).X(); - value *= refSoS * refSoS / inp.LRef(); + value = blk.TkeGrad(ii, jj, kk).X(); + value *= inp.ARef() * inp.ARef() / inp.LRef(); } else if (var == "tkeGrad_y") { - value = recombVars[ll].TkeGrad(ii, jj, kk).Y(); - value *= refSoS * refSoS / inp.LRef(); + value = blk.TkeGrad(ii, jj, kk).Y(); + value *= inp.ARef() * inp.ARef() / inp.LRef(); } else if (var == "tkeGrad_z") { - value = recombVars[ll].TkeGrad(ii, jj, kk).Z(); - value *= refSoS * refSoS / inp.LRef(); + value = blk.TkeGrad(ii, jj, kk).Z(); + value *= inp.ARef() * inp.ARef() / inp.LRef(); } else if (var == "omegaGrad_x") { - value = recombVars[ll].OmegaGrad(ii, jj, kk).X(); - value *= refSoS * refSoS * inp.RRef() / + value = blk.OmegaGrad(ii, jj, kk).X(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / (suth.MuRef() * inp.LRef()); } else if (var == "omegaGrad_y") { - value = recombVars[ll].OmegaGrad(ii, jj, kk).Y(); - value *= refSoS * refSoS * inp.RRef() / + value = blk.OmegaGrad(ii, jj, kk).Y(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / (suth.MuRef() * inp.LRef()); } else if (var == "omegaGrad_z") { - value = recombVars[ll].OmegaGrad(ii, jj, kk).Z(); - value *= refSoS * refSoS * inp.RRef() / + value = blk.OmegaGrad(ii, jj, kk).Z(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / (suth.MuRef() * inp.LRef()); } else if (var == "resid_mass") { - value = recombVars[ll].Residual(ii, jj, kk, 0); - value *= inp.RRef() * refSoS * inp.LRef() * inp.LRef(); + value = blk.Residual(ii, jj, kk, 0); + value *= inp.RRef() * inp.ARef() * inp.LRef() * inp.LRef(); } else if (var == "resid_mom_x") { - value = recombVars[ll].Residual(ii, jj, kk, 1); - value *= inp.RRef() * refSoS * refSoS * inp.LRef() * + value = blk.Residual(ii, jj, kk, 1); + value *= inp.RRef() * inp.ARef() * inp.ARef() * inp.LRef() * inp.LRef(); } else if (var == "resid_mom_y") { - value = recombVars[ll].Residual(ii, jj, kk, 2); - value *= inp.RRef() * refSoS * refSoS * inp.LRef() * + value = blk.Residual(ii, jj, kk, 2); + value *= inp.RRef() * inp.ARef() * inp.ARef() * inp.LRef() * inp.LRef(); } else if (var == "resid_mom_z") { - value = recombVars[ll].Residual(ii, jj, kk, 3); - value *= inp.RRef() * refSoS * refSoS * inp.LRef() * + value = blk.Residual(ii, jj, kk, 3); + value *= inp.RRef() * inp.ARef() * inp.ARef() * inp.LRef() * inp.LRef(); } else if (var == "resid_energy") { - value = recombVars[ll].Residual(ii, jj, kk, 4); - value *= inp.RRef() * pow(refSoS, 3.0) * inp.LRef() * + value = blk.Residual(ii, jj, kk, 4); + value *= inp.RRef() * pow(inp.ARef(), 3.0) * inp.LRef() * inp.LRef(); } else if (var == "resid_tke") { - value = recombVars[ll].Residual(ii, jj, kk, 5); - value *= inp.RRef() * pow(refSoS, 3.0) * inp.LRef() * + value = blk.Residual(ii, jj, kk, 5); + value *= inp.RRef() * pow(inp.ARef(), 3.0) * inp.LRef() * inp.LRef(); } else if (var == "resid_sdr") { - value = recombVars[ll].Residual(ii, jj, kk, 6); - value *= inp.RRef() * inp.RRef() * pow(refSoS, 4.0) * + value = blk.Residual(ii, jj, kk, 6); + value *= inp.RRef() * inp.RRef() * pow(inp.ARef(), 4.0) * inp.LRef() * inp.LRef() / suth.MuRef(); } else { cerr << "ERROR: Variable " << var @@ -280,13 +351,119 @@ void WriteFun(const vector &vars, const idealGas &eqnState, } } } + ll++; } // close plot3d function file outFile.close(); + + if (inp.NumWallVarsOutput() > 0) { + WriteWallFun(recombVars, eqnState, suth, solIter, inp, turb); + } } // function to write out variables in function file format +void WriteWallFun(const vector &vars, const idealGas &eos, + const sutherland &suth, const int &solIter, const input &inp, + const unique_ptr &turb) { + // open binary plot3d function file + const string fEnd = "_wall_center"; + const string fPostfix = ".fun"; + const auto writeName = + inp.SimNameRoot() + "_" + to_string(solIter) + fEnd + fPostfix; + ofstream outFile(writeName, ios::out | ios::binary); + + // check to see if file opened correctly + if (outFile.fail()) { + cerr << "ERROR: Function file " << writeName << " did not open correctly!!!" + << endl; + exit(EXIT_FAILURE); + } + + // get wall surfaces to write out dimensions + auto numWallSurfs = 0; + for (auto &blk : vars) { + numWallSurfs += blk.WallDataSize(); + } + vector wallSurfs; + wallSurfs.reserve(numWallSurfs); + for (auto &blk : vars) { + for (auto jj = 0; jj < blk.WallDataSize(); ++jj) { + const auto surf = blk.WallSurface(jj); + wallSurfs.push_back(surf); + } + } + + WriteBlockDims(outFile, wallSurfs, inp.NumWallVarsOutput()); + + // write out variables + for (auto &blk : vars) { // loop over all blocks + // loop over the number of variables to write out + for (auto &var : inp.WallOutputVariables()) { + // loop over wall boundaries + for (auto ll = 0; ll < blk.WallDataSize(); ++ll) { + const auto surf = blk.WallSurface(ll); + // write out dimensional variables -- loop over physical cells + for (auto kk = surf.RangeK().Start(); kk < surf.RangeK().End(); kk++) { + for (auto jj = surf.RangeJ().Start(); jj < surf.RangeJ().End(); + jj++) { + for (auto ii = surf.RangeI().Start(); ii < surf.RangeI().End(); + ii++) { + // now calculate wall variables + auto value = 0.0; + if (var == "yplus") { + value = blk.WallYplus(ll, ii, jj, kk); + } else if (var == "shearStress") { + value = blk.WallShearStress(ll, ii, jj, kk).Mag(); + value *= suth.InvNondimScaling() * suth.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 *= suth.MuRef() * inp.TRef() / inp.LRef(); + } else if (var == "frictionVelocity") { + value = blk.WallFrictionVelocity(ll, ii, jj, kk); + value *= inp.ARef(); + } else if (var == "density") { + value = blk.WallDensity(ll, ii, jj, kk); + value *= inp.RRef(); + } else if (var == "pressure") { + value = blk.WallPressure(ll, ii, jj, kk, 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 *= suth.MuRef() * suth.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() / suth.MuRef(); + } else { + cerr << "ERROR: Variable " << var + << " to write to wall function file is not defined!" + << endl; + exit(EXIT_FAILURE); + } + + outFile.write(reinterpret_cast(&value), sizeof(value)); + } + } + } + } + } + } + + // close plot3d function file + outFile.close(); +} + +// function to write out restart variables void WriteRestart(const vector &splitVars, const idealGas &eqnState, const sutherland &suth, const int &solIter, const decomposition &decomp, const input &inp, @@ -324,46 +501,43 @@ void WriteRestart(const vector &splitVars, const idealGas &eqnState, // variables to write to restart file vector restartVars = {"density", "vel_x", "vel_y", "vel_z", "pressure"}; - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { restartVars.push_back("tke"); restartVars.push_back("sdr"); } WriteBlockDims(outFile, vars, restartVars.size()); - // define reference speed of sound - const auto refSoS = inp.ARef(eqnState); - // write out variables - for (auto ll = 0U; ll < vars.size(); ll++) { // loop over all blocks + for (auto &blk : vars) { // loop over all blocks // write out dimensional variables -- loop over physical cells - for (auto kk = vars[ll].StartK(); kk < vars[ll].EndK(); kk++) { - for (auto jj = vars[ll].StartJ(); jj < vars[ll].EndJ(); jj++) { - for (auto ii = vars[ll].StartI(); ii < vars[ll].EndI(); ii++) { + for (auto kk = blk.StartK(); kk < blk.EndK(); kk++) { + for (auto jj = blk.StartJ(); jj < blk.EndJ(); jj++) { + for (auto ii = blk.StartI(); ii < blk.EndI(); ii++) { // loop over the number of variables to write out for (auto &var : restartVars) { auto value = 0.0; if (var == "density") { - value = vars[ll].State(ii, jj, kk).Rho(); + value = blk.State(ii, jj, kk).Rho(); value *= inp.RRef(); } else if (var == "vel_x") { - value = vars[ll].State(ii, jj, kk).U(); - value *= refSoS; + value = blk.State(ii, jj, kk).U(); + value *= inp.ARef(); } else if (var == "vel_y") { - value = vars[ll].State(ii, jj, kk).V(); - value *= refSoS; + value = blk.State(ii, jj, kk).V(); + value *= inp.ARef(); } else if (var == "vel_z") { - value = vars[ll].State(ii, jj, kk).W(); - value *= refSoS; + value = blk.State(ii, jj, kk).W(); + value *= inp.ARef(); } else if (var == "pressure") { - value = vars[ll].State(ii, jj, kk).P(); - value *= inp.RRef() * refSoS * refSoS; + value = blk.State(ii, jj, kk).P(); + value *= inp.RRef() * inp.ARef() * inp.ARef(); } else if (var == "tke") { - value = vars[ll].State(ii, jj, kk).Tke(); - value *= refSoS * refSoS; + value = blk.State(ii, jj, kk).Tke(); + value *= inp.ARef() * inp.ARef(); } else if (var == "sdr") { - value = vars[ll].State(ii, jj, kk).Omega(); - value *= refSoS * refSoS * inp.RRef() / suth.MuRef(); + value = blk.State(ii, jj, kk).Omega(); + value *= inp.ARef() * inp.ARef() * inp.RRef() / suth.MuRef(); } else { cerr << "ERROR: Variable " << var << " to write to restart file is not defined!" << endl; @@ -380,35 +554,35 @@ void WriteRestart(const vector &splitVars, const idealGas &eqnState, // write out 2nd solution if (numSols == 2) { // these variables are conserved variables - for (auto ll = 0U; ll < vars.size(); ll++) { // loop over all blocks + for (auto &blk : vars) { // loop over all blocks // write out dimensional variables -- loop over physical cells - for (auto kk = vars[ll].StartK(); kk < vars[ll].EndK(); kk++) { - for (auto jj = vars[ll].StartJ(); jj < vars[ll].EndJ(); jj++) { - for (auto ii = vars[ll].StartI(); ii < vars[ll].EndI(); ii++) { + for (auto kk = blk.StartK(); kk < blk.EndK(); kk++) { + for (auto jj = blk.StartJ(); jj < blk.EndJ(); jj++) { + for (auto ii = blk.StartI(); ii < blk.EndI(); ii++) { // loop over the number of variables to write out for (auto &var : restartVars) { auto value = 0.0; if (var == "density") { - value = vars[ll].ConsVarsNm1(ii, jj, kk)[0]; + value = blk.ConsVarsNm1(ii, jj, kk)[0]; value *= inp.RRef(); } else if (var == "vel_x") { // conserved var is rho-u - value = vars[ll].ConsVarsNm1(ii, jj, kk)[1]; - value *= refSoS * inp.RRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[1]; + value *= inp.ARef() * inp.RRef(); } else if (var == "vel_y") { // conserved var is rho-v - value = vars[ll].ConsVarsNm1(ii, jj, kk)[2]; - value *= refSoS * inp.RRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[2]; + value *= inp.ARef() * inp.RRef(); } else if (var == "vel_z") { // conserved var is rho-w - value = vars[ll].ConsVarsNm1(ii, jj, kk)[3]; - value *= refSoS * inp.RRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[3]; + value *= inp.ARef() * inp.RRef(); } else if (var == "pressure") { // conserved var is rho-E - value = vars[ll].ConsVarsNm1(ii, jj, kk)[4]; - value *= refSoS * refSoS * inp.RRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[4]; + value *= inp.ARef() * inp.ARef() * inp.RRef(); } else if (var == "tke") { // conserved var is rho-tke - value = vars[ll].ConsVarsNm1(ii, jj, kk)[5]; - value *= refSoS * refSoS * inp.RRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[5]; + value *= inp.ARef() * inp.ARef() * inp.RRef(); } else if (var == "sdr") { // conserved var is rho-sdr - value = vars[ll].ConsVarsNm1(ii, jj, kk)[6]; - value *= refSoS * refSoS * inp.RRef() * inp.RRef() / suth.MuRef(); + value = blk.ConsVarsNm1(ii, jj, kk)[6]; + value *= inp.ARef() * inp.ARef() * inp.RRef() * inp.RRef() / suth.MuRef(); } else { cerr << "ERROR: Variable " << var << " to write to restart file is not defined!" << endl; @@ -428,9 +602,10 @@ void WriteRestart(const vector &splitVars, const idealGas &eqnState, } void ReadRestart(vector &vars, const string &restartName, - input &inp, const idealGas &eos, const sutherland &suth, - const unique_ptr &turb, genArray &residL2First) { - // open binary plot3d grid file + const decomposition & decomp, input &inp, const idealGas &eos, + const sutherland &suth, const unique_ptr &turb, + genArray &residL2First, const vector> &gridSizes) { + // open binary restart file ifstream fName(restartName, ios::in | ios::binary); // check to see if file opened correctly @@ -468,9 +643,12 @@ void ReadRestart(vector &vars, const string &restartName, // read the number of blocks auto numBlks = 0; fName.read(reinterpret_cast(&numBlks), sizeof(numBlks)); - if (numBlks != static_cast(vars.size())) { + if (numBlks != static_cast(gridSizes.size())) { cerr << "ERROR: Number of blocks in restart file does not match grid!" << endl; + cerr << "Found " << numBlks << " blocks in restart file and " + << gridSizes.size() << " blocks in grid." << endl; + exit(EXIT_FAILURE); } // read the block sizes and check for match with grid @@ -480,8 +658,8 @@ void ReadRestart(vector &vars, const string &restartName, fName.read(reinterpret_cast(&numJ), sizeof(numJ)); fName.read(reinterpret_cast(&numK), sizeof(numK)); fName.read(reinterpret_cast(&numVars), sizeof(numVars)); - if (numI != vars[ii].NumI() || numJ != vars[ii].NumJ() || - numK != vars[ii].NumK() || numVars != numEqns) { + if (numI != gridSizes[ii].X() || numJ != gridSizes[ii].Y() || + numK != gridSizes[ii].Z() || numVars != 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; @@ -498,13 +676,43 @@ void ReadRestart(vector &vars, const string &restartName, // loop over blocks and initialize cout << "Reading solution from time n..." << endl; - for (auto &block : vars) { - block.ReadSolFromRestart(fName, inp, eos, suth, turb, restartVars); + vector> solN(numBlks); + for (auto ii = 0U; ii < solN.size(); ++ii) { + solN[ii] = ReadSolFromRestart(fName, inp, eos, suth, turb, restartVars, + gridSizes[ii].X(), gridSizes[ii].Y(), + gridSizes[ii].Z()); + } + // decompose solution + decomp.DecompArray(solN); + + // assign to procBlocks + for (auto ii = 0U; ii < solN.size(); ++ii) { + vars[ii].GetStatesFromRestart(solN[ii]); } - if (inp.IsMultilevelInTime() && numSols == 2) { - cout << "Reading solution from time n-1..." << endl; - for (auto &block : vars) { - block.ReadSolNm1FromRestart(fName, inp, eos, suth, turb, restartVars); + + if (inp.IsMultilevelInTime()) { + if (numSols == 2) { + cout << "Reading solution from time n-1..." << endl; + vector> solNm1(numBlks); + for (auto ii = 0U; ii < solNm1.size(); ++ii) { + solNm1[ii] = ReadSolNm1FromRestart(fName, inp, eos, suth, turb, + restartVars, gridSizes[ii].X(), + gridSizes[ii].Y(), gridSizes[ii].Z()); + } + // decompose solution + decomp.DecompArray(solNm1); + + // assign to procBlocks + for (auto ii = 0U; ii < solNm1.size(); ++ii) { + vars[ii].GetSolNm1FromRestart(solNm1[ii]); + } + + } else { + 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, eos); + AssignSolToTimeNm1(vars); } } @@ -513,24 +721,22 @@ void ReadRestart(vector &vars, const string &restartName, cout << "Done with restart file" << endl << endl; } - - - -void WriteBlockDims(ofstream &outFile, const vector &vars, +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 ll = 0; ll < numBlks; ll++) { - auto dumInt = vars[ll].NumI(); + for (auto &blk : vars) { + auto dumInt = blk.NumI(); outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - dumInt = vars[ll].NumJ(); + dumInt = blk.NumJ(); outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - dumInt = vars[ll].NumK(); + dumInt = blk.NumK(); outFile.write(reinterpret_cast(&dumInt), sizeof(dumInt)); - + if (numVars > 0) { outFile.write(reinterpret_cast(&numVars), sizeof(numVars)); } @@ -660,6 +866,55 @@ void WriteMeta(const input &inp, const int &iter) { // Close results file metaFile.close(); + + if (inp.NumWallVarsOutput() > 0) { + WriteWallMeta(inp, iter); + } +} + +// function to write out plot3d meta data for Paraview +void WriteWallMeta(const input &inp, const int &iter) { + // open meta file + const string fMetaPostfix = ".p3d"; + const string fEnd = "_wall_center"; + const auto metaName = inp.SimNameRoot() + fEnd + fMetaPostfix; + ofstream metaFile(metaName, ios::out); + + const auto gridName = inp.GridName() + fEnd + ".xyz"; + const auto funName = inp.SimNameRoot() + "_" + to_string(iter) + fEnd + ".fun"; + + // check to see if file opened correctly + if (metaFile.fail()) { + cerr << "ERROR: Results file " << metaName << " did not open correctly!!!" + << endl; + exit(EXIT_FAILURE); + } + + const auto outputVars = inp.WallOutputVariables(); + + // write to meta file + metaFile << "{" << endl; + metaFile << "\"auto-detect-format\" : true," << endl; + metaFile << "\"format\" : \"binary\"," << endl; + metaFile << "\"language\" : \"C\"," << endl; + metaFile << "\"filenames\" : [{ \"time\" : " << iter << ", \"xyz\" : \"" + << gridName << "\", \"function\" : \"" << funName << "\" }]," << endl; + + // Write out scalar variables + auto numVar = 0U; + metaFile << "\"function-names\" : [ "; + for (auto &var : outputVars) { + metaFile << "\"" << var << "\""; + if (numVar < outputVars.size() - 1) { + metaFile << ", "; + } + numVar++; + } + metaFile << " ]" << endl; + metaFile << "}" << endl; + + // Close results file + metaFile.close(); } @@ -697,7 +952,7 @@ void PrintHeaders(const input &inp, ostream &os) { os << std::left << setw(12) << "Res-Mass" << setw(12) << "Res-Mom-X" << setw(12) << "Res-Mom-Y" << setw(12) << "Res-Mom-Z" << setw(12) << "Res-Energy"; - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { os << std::left << setw(12) << "Res-Tke" << setw(12) << "Res-Omega"; } os << std::left << setw(8) << "Max-Eqn" << setw(8) @@ -738,7 +993,7 @@ void PrintResiduals(const input &inp, genArray &residL2First, os << std::left << setw(12) << resNormL2[0] << setw(12) << resNormL2[1] << setw(12) << resNormL2[2] << setw(12) << resNormL2[3] << setw(12) << resNormL2[4]; - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { os << std::left << setw(12) << resNormL2[5] << setw(12) << resNormL2[6]; } os.unsetf(std::ios::fixed | std::ios::scientific); @@ -840,3 +1095,104 @@ 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 idealGas &eos, + const sutherland &suth, const unique_ptr &turb, + const vector &restartVars, const int &numI, const int &numJ, + const int &numK) { + // intialize multiArray3d + multiArray3d sol(numI, numJ, numK, 0); + + // read the primative 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; + // 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(); + } else if (var == "vel_x") { + resFile.read(reinterpret_cast(&value[1]), sizeof(value[1])); + value[1] /= inp.ARef(); + } else if (var == "vel_y") { + resFile.read(reinterpret_cast(&value[2]), sizeof(value[2])); + value[2] /= inp.ARef(); + } else if (var == "vel_z") { + resFile.read(reinterpret_cast(&value[3]), sizeof(value[3])); + value[3] /= inp.ARef(); + } else if (var == "pressure") { + resFile.read(reinterpret_cast(&value[4]), sizeof(value[4])); + value[4] /= 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(); + } else if (var == "sdr") { + resFile.read(reinterpret_cast(&value[6]), sizeof(value[6])); + value[6] /= inp.ARef() * inp.ARef() * inp.RRef() / suth.MuRef(); + } else { + cerr << "ERROR: Variable " << var + << " to read from restart file is not defined!" << endl; + exit(EXIT_FAILURE); + } + } + sol(ii, jj, kk) = primVars(value, true, eos, turb); + } + } + } + return sol; +} + +multiArray3d ReadSolNm1FromRestart( + ifstream &resFile, const input &inp, const idealGas &eos, + const sutherland &suth, const unique_ptr &turb, + const vector &restartVars, const int &numI, const int &numJ, + const int &numK) { + // intialize multiArray3d + multiArray3d sol(numI, numJ, numK, 0); + + // 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; + // 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(); + } 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(); + } 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(); + } 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(); + } 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(); + } 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(); + } 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() / suth.MuRef(); + } else { + cerr << "ERROR: Variable " << var + << " to read from restart file is not defined!" << endl; + exit(EXIT_FAILURE); + } + } + sol(ii, jj, kk) = value; + } + } + } + return sol; +} diff --git a/src/parallel.cpp b/src/parallel.cpp index c1153b5..5f145f8 100644 --- a/src/parallel.cpp +++ b/src/parallel.cpp @@ -26,7 +26,7 @@ #include "plot3d.hpp" // plot3d #include "primVars.hpp" // primVars #include "procBlock.hpp" // procBlock -#include "boundaryConditions.hpp" // interblock +#include "boundaryConditions.hpp" // connection #include "resid.hpp" // resid #include "macros.hpp" #include "genArray.hpp" @@ -124,10 +124,10 @@ decomposition CubicDecomposition(vector &grid, } else { // split/send auto newBlk = static_cast(grid.size()); - vector altSurf; plot3dBlock lBlk, uBlk; grid[blk].Split(dir, ind, lBlk, uBlk); grid.push_back(uBlk); + vector altSurf; auto newBcs = bcs[blk].Split(dir, ind, blk, newBlk, altSurf); bcs.push_back(newBcs); @@ -136,6 +136,7 @@ decomposition CubicDecomposition(vector &grid, altSurf[ii], grid[blk], grid[altSurf[ii].PartnerBlock()], altSurf[ii].PartnerBlock(), dir, ind, blk, newBlk); } + // reassign split grid grid[blk] = lBlk; @@ -179,38 +180,40 @@ void SendNumProcBlocks(const vector &loadBal, int &numProcBlock) { MPI_COMM_WORLD); } -// function to send each processor the vector of interblocks it needs to compute +// function to send each processor the vector of connections it needs to compute // its boundary conditions -void SendConnections(vector &connections, - const MPI_Datatype &MPI_interblock) { - // first determine the number of interblocks and send that to all processors +void SendConnections(vector &connections, + const MPI_Datatype &MPI_connection) { + // first determine the number of connections and send that to all processors auto numCon = static_cast(connections.size()); MPI_Bcast(&numCon, 1, MPI_INT, ROOTP, MPI_COMM_WORLD); - connections.resize(numCon); // allocate space to receive the interblocks + connections.resize(numCon); // allocate space to receive the connections - // broadcast all interblocks to all processors - MPI_Bcast(&connections[0], connections.size(), MPI_interblock, ROOTP, + // broadcast all connections to all processors + MPI_Bcast(&connections[0], connections.size(), MPI_connection, ROOTP, MPI_COMM_WORLD); } /* Function to set custom MPI datatypes to allow for easier data transmission */ void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, MPI_Datatype &MPI_procBlockInts, - MPI_Datatype &MPI_interblock, + MPI_Datatype &MPI_connection, MPI_Datatype &MPI_DOUBLE_5INT, MPI_Datatype &MPI_vec3dMag, MPI_Datatype &MPI_uncoupledScalar, - MPI_Datatype &MPI_tensorDouble) { + MPI_Datatype &MPI_tensorDouble, + MPI_Datatype &MPI_wallData) { // 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_interblock -- output MPI_Datatype to send interblock class + // MPI_connection -- output MPI_Datatype to send connection class // MPI_DOUBLE_5INT -- output MPI_Datatype for a double followed by 5 ints // 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); @@ -228,6 +231,10 @@ 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); @@ -277,51 +284,54 @@ void SetDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, MPI_Type_commit(&MPI_DOUBLE_5INT); - // create MPI datatype for interblock class - int counts[11] = {2, 2, 2, 2, 2, 2, - 2, 2, 2, 8, 1}; // number of entries per field - MPI_Datatype types[11] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_C_BOOL, MPI_INT}; // field types - MPI_Aint disp[11], lowerBound, extent; - interblock inter; // dummy interblock to get layout of class + // create MPI datatype for connection class + constexpr auto nFields = 12; + int counts[nFields] = {2, 2, 2, 2, 2, 2, + 2, 2, 2, 8, 1, 1}; // number of entries per field + // field types + MPI_Datatype types[nFields] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, + MPI_INT, MPI_INT, MPI_INT, MPI_INT, + MPI_INT, MPI_C_BOOL, MPI_INT, MPI_C_BOOL}; + MPI_Aint disp[nFields], lowerBound, extent; + connection inter; // dummy connection to get layout of class inter.GetAddressesMPI(disp); // make addresses relative to first field - for (auto ii = 10; ii >= 0; ii--) { + for (auto ii = nFields - 1; ii >= 0; ii--) { disp[ii] -= disp[0]; } - MPI_Type_create_struct(11, counts, disp, types, &MPI_interblock); + MPI_Type_create_struct(11, counts, disp, types, &MPI_connection); // check that datatype has the correct extent, if it doesn't change the extent // this is necessary to portably send an array of this type - MPI_Type_get_extent(MPI_interblock, &lowerBound, &extent); + MPI_Type_get_extent(MPI_connection, &lowerBound, &extent); if (extent != sizeof(inter)) { - auto temp = MPI_interblock; - MPI_Type_create_resized(temp, 0, sizeof(inter), &MPI_interblock); + auto temp = MPI_connection; + MPI_Type_create_resized(temp, 0, sizeof(inter), &MPI_connection); MPI_Type_free(&temp); } - MPI_Type_commit(&MPI_interblock); + MPI_Type_commit(&MPI_connection); } /* Function to free custom MPI datatypesn */ void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, MPI_Datatype &MPI_procBlockInts, - MPI_Datatype &MPI_interblock, + MPI_Datatype &MPI_connection, MPI_Datatype &MPI_DOUBLE_5INT, MPI_Datatype &MPI_vec3dMag, MPI_Datatype &MPI_uncoupledScalar, - 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_interblock -- output MPI_Datatype to send interblock class - // MPI_DOUBLE_5INT -- output MPI_Datatype for a double followed by 5 ints - // 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_Datatype &MPI_tensorDouble, + MPI_Datatype &MPI_wallData) { + // 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); @@ -341,8 +351,14 @@ void FreeDataTypesMPI(MPI_Datatype &MPI_vec3d, MPI_Datatype &MPI_cellData, // free MPI datatype for a double followed by 5 ints MPI_Type_free(&MPI_DOUBLE_5INT); - // free MPI datatype for interblock class - MPI_Type_free(&MPI_interblock); + // free MPI datatype for connection class + MPI_Type_free(&MPI_connection); + + // 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 @@ -357,7 +373,9 @@ 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_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 // call the function @@ -368,6 +386,8 @@ vector SendProcBlocks(const vector &blocks, // 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 vector localBlocks(numProcBlock); @@ -383,7 +403,8 @@ vector SendProcBlocks(const vector &blocks, localBlocks[blocks[ii].LocalPosition()] = blocks[ii]; } else { // send data to receiving processors // pack and send procBlock - blocks[ii].PackSendGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag); + blocks[ii].PackSendGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag, + MPI_wallData); } } //-------------------------------------------------------------------------- @@ -393,7 +414,8 @@ vector SendProcBlocks(const vector &blocks, for (auto ii = 0; ii < numProcBlock; ii++) { // recv and unpack procBlock procBlock tempBlock; - tempBlock.RecvUnpackGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag); + tempBlock.RecvUnpackGeomMPI(MPI_cellData, MPI_vec3d, MPI_vec3dMag, + MPI_wallData, inp); // add procBlock to output vector localBlocks[tempBlock.LocalPosition()] = tempBlock; @@ -413,7 +435,8 @@ void GetProcBlocks(vector &blocks, const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_tensorDouble) { + const MPI_Datatype &MPI_tensorDouble, + 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 // call the function @@ -424,6 +447,8 @@ void GetProcBlocks(vector &blocks, // 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 @@ -437,7 +462,8 @@ void GetProcBlocks(vector &blocks, blocks[ii] = localBlocks[blocks[ii].LocalPosition()]; } else { // recv data from sending processors blocks[ii].RecvUnpackSolMPI(MPI_cellData, MPI_uncoupledScalar, - MPI_vec3d, MPI_tensorDouble); + MPI_vec3d, MPI_tensorDouble, MPI_wallData, + inp); } } //------------------------------------------------------------------------- @@ -464,7 +490,8 @@ void GetProcBlocks(vector &blocks, localBlocks[localPos[minGlobal]].PackSendSolMPI(MPI_cellData, MPI_uncoupledScalar, MPI_vec3d, - MPI_tensorDouble); + MPI_tensorDouble, + MPI_wallData); localPos.erase(localPos.begin() + minGlobal); } } @@ -480,17 +507,16 @@ void BroadcastString(string &str) { auto strSize = static_cast(str.size() + 1); MPI_Bcast(&strSize, 1, MPI_INT, ROOTP, MPI_COMM_WORLD); // broadcast string size - - auto *buf = new char[strSize]; // allocate a char buffer of string size - snprintf(buf, strSize, "%s", str.c_str()); // copy string into buffer - MPI_Bcast(&buf[0], strSize, MPI_CHAR, ROOTP, + + // allocate a char buffer of string size + auto buf = unique_ptr(new char[strSize]); + snprintf(buf.get(), strSize, "%s", str.c_str()); // copy string into buffer + MPI_Bcast(buf.get(), strSize, MPI_CHAR, ROOTP, MPI_COMM_WORLD); // broadcast string as char // create new string and assign to old string - string newStr(buf, strSize - 1); // -1 to not include c_str end character + string newStr(buf.get(), strSize - 1); // -1 to not include c_str end character str = newStr; - - delete[] buf; // deallocate buffer } // constructor with arguements @@ -599,11 +625,11 @@ int decomposition::MostUnderloadedProc(const vector &grid, /*Member function to return the number of blocks on a given processor.*/ int decomposition::NumBlocksOnProc(const int &a) const { - // a -- processor rank_ to find number of blocks on + // a -- processor rank to find number of blocks on auto num = 0; - for (auto ii = 0U; ii < rank_.size(); ii++) { - if (rank_[ii] == a) { + for (auto &rank : rank_) { + if (rank == a) { num++; } } @@ -613,12 +639,13 @@ int decomposition::NumBlocksOnProc(const int &a) const { /*Member function to return the number of blocks on all processors.*/ vector decomposition::NumBlocksOnAllProc() const { vector num(numProcs_, 0); - for (auto ii = 0U; ii < rank_.size(); ii++) { - num[rank_[ii]]++; + for (auto &rank : rank_) { + num[rank]++; } return num; } + /*Member function to send a block to a given processor*/ void decomposition::SendToProc(const int &blk, const int &fromProc, const int &toProc) { @@ -716,11 +743,11 @@ double decomposition::LoadRatio(const vector &grid, return fabs(1.0 - load / ideal); } -/*Member function to determine whether to send a whole block or a split block +/* Member function to determine whether to send a whole block or a split block from a given processor. If it is determined to send a split block, the index of -the -split is returned, and the direction string is changed to the appropriate value. -If a whole block is to be sent, the index returned is -1.*/ +the split is returned, and the direction string is changed to the appropriate +value. If a whole block is to be sent, the index returned is -1. +*/ int decomposition::SendWholeOrSplit(const vector &grid, const int &send, const int &recv, int &blk, string &dir) const { @@ -773,15 +800,15 @@ int decomposition::SendWholeOrSplit(const vector &grid, grid[blk].NumK() >= grid[blk].NumI()) { dir = "k"; // -1 to get cell sizes - planeSize = (grid[blk].NumJ() - 1) * (grid[blk].NumI() - 1); + planeSize = grid[blk].NumCellsJ() * grid[blk].NumCellsI(); splitLen = grid[blk].NumK(); } else if (grid[blk].NumJ() >= grid[blk].NumI()) { dir = "j"; - planeSize = (grid[blk].NumK() - 1) * (grid[blk].NumI() - 1); + planeSize = grid[blk].NumCellsK() * grid[blk].NumCellsI(); splitLen = grid[blk].NumJ(); } else { dir = "i"; - planeSize = (grid[blk].NumJ() - 1) * (grid[blk].NumK() - 1); + planeSize = grid[blk].NumCellsJ() * grid[blk].NumCellsK(); splitLen = grid[blk].NumI(); } @@ -807,6 +834,7 @@ int decomposition::SendWholeOrSplit(const vector &grid, return ind; } + void decomposition::PrintDiagnostics(const vector &grid) const { cout << "Decomposition for " << numProcs_ << " processors" << endl; for (auto ii = 0U; ii < rank_.size(); ii++) { diff --git a/src/plot3d.cpp b/src/plot3d.cpp index 7f8789c..e999a5b 100644 --- a/src/plot3d.cpp +++ b/src/plot3d.cpp @@ -31,12 +31,24 @@ using std::ios; // plot 3d block member functions +// member function to calculate the centroid of a given cell +vector3d plot3dBlock::Centroid(const int &ii, const int &jj, + const int &kk) const { + // centroid is average of all coordinates forming cell + return 0.125 * + (coords_(ii, jj, kk) + coords_(ii + 1, jj, kk) + + coords_(ii, jj + 1, kk) + coords_(ii + 1, jj + 1, kk) + + coords_(ii, jj, kk + 1) + coords_(ii + 1, jj, kk + 1) + + coords_(ii, jj + 1, kk + 1) + coords_(ii + 1, jj + 1, kk + 1)); +} + // plot3dBlock member function that calcualtes the volume of each cell /* All cells are assumed to be hexahedra. The 8 points that make up each hexahedron -are used to split the cell into 3 pyramids. The area of each pyramid is then -calculated and the volume of the 3 pyramids are summed to get the volume of the -hexahedra. This method is outlined in Hirsch. +are used to split the cell into 6 pyramids. The area of each pyramid is then +calculated and the volume of the 6 pyramids are summed to get the volume of the +hexahedra. The point of each pyramid is the centroid, and the six sides of the +cell make up the six bases. Vp = Havg * (D1 (cross) D2)) @@ -53,58 +65,44 @@ multiArray3d plot3dBlock::Volume() const { for (auto kk = 0; kk < vol.NumK(); kk++) { for (auto jj = 0; jj < vol.NumJ(); jj++) { for (auto ii = 0; ii < vol.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the i-direction - auto botStarFore = coords_(ii + 1, jj, kk); - // up 1 in the j-direction - auto botPortAft = coords_(ii, jj + 1, kk); - // up 1 in the i and j directions - auto botPortFore = coords_(ii + 1, jj + 1, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the i and k directions - auto topStarFore = coords_(ii + 1, jj, kk + 1); - // up 1 in the j and k directions - auto topPortAft = coords_(ii, jj + 1, kk + 1); - // up 1 in the i, j, and k directions - auto topPortFore = coords_(ii + 1, jj + 1, kk + 1); - - // Point of all three pyramids is located at the top, starboard, aft - // corner of the cell - // Calculate volume for pyramid 1 - quad face is bottom side - // xp is average vector from 4 base points to peak of pyramid - auto xp = 0.25 * ((botStarAft - topStarAft) + - (botPortAft - topStarAft) + - (botStarFore - topStarAft) + - (botPortFore - topStarAft)); - // vectors along diagonal of base - auto xac = botPortFore - botStarAft; - auto xbd = botStarFore - botPortAft; - auto pyramidVol = 1.0 / 6.0 * xp.DotProd(xac.CrossProd(xbd)); - - // Calculate volume for pyramid2 - quad face is fore side - xp = 0.25 * ((botStarFore - topStarAft) + (botPortFore - topStarAft) + - (topStarFore - topStarAft) + (topPortFore - topStarAft)); - xac = topPortFore - botStarFore; - xbd = topStarFore - botPortFore; - pyramidVol += 1.0 / 6.0 * xp.DotProd(xac.CrossProd(xbd)); - - // Calculate volume for pyramid3 - quad face is port side - xp = 0.25 * ((botPortFore - topStarAft) + (botPortAft - topStarAft) + - (topPortFore - topStarAft) + (topPortAft - topStarAft)); - xac = topPortFore - botPortAft; - xbd = botPortFore - topPortAft; - pyramidVol += 1.0 / 6.0 * xp.DotProd(xac.CrossProd(xbd)); - - // Assign volume to appropriate location - vol(ii, jj, kk) = pyramidVol; + // get centroid + const auto centroid = this->Centroid(ii, jj, kk); + + // calculate area of i-lower pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii, jj, kk), coords_(ii, jj, kk + 1), + coords_(ii, jj + 1, kk + 1), coords_(ii, jj + 1, kk)); + + // calculate area of i-upper pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii + 1, jj, kk), coords_(ii + 1, jj + 1, kk), + coords_(ii + 1, jj + 1, kk + 1), coords_(ii + 1, jj, kk + 1)); + + // calculate area of j-lower pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii, jj, kk), coords_(ii + 1, jj, kk), + coords_(ii + 1, jj, kk + 1), coords_(ii, jj, kk + 1)); + + // calculate area of j-upper pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii, jj + 1, kk), coords_(ii, jj + 1, kk + 1), + coords_(ii + 1, jj + 1, kk + 1), coords_(ii + 1, jj + 1, kk)); + + // calculate area of k-lower pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii, jj, kk), coords_(ii, jj + 1, kk), + coords_(ii + 1, jj + 1, kk), coords_(ii + 1, jj, kk)); + + // calculate area of k-upper pyramid + vol(ii, jj, kk) += PyramidVolume( + centroid, coords_(ii, jj, kk + 1), coords_(ii + 1, jj, kk + 1), + coords_(ii + 1, jj + 1, kk + 1), coords_(ii, jj + 1, kk + 1)); // Check for negative volumes - if (pyramidVol <= 0) { + if (vol(ii, jj, kk) <= 0) { cerr << "ERROR: Negative volume in PLOT3D block!!!" << endl; cerr << "i-dim = " << ii << ", j-dim = " << jj - << ", k-dim = " << kk << endl; + << ", k-dim = " << kk << ", vol = " << vol(ii, jj, kk) << endl; exit(EXIT_FAILURE); } } @@ -125,27 +123,8 @@ multiArray3d> plot3dBlock::Centroid() const { for (auto kk = 0; kk < centroid.NumK(); kk++) { for (auto jj = 0; jj < centroid.NumJ(); jj++) { for (auto ii = 0; ii < centroid.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the i-direction - auto botStarFore = coords_(ii + 1, jj, kk); - // up 1 in the j-direction - auto botPortAft = coords_(ii, jj + 1, kk); - // up 1 in the i and j directions - auto botPortFore = coords_(ii + 1, jj + 1, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the i and k directions - auto topStarFore = coords_(ii + 1, jj, kk + 1); - // up 1 in the j and k directions - auto topPortAft = coords_(ii, jj + 1, kk + 1); - // up 1 in the i, j, and k directions - auto topPortFore = coords_(ii + 1, jj + 1, kk + 1); - // Calculate the centroid of the cell - centroid(ii, jj, kk) = (0.125 * (botStarAft + botStarFore + botPortAft + - botPortFore + topStarAft + topStarFore - + topPortAft + topPortFore)); + centroid(ii, jj, kk) = this->Centroid(ii, jj, kk); } } } @@ -178,20 +157,11 @@ multiArray3d> plot3dBlock::FaceAreaI() const { for (auto kk = 0; kk < fArea.NumK(); kk++) { for (auto jj = 0; jj < fArea.NumJ(); jj++) { for (auto ii = 0; ii < fArea.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the j-direction - auto botPortAft = coords_(ii, jj + 1, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the j and k directions - auto topPortAft = coords_(ii, jj + 1, kk + 1); - // Calculate area for face by taking 1/2 of the cross product between // opposite diagonals // vectors from opposite corners of face - auto xac = topPortAft - botStarAft; - auto xbd = botPortAft - topStarAft; + auto xac = coords_(ii, jj + 1, kk + 1) - coords_(ii, jj, kk); + auto xbd = coords_(ii, jj + 1, kk) - coords_(ii, jj, kk + 1); // area vector is calculated so that normal points nominally in // direction of increasing i-coordinate @@ -209,7 +179,6 @@ multiArray3d> plot3dBlock::FaceAreaI() const { } } } - return fArea; } @@ -224,22 +193,13 @@ multiArray3d> plot3dBlock::FaceCenterI() const { for (auto kk = 0; kk < fCenter.NumK(); kk++) { for (auto jj = 0; jj < fCenter.NumJ(); jj++) { for (auto ii = 0; ii < fCenter.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the j-direction - auto botPortAft = coords_(ii, jj + 1, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the j and k directions - auto topPortAft = coords_(ii, jj + 1, kk + 1); - // Calculate face center by averaging four points that make up the face - fCenter(ii, jj, kk) = 0.25 * - (botStarAft + botPortAft + topStarAft + topPortAft); + fCenter(ii, jj, kk) = + 0.25 * (coords_(ii, jj, kk) + coords_(ii, jj + 1, kk) + + coords_(ii, jj, kk + 1) + coords_(ii, jj + 1, kk + 1)); } } } - return fCenter; } @@ -268,20 +228,11 @@ multiArray3d> plot3dBlock::FaceAreaJ() const { for (auto kk = 0; kk < fArea.NumK(); kk++) { for (auto jj = 0; jj < fArea.NumJ(); jj++) { for (auto ii = 0; ii < fArea.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the i-direction - auto botStarFore = coords_(ii + 1, jj, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the i and k directions - auto topStarFore = coords_(ii + 1, jj, kk + 1); - // Calculate area for face by taking 1/2 of the cross product between // opposite diagonals // vectors from opposite corners of face - auto xac = topStarAft - botStarFore; - auto xbd = botStarAft - topStarFore; + auto xac = coords_(ii, jj, kk + 1) - coords_(ii + 1, jj, kk); + auto xbd = coords_(ii, jj, kk) - coords_(ii + 1, jj, kk + 1); // area vector is calculated so that normal nominally points in // direction of increasing j-coordinate @@ -299,7 +250,6 @@ multiArray3d> plot3dBlock::FaceAreaJ() const { } } } - return fArea; } @@ -315,23 +265,14 @@ multiArray3d> plot3dBlock::FaceCenterJ() const { for (auto kk = 0; kk < fCenter.NumK(); kk++) { for (auto jj = 0; jj < fCenter.NumJ(); jj++) { for (auto ii = 0; ii < fCenter.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the i-direction - auto botStarFore = coords_(ii + 1, jj, kk); - // up 1 in the k direction - auto topStarAft = coords_(ii, jj, kk + 1); - // up 1 in the i and k directions - auto topStarFore = coords_(ii + 1, jj, kk + 1); - // Calculate face center by averaging the four points that make up the // face - fCenter(ii, jj, kk) = 0.25 * - (botStarAft + botStarFore + topStarAft + topStarFore); + fCenter(ii, jj, kk) = + 0.25 * (coords_(ii, jj, kk) + coords_(ii + 1, jj, kk) + + coords_(ii, jj, kk + 1) + coords_(ii + 1, jj, kk + 1)); } } } - return fCenter; } @@ -360,20 +301,11 @@ multiArray3d> plot3dBlock::FaceAreaK() const { for (auto kk = 0; kk < fArea.NumK(); kk++) { for (auto jj = 0; jj < fArea.NumJ(); jj++) { for (auto ii = 0; ii < fArea.NumI(); ii++) { - // baseline location - auto botStarAft = coords_(ii, jj, kk); - // up 1 in the i-direction - auto botStarFore = coords_(ii + 1, jj, kk); - // up 1 in the j-direction - auto botPortAft = coords_(ii, jj + 1, kk); - // up 1 in the i and j directions - auto botPortFore = coords_(ii + 1, jj + 1, kk); - // Calculate area for face by taking 1/2 of the cross product between // opposite diagonals // vectors from opposite corners of face - auto xac = botPortAft - botStarFore; - auto xbd = botPortFore - botStarAft; + auto xac = coords_(ii, jj + 1, kk) - coords_(ii + 1, jj, kk); + auto xbd = coords_(ii + 1, jj + 1, kk) - coords_(ii, jj, kk); // area vector is calculated so that normal nominally points in // direction of increasing k-coordinate @@ -391,7 +323,6 @@ multiArray3d> plot3dBlock::FaceAreaK() const { } } } - return fArea; } @@ -417,12 +348,12 @@ multiArray3d> plot3dBlock::FaceCenterK() const { auto botPortFore = coords_(ii + 1, jj + 1, kk); // Calculate face center by averaging four points that make up cell face - fCenter(ii, jj, kk) = 0.25 * - (botStarAft + botStarFore + botPortAft + botPortFore); + fCenter(ii, jj, kk) = + 0.25 * (coords_(ii, jj, kk) + coords_(ii + 1, jj, kk) + + coords_(ii, jj + 1, kk) + coords_(ii + 1, jj + 1, kk)); } } } - return fCenter; } @@ -451,9 +382,7 @@ vector ReadP3dGrid(const string &gridName, const double &LRef, // read the number of i, j, k coordinates in each plot3d block cout << "Size of each block is..." << endl; - vector vecI(numBlks, 0); - vector vecJ(numBlks, 0); - vector vecK(numBlks, 0); + vector> blkSize(numBlks); auto tempInt = 0; numCells = 0; @@ -461,18 +390,19 @@ vector ReadP3dGrid(const string &gridName, const double &LRef, for (auto ii = 0; ii < numBlks; ii++) { cout << "Block Number: " << ii << " "; fName.read(reinterpret_cast(&tempInt), sizeof(tempInt)); - vecI[ii] = tempInt; + blkSize[ii][0] = tempInt; cout << "I-DIM: " << tempInt << " "; fName.read(reinterpret_cast(&tempInt), sizeof(tempInt)); - vecJ[ii] = tempInt; + blkSize[ii][1] = tempInt; cout << "J-DIM: " << tempInt << " "; fName.read(reinterpret_cast(&tempInt), sizeof(tempInt)); - vecK[ii] = tempInt; + blkSize[ii][2] = tempInt; cout << "K-DIM: " << tempInt << endl; // calculate total number of cells (subtract 1 because number of cells is 1 // less than number of points) - numCells += (vecI[ii] - 1) * (vecJ[ii] - 1) * (vecK[ii] - 1); + numCells += + (blkSize[ii][0] - 1) * (blkSize[ii][1] - 1) * (blkSize[ii][2] - 1); } cout << endl; @@ -482,7 +412,8 @@ vector ReadP3dGrid(const string &gridName, const double &LRef, mesh.reserve(numBlks); for (auto ii = 0; ii < numBlks; ii++) { - multiArray3d> coordinates(vecI[ii], vecJ[ii], vecK[ii], 0); + multiArray3d> coordinates(blkSize[ii][0], blkSize[ii][1], + blkSize[ii][2], 0); for (auto jj = 0; jj < coordinates.Size(); jj++) { fName.read(reinterpret_cast(&tempDouble), sizeof(tempDouble)); @@ -554,3 +485,13 @@ void plot3dBlock::Join(const plot3dBlock &blk, const string &dir) { blk.coords_); (*this) = newBlk; } + +double PyramidVolume(const vector3d &p, const vector3d &a, + const vector3d &b, const vector3d &c, + const vector3d &d) { + auto xp = 0.25 * ((a - p) + (b - p) + (c - p) + (d - p)); + // vectors along diagonal of base + auto xac = c - a; + auto xbd = d - b; + return 1.0 / 6.0 * xp.DotProd(xac.CrossProd(xbd)); +} \ No newline at end of file diff --git a/src/primVars.cpp b/src/primVars.cpp index e01ae42..eba0bfa 100644 --- a/src/primVars.cpp +++ b/src/primVars.cpp @@ -25,6 +25,8 @@ #include "input.hpp" // input #include "turbulence.hpp" // turbModel #include "utility.hpp" +#include "wallLaw.hpp" +#include "wallData.hpp" using std::cout; using std::endl; @@ -64,26 +66,26 @@ primVars::primVars(const genArray &a, const bool &prim, } // member function to initialize a state with nondimensional values -void primVars::NondimensionalInitialize(const idealGas &eos, const double &aRef, +void primVars::NondimensionalInitialize(const idealGas &eos, const input &inp, const sutherland &suth, - const int &parBlock) { + const int &parBlock, + const unique_ptr &turb) { // get initial condition state for parent block auto ic = inp.ICStateForBlock(parBlock); - data_[0] = ic.Density() / inp.RRef(); - data_[4] = ic.Pressure() / (inp.PRef() * eos.Gamma()); - - data_[1] = ic.Velocity().X() / aRef; - data_[2] = ic.Velocity().Y() / aRef; - data_[3] = ic.Velocity().Z() / aRef; - - if (inp.IsTurbulent()) { + 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(), suth, eos); + ic.EddyViscosityRatio(), suth, eos, turb); } else { data_[5] = 0.0; data_[6] = 0.0; @@ -350,7 +352,6 @@ ____________________|___________ 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, @@ -359,7 +360,7 @@ primVars primVars::GetGhostState(const string &bcType, const idealGas &eqnState, const sutherland &suth, const unique_ptr &turb, - const int layer) const { + 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] @@ -380,7 +381,8 @@ primVars primVars::GetGhostState(const string &bcType, // face area vector (should always point out of domain) // at lower surface normal should point out of domain for ghost cell calc - const auto normArea = (surf % 2 == 1) ? -1.0 * areaVec : areaVec; + const auto isLower = surf % 2 == 1; + const auto normArea = isLower? -1.0 * areaVec : areaVec; // slip wall boundary condition // ---------------------------------------------------------------------- @@ -412,44 +414,126 @@ primVars primVars::GetGhostState(const string &bcType, // stay equal to the boundary cell const auto & bcData = inputVars.BCData(tag); - const auto aRef = inputVars.ARef(eqnState); - // ghost cell velocity at cell center is set to opposite of velocity at // boundary cell center so that velocity at face will be zero - const auto ghostVel = bcData->Velocity() / aRef - this->Velocity(); - + // 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 = 2.0 * (bcData->Temperature() / inputVars.TRef()) - - this->Temperature(eqnState); - ghostState.data_[0] = eqnState.DensityTP(tWall, ghostState.P()); - } else if (bcData->IsConstantHeatFlux()) { - // don't need turbulent contribution because eddy viscosity is 0 at wall - const auto mu = suth.EffectiveViscosity(this->Temperature(eqnState)); - const auto kappa = eqnState.Conductivity(mu); - // 2x wall distance as gradient length + 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, suth, 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 = + eqnState.Conductivity(wVars.viscosity_) + + eqnState.TurbConductivity(wVars.turbEddyVisc_, + turb->TurbPrandtlNumber()); + // 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 tWall = this->Temperature(eqnState) - - (bcData->HeatFlux() * pow(aRef / inputVars.LRef(), 3.0)) / - kappa * 2.0 * wallDist; - ghostState.data_[0] = eqnState.DensityTP(tWall, ghostState.P()); - } // default is adiabatic - // numerical BCs for pressure, same as boundary state + const auto qWall = bcData->HeatFlux(); + if (bcData->IsWallLaw()) { + wallLaw wl(bcData->VonKarmen(), bcData->WallConstant(), *this, wallDist, + inputVars.IsRANS()); + wVars = wl.HeatFluxBCs(normArea, velWall, eqnState, suth, turb, qWall, + isLower); + + if (wVars.SwitchToLowRe()) { + // don't need turbulent contribution b/c eddy viscosity is 0 at wall + const auto mu = suth.EffectiveViscosity(this->Temperature(eqnState)); + const auto kappa = eqnState.Conductivity(mu); + // 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 mu = suth.EffectiveViscosity(this->Temperature(eqnState)); + const auto kappa = eqnState.Conductivity(mu); + // 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, suth, 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 - // tke at cell center is set to opposite of tke at boundary cell center - // so that tke at face will be zero - if (inputVars.IsTurbulent()) { + // 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 = suth.Viscosity(this->Temperature(eqnState)) - / this->Rho(); - const auto wWall = suth.NondimScaling() * suth.NondimScaling() * - 60.0 * nuW / (wallDist * wallDist * turb->WallBeta()); - + const auto nuW = + suth.Viscosity(this->Temperature(eqnState)) / this->Rho(); + const auto wWall = suth.NondimScaling() * suth.NondimScaling() * 60.0 * + nuW / (wallDist * wallDist * turb->WallBeta()); ghostState.data_[6] = 2.0 * wWall - this->Omega(); if (layer > 1) { @@ -457,21 +541,20 @@ primVars primVars::GetGhostState(const string &bcType, } } - // 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 + // 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); - // nondimensionalize velocity - const auto aRef = inputVars.ARef(eqnState); - const auto ghostVel = bcData->Velocity() / aRef; + const auto ghostVel = bcData->Velocity(); - ghostState.data_[0] = bcData->Density() / inputVars.RRef(); + ghostState.data_[0] = bcData->Density(); ghostState.data_[1] = ghostVel.X(); ghostState.data_[2] = ghostVel.Y(); ghostState.data_[3] = ghostVel.Z(); @@ -479,22 +562,22 @@ primVars primVars::GetGhostState(const string &bcType, // numerical bc for pressure, same as boundary state // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(ghostVel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + 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.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(ghostVel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } } @@ -506,8 +589,7 @@ primVars primVars::GetGhostState(const string &bcType, // better options } else if (bcType == "subsonicOutflow") { // set pressure to freestream value const auto & bcData = inputVars.BCData(tag); - ghostState.data_[4] = bcData->Pressure() / - (inputVars.PRef() * eqnState.Gamma()); + ghostState.data_[4] = bcData->Pressure(); // numerical bcs for density, velocity -- equal to boundary cell // numerical bcs for turbulence variables @@ -526,11 +608,8 @@ primVars primVars::GetGhostState(const string &bcType, } else if (bcType == "characteristic") { const auto & bcData = inputVars.BCData(tag); // freestream variables - const auto freeSoS = inputVars.ARef(eqnState); - const auto freeVel = bcData->Velocity() / freeSoS; - const primVars freeState(bcData->Density() / inputVars.RRef(), - bcData->Pressure() / (inputVars.PRef() * eqnState.Gamma()), - freeVel); + const auto freeVel = bcData->Velocity(); + const primVars freeState(bcData->Density(), freeVel, bcData->Pressure()); // internal variables const auto velIntNorm = this->Velocity().DotProd(normArea); @@ -544,11 +623,11 @@ primVars primVars::GetGhostState(const string &bcType, ghostState = freeState; // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } } else if (machInt >= 1.0 && velIntNorm >= 0.0) { // supersonic outflow @@ -577,11 +656,11 @@ primVars primVars::GetGhostState(const string &bcType, normArea.Z() * (freeState.P() - ghostState.P()) / rhoSoSInt; // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } } else if (machInt < 1.0 && velIntNorm >= 0.0) { // subsonic outflow @@ -614,11 +693,11 @@ primVars primVars::GetGhostState(const string &bcType, ghostState = layer * ghostState - (*this); // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(freeVel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } } @@ -629,29 +708,26 @@ primVars primVars::GetGhostState(const string &bcType, } else if (bcType == "supersonicInflow") { const auto & bcData = inputVars.BCData(tag); // physical boundary conditions - fix everything - const auto aRef = inputVars.ARef(eqnState); - // nondimensional velocity - const auto vel = bcData->Velocity() / aRef; + const auto vel = bcData->Velocity(); - ghostState.data_[0] = bcData->Density() / inputVars.RRef(); + 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() / - (inputVars.PRef() * eqnState.Gamma()); + ghostState.data_[4] = bcData->Pressure(); // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { - ghostState.ApplyFarfieldTurbBC(vel, - bcData->TurbulenceIntensity(), + if (inputVars.IsRANS()) { + ghostState.ApplyFarfieldTurbBC(vel, bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } - // supersonic outflow boundary condition - // -------------------------------------------------------------------------- - // this boundary condition enforces the entire state as extrapolated from the - // interior (zeroth order extrapolation) + // 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 @@ -679,13 +755,10 @@ primVars primVars::GetGhostState(const string &bcType, 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() / - inputVars.TRef() * (sosB * sosB / stagSoSsq); - const auto aRef = eqnState.SoS(inputVars.PRef(), inputVars.RRef()); - const auto pb = bcData->StagnationPressure() / (inputVars.RRef() * aRef * aRef) - * pow(sosB * sosB / stagSoSsq, eqnState.Gamma() / g); - const auto vbMag = sqrt(2.0 / g * (bcData->StagnationTemperature() / - inputVars.TRef() - tb)); + const auto tb = bcData->StagnationTemperature() * (sosB * sosB / stagSoSsq); + const auto pb = bcData->StagnationPressure() * + pow(sosB * sosB / stagSoSsq, eqnState.Gamma() / 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(); @@ -694,22 +767,22 @@ primVars primVars::GetGhostState(const string &bcType, ghostState.data_[4] = pb; // assign farfield conditions to turbulence variables - if (inputVars.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(ghostState.Velocity(), bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + 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.IsTurbulent()) { + if (inputVars.IsRANS()) { ghostState.ApplyFarfieldTurbBC(ghostState.Velocity(), bcData->TurbulenceIntensity(), bcData->EddyViscosityRatio(), suth, - eqnState); + eqnState, turb); } } @@ -720,10 +793,8 @@ primVars primVars::GetGhostState(const string &bcType, } else if (bcType == "pressureOutlet") { const auto & bcData = inputVars.BCData(tag); - // reference speed of sound - const auto aRef = inputVars.ARef(eqnState); // nondimensional pressure from input file - const auto pb = bcData->Pressure() / (inputVars.RRef() * aRef * aRef); + const auto pb = bcData->Pressure(); const auto SoSInt = this->SoS(eqnState); const auto rhoSoSInt = this->Rho() * SoSInt; @@ -744,11 +815,11 @@ primVars primVars::GetGhostState(const string &bcType, ghostState = layer * ghostState - (*this); } - // interblock boundary condition + // connection boundary condition // -------------------------------------------------------------------------- // this boundary condition is appropriate for point matched interfaces between // physical blocks or processor blocks - } else if (bcType == "interblock") { + } 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 @@ -797,53 +868,19 @@ void primVars::ApplyFarfieldTurbBC(const vector3d &vel, const double &turbInten, const double &viscRatio, const sutherland &suth, - const idealGas &eqnState) { + const idealGas &eqnState, + const unique_ptr &turb) { // vel -- reference velocity (nondimensionalized) // turbInten -- turbulence intensity at farfield // viscRatio -- eddy viscosity ratio at farfield // suth -- sutherland's law for viscosity // eqnState -- equation of state + // turb -- turbulence model data_[5] = 1.5 * pow(turbInten * vel.Mag(), 2.0); data_[6] = data_[0] * data_[5] / (viscRatio * suth.Viscosity(this->Temperature(eqnState))); -} - - -multiArray3d GetGhostStates( - const multiArray3d &bndStates, const string &bcName, - const multiArray3d> &faceAreas, - const multiArray3d &wDist, const int &surf, - const input &inp, const int &tag, const idealGas &eos, const sutherland &suth, - const unique_ptr &turb, const int layer) { - // bndStates -- states at cells adjacent to boundary - // bcName -- boundary condition type - // faceAreas -- face areas of boundary - // surf -- boundary surface type [1-6] - // inp -- input variables - // tag -- boundary condition tag - // eos -- equation of state - // suth -- sutherland's law for viscosity - // turb -- turbulence model - // layer -- layer of ghost cell to return - // (1 closest to boundary, or 2 farthest) - - multiArray3d ghostStates(bndStates.NumINoGhosts(), - bndStates.NumJNoGhosts(), - bndStates.NumKNoGhosts(), - bndStates.GhostLayers()); - 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++) { - ghostStates(ii, jj, kk) = - bndStates(ii, jj, kk). - GetGhostState(bcName, faceAreas(ii, jj, kk).UnitVector(), - wDist(ii, jj, kk), surf, inp, tag, eos, suth, turb, - layer); - } - } - } - return ghostStates; + this->LimitTurb(turb); } void primVars::LimitTurb(const unique_ptr &turb) { diff --git a/src/procBlock.cpp b/src/procBlock.cpp index d039dcb..8e99357 100644 --- a/src/procBlock.cpp +++ b/src/procBlock.cpp @@ -33,6 +33,7 @@ #include "fluxJacobian.hpp" #include "kdtree.hpp" #include "utility.hpp" +#include "wallData.hpp" using std::cout; using std::endl; @@ -45,11 +46,11 @@ using std::unique_ptr; using std::ifstream; // constructors for procBlock class -procBlock::procBlock(const double &aRef, const plot3dBlock &blk, - const int &numBlk, const boundaryConditions &bound, - const int &pos, const int &r, const int &lpos, - const input &inp, const idealGas &eos, - const sutherland &suth) { +procBlock::procBlock(const plot3dBlock &blk, const int &numBlk, + const boundaryConditions &bound, const int &pos, + const int &r, const int &lpos, const input &inp, + const idealGas &eos, const sutherland &suth, + const unique_ptr &turb) { // blk -- plot3d block of which this procBlock is a subset of // numBlk -- the block number of blk (the parent block) // bound -- boundary conditions for block @@ -59,6 +60,7 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, // inp -- input variables // eos -- equation of state // suth -- sutherland's law for viscosity + // turb -- turbulence model numGhosts_ = inp.NumberGhostLayers(); parBlock_ = numBlk; @@ -68,10 +70,18 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, localPos_ = lpos; bc_ = bound; + for (auto ii = 0; ii < bound.NumSurfaces(); ++ii) { + if (bound.GetBCTypes(ii) == "viscousWall") { + const auto surf = bound.GetSurface(ii); + const auto &bcData = inp.BCData(surf.Tag()); + wallData_.push_back(wallData(surf, bcData)); + } + } isViscous_ = inp.IsViscous(); isTurbulent_ = inp.IsTurbulent(); - storeTimeN_ = (inp.IsImplicit() || inp.TimeIntegration() == "rk4"); + isRANS_ = inp.IsRANS(); + storeTimeN_ = inp.NeedToStoreTimeN(); isMultiLevelTime_ = inp.IsMultilevelInTime(); // get initial condition state for parent block @@ -84,7 +94,7 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, // get nondimensional state for initialization primVars inputState; - inputState.NondimensionalInitialize(eos, aRef, inp, suth, parBlock_); + inputState.NondimensionalInitialize(eos, inp, suth, parBlock_, turb); // pad stored variable vectors with ghost cells state_ = PadWithGhosts(multiArray3d(numI, numJ, numK, 0, @@ -92,12 +102,12 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, if (storeTimeN_) { consVarsN_ = {numI, numJ, numK, 0, genArray(0.0)}; } else { - consVarsN_ = {1, 1, 1, 0}; + consVarsN_ = {0, 0, 0, 0}; } if (isMultiLevelTime_) { consVarsNm1_ = {numI, numJ, numK, 0, genArray(0.0)}; } else { - consVarsNm1_ = {1, 1, 1, 0}; + consVarsNm1_ = {0, 0, 0, 0}; } vol_ = PadWithGhosts(blk.Volume(), numGhosts_); @@ -109,9 +119,9 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, fCenterJ_ = PadWithGhosts(blk.FaceCenterJ(), numGhosts_); fCenterK_ = PadWithGhosts(blk.FaceCenterK(), numGhosts_); - cellWidthI_ = {1, 1, 1, 0}; - cellWidthJ_ = {1, 1, 1, 0}; - cellWidthK_ = {1, 1, 1, 0}; + cellWidthI_ = {numI, numJ, numK, numGhosts_}; + cellWidthJ_ = {numI, numJ, numK, numGhosts_}; + cellWidthK_ = {numI, numJ, numK, numGhosts_}; wallDist_ = {numI, numJ, numK, numGhosts_, DEFAULTWALLDIST}; @@ -129,32 +139,36 @@ procBlock::procBlock(const double &aRef, const plot3dBlock &blk, inputViscosity = suth.Viscosity(inputTemperature); viscosity_ = {numI, numJ, numK, numGhosts_, inputViscosity}; } else { - velocityGrad_ = {1, 1, 1, 0}; - temperatureGrad_ = {1, 1, 1, 0}; - viscosity_ = {1, 1, 1, 0}; + velocityGrad_ = {0, 0, 0, 0}; + temperatureGrad_ = {0, 0, 0, 0}; + viscosity_ = {0, 0, 0, 0}; } if (isTurbulent_) { - tkeGrad_ = {numI, numJ, numK, numGhosts_}; - omegaGrad_ = {numI, numJ, numK, numGhosts_}; eddyViscosity_ = {numI, numJ, numK, numGhosts_, ic.EddyViscosityRatio() * inputViscosity}; + } else { + eddyViscosity_ = {0, 0, 0, 0, 0.0}; + } + + 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}; } else { - tkeGrad_ = {1, 1, 1, 0}; - omegaGrad_ = {1, 1, 1, 0}; - eddyViscosity_ = {1, 1, 1, 0, 0.0}; - f1_ = {1, 1, 1, 0, 0.0}; - f2_ = {1, 1, 1, 0, 0.0}; + tkeGrad_ = {0, 0, 0, 0}; + omegaGrad_ = {0, 0, 0, 0}; + f1_ = {0, 0, 0, 0, 0.0}; + f2_ = {0, 0, 0, 0, 0.0}; } } // 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 &storeTimeN, - const bool &isMultiLevelInTime) { + const bool &isTurbulent, const bool &isRANS, + const bool &storeTimeN, const bool &isMultiLevelInTime) { // ni -- i-dimension (cell) // nj -- j-dimension (cell) // nk -- k-dimension (cell) @@ -170,9 +184,11 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, localPos_ = 0; bc_ = {}; + wallData_ = {}; isViscous_ = isViscous; isTurbulent_ = isTurbulent; + isRANS_ = isRANS; storeTimeN_ = storeTimeN; isMultiLevelTime_ = isMultiLevelInTime; @@ -181,12 +197,12 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, if (storeTimeN) { consVarsN_ = {ni, nj, nk, 0}; } else { - consVarsN_ = {1, 1, 1, 0}; + consVarsN_ = {0, 0, 0, 0}; } if (isMultiLevelTime_) { consVarsNm1_ = {ni, nj, nk, 0}; } else { - consVarsNm1_ = {1, 1, 1, 0}; + consVarsNm1_ = {0, 0, 0, 0}; } center_ = {ni, nj, nk, numGhosts_}; fAreaI_ = {ni + 1, nj, nk, numGhosts_}; @@ -199,9 +215,9 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, vol_ = {ni, nj, nk, numGhosts_}; wallDist_ = {ni, nj, nk, numGhosts_, DEFAULTWALLDIST}; - cellWidthI_ = {1, 1, 1, 0}; - cellWidthJ_ = {1, 1, 1, 0}; - cellWidthK_ = {1, 1, 1, 0}; + cellWidthI_ = {ni, nj, nk, numGhosts_}; + cellWidthJ_ = {ni, nj, nk, numGhosts_}; + cellWidthK_ = {ni, nj, nk, numGhosts_}; specRadius_ = {ni, nj, nk, 0}; dt_ = {ni, nj, nk, 0}; @@ -213,23 +229,27 @@ procBlock::procBlock(const int &ni, const int &nj, const int &nk, temperatureGrad_ = {ni, nj, nk, numGhosts_}; viscosity_ = {ni, nj, nk, numGhosts_}; } else { - velocityGrad_ = {1, 1, 1, 0}; - temperatureGrad_ = {1, 1, 1, 0}; - viscosity_ = {1, 1, 1, 0}; + velocityGrad_ = {0, 0, 0, 0}; + temperatureGrad_ = {0, 0, 0, 0}; + viscosity_ = {0, 0, 0, 0}; } if (isTurbulent_) { + eddyViscosity_ = {ni, nj, nk, numGhosts_}; + } else { + eddyViscosity_ = {0, 0, 0, 0}; + } + + if (isRANS_) { tkeGrad_ = {ni, nj, nk, numGhosts_}; omegaGrad_ = {ni, nj, nk, numGhosts_}; - eddyViscosity_ = {ni, nj, nk, numGhosts_}; f1_ = {ni, nj, nk, numGhosts_}; f2_ = {ni, nj, nk, numGhosts_}; } else { - tkeGrad_ = {1, 1, 1, 0}; - omegaGrad_ = {1, 1, 1, 0}; - eddyViscosity_ = {1, 1, 1, 0}; - f1_ = {1, 1, 1, 0}; - f2_ = {1, 1, 1, 0}; + tkeGrad_ = {0, 0, 0, 0}; + omegaGrad_ = {0, 0, 0, 0}; + f1_ = {0, 0, 0, 0}; + f2_ = {0, 0, 0, 0}; } } @@ -431,7 +451,7 @@ void procBlock::CalcInvFluxI(const idealGas &eqnState, const input &inp, const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk), eqnState); - const auto turbInvSpecRad = isTurbulent_ ? + const auto turbInvSpecRad = isRANS_ ? turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk)): 0.0; @@ -560,7 +580,7 @@ void procBlock::CalcInvFluxJ(const idealGas &eqnState, const input &inp, const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk), eqnState); - const auto turbInvSpecRad = isTurbulent_ ? + const auto turbInvSpecRad = isRANS_ ? turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk)): 0.0; @@ -691,7 +711,7 @@ void procBlock::CalcInvFluxK(const idealGas &eqnState, const input &inp, const auto invSpecRad = state_(ii, jj, kk).InvCellSpectralRadius( fAreaK_(ii, jj, kk), fAreaK_(ii, jj, kk + 1), eqnState); - const auto turbInvSpecRad = isTurbulent_ ? + const auto turbInvSpecRad = isRANS_ ? turb->InviscidCellSpecRad(state_(ii, jj, kk), fAreaK_(ii, jj, kk), fAreaK_(ii, jj, kk + 1)) : 0.0; @@ -741,22 +761,21 @@ the time step is user specified assign that time step (after nondimensionalization) to dt variable. If time step is to be determined using CFL number, call function to do so. */ -void procBlock::CalcBlockTimeStep(const input &inputVars, const double &aRef) { - // inputVars -- all input variables - // aRef -- reference speed of sound (used for time non dimensionalization) +void procBlock::CalcBlockTimeStep(const input &inp) { + // inp -- all input variables // loop over all physical cells - no ghost cells for dt variable for (auto kk = 0; kk < this->NumK(); kk++) { for (auto jj = 0; jj < this->NumJ(); jj++) { for (auto ii = 0; ii < this->NumI(); ii++) { // dt specified, use global time stepping - if (inputVars.Dt() > 0.0) { + if (inp.Dt() > 0.0) { // nondimensional time - dt_(ii, jj, kk) = inputVars.Dt() * aRef / inputVars.LRef(); + dt_(ii, jj, kk) = inp.Dt() * inp.ARef() / inp.LRef(); // cfl specified, use local time stepping - } else if (inputVars.CFL() > 0.0) { - this->CalcCellDt(ii, jj, kk, inputVars.CFL()); + } else if (inp.CFL() > 0.0) { + this->CalcCellDt(ii, jj, kk, inp.CFL()); } else { cerr << "ERROR: Neither dt or cfl was specified!" << endl; exit(EXIT_FAILURE); @@ -771,14 +790,12 @@ 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 idealGas &eos, - const double &aRef, const sutherland &suth, const multiArray3d &du, - const unique_ptr &turb, - const int &rr, genArray &l2, resid &linf) { + const unique_ptr &turb, const int &rr, + genArray &l2, resid &linf) { // inputVars -- all input variables // eos -- equation of state - // aRef -- reference speed of sound (for nondimensionalization) // suth -- sutherland's law for viscosity // du -- updates to conservative variables (only used in implicit solver) // turb -- turbulence model @@ -913,8 +930,10 @@ void procBlock::ResetResidWS() { void procBlock::ResetGradients() { velocityGrad_.Zero(); temperatureGrad_.Zero(); - tkeGrad_.Zero(); - omegaGrad_.Zero(); + if (isRANS_) { + tkeGrad_.Zero(); + omegaGrad_.Zero(); + } } // member function to reset the turbulence variables back to zero after an @@ -922,8 +941,10 @@ void procBlock::ResetGradients() { // function calls. void procBlock::ResetTurbVars() { eddyViscosity_.Zero(0.0); - f1_.Zero(0.0); - f2_.Zero(0.0); + if (isRANS_) { + f1_.Zero(0.0); + f2_.Zero(0.0); + } } /* Member function to add the cell volume divided by the cell time step to the @@ -953,37 +974,6 @@ The above equation shows that the time m minus time n term (FD(Un)) requires a (1+zeta)V/(t*theta) term multiplied by it. That is the purpose of this function. */ -// multiArray3d procBlock::SolTimeMMinusN( -// const multiArray3d &n, const idealGas &eos, const input &inp, -// const int &mm) const { -// // n -- solution for block at time n -// // eos -- equation of state -// // inp -- input variables -// // mm -- nonlinear iteration number - -// // initialize a vector to hold the returned values to zero -// multiArray3d mMinusN(n.NumI(), n.NumJ(), n.NumK(), 0); - -// // if mm is 0, then solution at time m and solution at time n is the same -// if (mm != 0) { -// auto m = this->GetCopyConsVars(eos); - -// // loop over all 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++) { -// const auto diagVolTime = (vol_(ii, jj, kk) * (1.0 + inp.Zeta())) -// / (dt_(ii, jj, kk) * inp.Theta()); -// mMinusN(ii, jj, kk) = diagVolTime * (m(ii, jj, kk) - n(ii, jj, kk)); -// } -// } -// } -// } - -// return mMinusN; -// } - - double procBlock::SolDeltaNCoeff(const int &ii, const int &jj, const int &kk, const input &inp) const { return (vol_(ii, jj, kk) * (1.0 + inp.Zeta())) / (dt_(ii, jj, kk) * inp.Theta()); @@ -1002,65 +992,14 @@ double procBlock::SolDeltaNm1Coeff(const int &ii, const int &jj, const int &kk, genArray procBlock::SolDeltaNm1(const int &ii, const int &jj, const int &kk, const input &inp) const { - const auto coeff = this->SolDeltaNm1Coeff(ii, jj, kk, inp); - return coeff * (consVarsN_(ii, jj, kk) - consVarsNm1_(ii, jj, kk)); + 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); + } } -/* Member function to calculate the delta n-1 term for the implicit bdf2 solver. - -dU/dt = V/t * [ ((1 + zeta) * FD - zeta * BD) / ((1 + theta) * FD )] * Un = -Rn - -The above equation shows the governing equations written in the Beam & Warming -format for time integration. U is the vector of conserved variables -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 -the following: - -FD(Un) = (-t * Rn - t * theta * FD(Rn) + zeta * V * FD(Un-1)) / ((1 + zeta) * V) - -FD(Rn) requires us to know the residual at time n+1, but this is unknown. To -bypass this difficulty we linearize the residual using a Taylor series -expansion about time n. Rn+1 = Rn + J*FD(Un) where J is the flux jacobian dR/dU. -Rearranging the above equation we get the following: - -[J + (1+zeta)*V/(t*theta)] * FD(Un) = -Rn/theta + zeta*V/(t*theta) * FD(Un-1) - -The above equation shows that the time n minus time n-1 term (FD(Un-1)) requires -a zeta*V/(t*theta) term multiplied by it. That is the purpose of this -function. - -This function is supposed to be run at the end of a time step when the data stored -in *this has been updated to the next time step. -*/ -// multiArray3d procBlock::DeltaNMinusOne( -// const multiArray3d &solTimeN, const idealGas &eqnState, -// const double &theta, const double &zeta) const { -// // solTimeN -- The solution at time n -// // eqnState -- equation of state -// // theta -- Beam & Warming coefficient theta for time integration -// // zeta -- Beam & Warming coefficient zeta for time integration - -// // Solution at time n minus solution at time n-1 -// multiArray3d solDeltaNm1(this->NumI(), this->NumJ(), this->NumK(), 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++) { -// const auto diagVolTime = (vol_(ii, jj, kk) * zeta) / -// (dt_(ii, jj, kk) * theta); -// solDeltaNm1(ii, jj, kk) = diagVolTime * -// (state_(ii, jj, kk).ConsVars(eqnState) - -// solTimeN(ii, jj, kk)); -// } -// } -// } -// return solDeltaNm1; -// } - void procBlock::InvertDiagonal(multiArray3d &mainDiagonal, const input &inp) const { // mainDiagonal -- main diagonal in implicit operator @@ -1080,9 +1019,9 @@ void procBlock::InvertDiagonal(multiArray3d &mainDiagonal, // add volume and time term mainDiagonal(ii, jj, kk).MultiplyOnDiagonal(inp.MatrixRelaxation(), - isTurbulent_); - mainDiagonal(ii, jj, kk).AddOnDiagonal(diagVolTime, isTurbulent_); - mainDiagonal(ii, jj, kk).Inverse(isTurbulent_); + isRANS_); + mainDiagonal(ii, jj, kk).AddOnDiagonal(diagVolTime, isRANS_); + mainDiagonal(ii, jj, kk).Inverse(isRANS_); } } } @@ -1247,7 +1186,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if i lower diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii - 1, jj, kk) || - bc_.GetBCName(ii, jj, kk, 1) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 1)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); @@ -1265,7 +1204,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if j lower diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj - 1, kk) || - bc_.GetBCName(ii, jj, kk, 3) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 3)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); @@ -1283,7 +1222,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if k lower diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj, kk - 1) || - bc_.GetBCName(ii, jj, kk, 5) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 5)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); @@ -1307,7 +1246,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if i upper cell is in physical location there is a contribution // from it if (this->IsPhysical(ii + 1, jj, kk) || - bc_.GetBCName(ii + 1, jj, kk, 2) == "interblock") { + bc_.BCIsConnection(ii + 1, jj, kk, 2)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); @@ -1325,7 +1264,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if j upper cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj + 1, kk) || - bc_.GetBCName(ii, jj + 1, kk, 4) == "interblock") { + bc_.BCIsConnection(ii, jj + 1, kk, 4)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); @@ -1343,7 +1282,7 @@ void procBlock::LUSGS_Forward(const vector> &reorder, // if k lower cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj, kk + 1) || - bc_.GetBCName(ii, jj, kk + 1, 6) == "interblock") { + bc_.BCIsConnection(ii, jj, kk + 1, 6)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); @@ -1407,7 +1346,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if i upper diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii + 1, jj, kk) || - bc_.GetBCName(ii + 1, jj, kk, 2) == "interblock") { + bc_.BCIsConnection(ii + 1, jj, kk, 2)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); @@ -1425,7 +1364,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if j upper diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj + 1, kk) || - bc_.GetBCName(ii, jj + 1, kk, 4) == "interblock") { + bc_.BCIsConnection(ii, jj + 1, kk, 4)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); @@ -1443,7 +1382,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if k upper diagonal cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj, kk + 1) || - bc_.GetBCName(ii, jj, kk + 1, 6) == "interblock") { + bc_.BCIsConnection(ii, jj, kk + 1, 6)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); @@ -1467,7 +1406,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if i lower cell is in physical location there is a contribution // from it if (this->IsPhysical(ii - 1, jj, kk) || - bc_.GetBCName(ii, jj, kk, 1) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 1)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); @@ -1485,7 +1424,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if j lower cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj - 1, kk) || - bc_.GetBCName(ii, jj, kk, 3) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 3)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); @@ -1503,7 +1442,7 @@ double procBlock::LUSGS_Backward(const vector> &reorder, // if k lower cell is in physical location there is a contribution // from it if (this->IsPhysical(ii, jj, kk - 1) || - bc_.GetBCName(ii, jj, kk, 5) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 5)) { // calculate projected center to center distance along face area const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); @@ -1572,7 +1511,7 @@ double procBlock::DPLUR(multiArray3d &x, // if i lower diagonal cell is in physical location there is a // contribution from it if (this->IsPhysical(ii - 1, jj, kk) || - bc_.GetBCName(ii, jj, kk, 1) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 1)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii, jj, kk, "i"); @@ -1590,7 +1529,7 @@ double procBlock::DPLUR(multiArray3d &x, // if j lower diagonal cell is in physical location there is a // constribution from it if (this->IsPhysical(ii, jj - 1, kk) || - bc_.GetBCName(ii, jj, kk, 3) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 3)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii, jj, kk, "j"); @@ -1608,7 +1547,7 @@ double procBlock::DPLUR(multiArray3d &x, // if k lower diagonal cell is in physical location there is a // contribution from it if (this->IsPhysical(ii, jj, kk - 1) || - bc_.GetBCName(ii, jj, kk, 5) == "interblock") { + bc_.BCIsConnection(ii, jj, kk, 5)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii, jj, kk, "k"); @@ -1626,7 +1565,7 @@ double procBlock::DPLUR(multiArray3d &x, // if i upper diagonal cell is in physical location there is a // contribution from it if (this->IsPhysical(ii + 1, jj, kk) || - bc_.GetBCName(ii + 1, jj, kk, 2) == "interblock") { + bc_.BCIsConnection(ii + 1, jj, kk, 2)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii + 1, jj, kk, "i"); @@ -1645,7 +1584,7 @@ double procBlock::DPLUR(multiArray3d &x, // if j upper diagonal cell is in physical location there is a // contribution from it if (this->IsPhysical(ii, jj + 1, kk) || - bc_.GetBCName(ii, jj + 1, kk, 4) == "interblock") { + bc_.BCIsConnection(ii, jj + 1, kk, 4)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii, jj + 1, kk, "j"); @@ -1664,7 +1603,7 @@ double procBlock::DPLUR(multiArray3d &x, // if k upper diagonal cell is in physical location there is a // contribution from it if (this->IsPhysical(ii, jj, kk + 1) || - bc_.GetBCName(ii, jj, kk + 1, 6) == "interblock") { + bc_.BCIsConnection(ii, jj, kk + 1, 6)) { // calculate projected center to center distance const auto projDist = this->ProjC2CDist(ii, jj, kk + 1, "k"); @@ -1856,74 +1795,128 @@ void procBlock::CalcViscFluxI(const sutherland &suth, const idealGas &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 state; - auto wDist = 0.0; - auto mu = 0.0; - - if (inp.ViscousFaceReconstruction() == "central") { - // get cell widths - const vector cellWidth = {cellWidthI_(ii - 1, jj, kk), - cellWidthI_(ii, jj, kk)}; - - // Get state at face - state = FaceReconCentral(state_(ii - 1, jj, kk), - state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); - - // Get wall distance at face - wDist = FaceReconCentral(wallDist_(ii - 1, jj, kk), - wallDist_(ii, jj, kk), cellWidth); - - // Get viscosity at face - mu = FaceReconCentral(viscosity_(ii - 1, jj, kk), - viscosity_(ii, jj, kk), cellWidth); - - } else { // use 4th order reconstruction - // get cell widths - const vector cellWidth = {cellWidthI_(ii - 2, jj, kk), - cellWidthI_(ii - 1, jj, kk), - cellWidthI_(ii, jj, kk), - cellWidthI_(ii + 1, jj, kk)}; - - // Get state at face - 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); - - // 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); - - // 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); - } - // calculate gradients tensor velGrad; vector3d tempGrad, tkeGrad, omegaGrad; - CalcGradsI(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + this->CalcGradsI(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); - // calculate turbulent eddy viscosity and blending coefficients + // declare variables needed throughout function + primVars state; auto f1 = 0.0; auto f2 = 0.0; + auto mu = 0.0; auto mut = 0.0; - if (isTurbulent_) { - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, suth, mut, f1, f2); + viscousFlux tempViscFlux; + + // get surface info it at boundary + auto surfType = 0; + if (ii == fAreaI_.PhysStartI()) { + surfType = 1; + } else if (ii == fAreaI_.PhysEndI() - 1) { + surfType = 2; + } + const auto isBoundary = (surfType > 0) ? true : false; + auto isWallLawBoundary = false; + auto isLowReBoundary = false; + auto wallDataInd = 0; + + if (isBoundary) { + // get boundary surface information + const auto surf = bc_.GetBCSurface(ii, jj, kk, surfType); + if (surf.BCType() == "viscousWall") { + wallDataInd = this->WallDataIndex(surf); + isWallLawBoundary = + wallData_[wallDataInd].IsWallLaw() && + !wallData_[wallDataInd].SwitchToLowRe(ii, jj, kk); + isLowReBoundary = !isWallLawBoundary; + } } - // calculate viscous flux - const viscousFlux tempViscFlux(velGrad, suth, eqnState, tempGrad, - this->FAreaUnitI(ii, jj, kk), - tkeGrad, omegaGrad, turb, state, mu, - mut, f1); + if (isWallLawBoundary) { + // wall law wall boundary + f1 = 1.0; + f2 = 1.0; + mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + 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); + } else { // not boundary, or low Re wall boundary + auto wDist = 0.0; + if (inp.ViscousFaceReconstruction() == "central") { + // get cell widths + const vector cellWidth = {cellWidthI_(ii - 1, jj, kk), + cellWidthI_(ii, jj, kk)}; + + // Get state at face + state = FaceReconCentral(state_(ii - 1, jj, kk), state_(ii, jj, kk), + cellWidth); + state.LimitTurb(turb); + + // Get wall distance at face + wDist = FaceReconCentral(wallDist_(ii - 1, jj, kk), + wallDist_(ii, jj, kk), cellWidth); + + // Get viscosity at face + mu = FaceReconCentral(viscosity_(ii - 1, jj, kk), + viscosity_(ii, jj, kk), cellWidth); + + } else { // use 4th order reconstruction + // get cell widths + const vector cellWidth = { + cellWidthI_(ii - 2, jj, kk), cellWidthI_(ii - 1, jj, kk), + cellWidthI_(ii, jj, kk), cellWidthI_(ii + 1, jj, kk)}; + + // Get state at face + 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); + + // 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); + + // 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); + } + + // 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, suth, lengthScale, mut, f1, f2); + } + + if (isLowReBoundary) { + // calculate viscous flux + auto wVars = tempViscFlux.CalcWallFlux( + velGrad, suth, eqnState, tempGrad, this->FAreaUnitI(ii, jj, kk), + tkeGrad, omegaGrad, turb, state, mu, mut, f1); + auto y = (surfType == 1) ? wallDist_(ii, jj, kk) + : wallDist_(ii - 1, jj, kk); + wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / + (wVars.viscosity_ + wVars.turbEddyVisc_); + wallData_[wallDataInd](ii, jj, kk) = wVars; + } else { + // calculate viscous flux + tempViscFlux.CalcFlux(velGrad, suth, eqnState, tempGrad, + this->FAreaUnitI(ii, jj, kk), tkeGrad, + omegaGrad, turb, state, mu, mut, f1); + } + } // calculate projected center to center distance const auto c2cDist = this->ProjC2CDist(ii, jj, kk, "i"); @@ -1941,11 +1934,13 @@ void procBlock::CalcViscFluxI(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii - 1, jj, kk) += sixth * velGrad; temperatureGrad_(ii - 1, jj, kk) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii - 1, jj, kk) += sixth * tkeGrad; - omegaGrad_(ii - 1, jj, kk) += sixth * omegaGrad; eddyViscosity_(ii - 1, jj, kk) += sixth * mut; - f1_(ii - 1, jj, kk) += sixth * f1; - f2_(ii - 1, jj, kk) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii - 1, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii - 1, jj, kk) += sixth * omegaGrad; + f1_(ii - 1, jj, kk) += sixth * f1; + f2_(ii - 1, jj, kk) += sixth * f2; + } } // if using block matrix on main diagonal, accumulate flux jacobian @@ -1968,11 +1963,13 @@ void procBlock::CalcViscFluxI(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii, jj, kk) += sixth * tkeGrad; - omegaGrad_(ii, jj, kk) += sixth * omegaGrad; eddyViscosity_(ii, jj, kk) += sixth * mut; - f1_(ii, jj, kk) += sixth * f1; - f2_(ii, jj, kk) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + f1_(ii, jj, kk) += sixth * f1; + f2_(ii, jj, kk) += sixth * f2; + } } // calculate component of wave speed. This is done on a cell by cell @@ -1982,7 +1979,7 @@ void procBlock::CalcViscFluxI(const sutherland &suth, const idealGas &eqnState, fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk), eqnState, suth, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut, turb); - const auto turbViscSpecRad = isTurbulent_ ? + const auto turbViscSpecRad = isRANS_ ? turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaI_(ii, jj, kk), fAreaI_(ii + 1, jj, kk), viscosity_(ii, jj, kk), @@ -2102,74 +2099,128 @@ void procBlock::CalcViscFluxJ(const sutherland &suth, const idealGas &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 state; - auto wDist = 0.0; - auto mu = 0.0; - - if (inp.ViscousFaceReconstruction() == "central") { - // get cell widths - const vector cellWidth = {cellWidthJ_(ii, jj - 1, kk), - cellWidthJ_(ii, jj, kk)}; - - // Get velocity at face - state = FaceReconCentral(state_(ii, jj - 1, kk), - state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); - - // Get wall distance at face - wDist = FaceReconCentral(wallDist_(ii, jj - 1, kk), - wallDist_(ii, jj, kk), cellWidth); - - // Get wall distance at face - mu = FaceReconCentral(viscosity_(ii, jj - 1, kk), - viscosity_(ii, jj, kk), cellWidth); - - } else { // use 4th order reconstruction - // get cell widths - const vector cellWidth = {cellWidthJ_(ii, jj - 2, kk), - cellWidthJ_(ii, jj - 1, kk), - cellWidthJ_(ii, jj, kk), - cellWidthJ_(ii, jj + 1, kk)}; - - // Get velocity at face - 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); - - // 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); - - // 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); - } - // calculate gradients tensor velGrad; vector3d tempGrad, tkeGrad, omegaGrad; - CalcGradsJ(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + this->CalcGradsJ(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); - // calculate turbulent eddy viscosity and blending coefficients + // declare variables needed throughout function + primVars state; auto f1 = 0.0; auto f2 = 0.0; + auto mu = 0.0; auto mut = 0.0; - if (isTurbulent_) { - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, suth, mut, f1, f2); + viscousFlux tempViscFlux; + + // get surface info if at boundary + auto surfType = 0; + if (jj == fAreaJ_.PhysStartJ()) { + surfType = 3; + } else if (jj == fAreaJ_.PhysEndJ() - 1) { + surfType = 4; + } + const auto isBoundary = (surfType > 0) ? true : false; + auto isWallLawBoundary = false; + auto isLowReBoundary = false; + auto wallDataInd = 0; + + if (isBoundary) { + // get boundary surface information + const auto surf = bc_.GetBCSurface(ii, jj, kk, surfType); + if (surf.BCType() == "viscousWall") { + wallDataInd = this->WallDataIndex(surf); + isWallLawBoundary = + wallData_[wallDataInd].IsWallLaw() && + !wallData_[wallDataInd].SwitchToLowRe(ii, jj, kk); + isLowReBoundary = !isWallLawBoundary; + } } - // calculate viscous flux - const viscousFlux tempViscFlux(velGrad, suth, eqnState, tempGrad, - this->FAreaUnitJ(ii, jj, kk), - tkeGrad, omegaGrad, turb, state, mu, - mut, f1); + if (isWallLawBoundary) { + // wall law wall boundary + f1 = 1.0; + f2 = 1.0; + mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + 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); + } else { // not boundary, or low Re wall boundary + auto wDist = 0.0; + if (inp.ViscousFaceReconstruction() == "central") { + // get cell widths + const vector cellWidth = {cellWidthJ_(ii, jj - 1, kk), + cellWidthJ_(ii, jj, kk)}; + + // Get velocity at face + state = FaceReconCentral(state_(ii, jj - 1, kk), state_(ii, jj, kk), + cellWidth); + state.LimitTurb(turb); + + // Get wall distance at face + wDist = FaceReconCentral(wallDist_(ii, jj - 1, kk), + wallDist_(ii, jj, kk), cellWidth); + + // Get wall distance at face + mu = FaceReconCentral(viscosity_(ii, jj - 1, kk), + viscosity_(ii, jj, kk), cellWidth); + + } else { // use 4th order reconstruction + // get cell widths + const vector cellWidth = { + cellWidthJ_(ii, jj - 2, kk), cellWidthJ_(ii, jj - 1, kk), + cellWidthJ_(ii, jj, kk), cellWidthJ_(ii, jj + 1, kk)}; + + // Get velocity at face + 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); + + // 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); + + // 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); + } + + // 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, suth, lengthScale, mut, f1, f2); + } + + if (isLowReBoundary) { + // calculate viscous flux + auto wVars = tempViscFlux.CalcWallFlux( + velGrad, suth, eqnState, tempGrad, this->FAreaUnitJ(ii, jj, kk), + tkeGrad, omegaGrad, turb, state, mu, mut, f1); + auto y = (surfType == 3) ? wallDist_(ii, jj, kk) + : wallDist_(ii, jj - 1, kk); + wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / + (wVars.viscosity_ + wVars.turbEddyVisc_); + wallData_[wallDataInd](ii, jj, kk) = wVars; + } else { + // calculate viscous flux + tempViscFlux.CalcFlux(velGrad, suth, eqnState, tempGrad, + this->FAreaUnitJ(ii, jj, kk), tkeGrad, + omegaGrad, turb, state, mu, mut, f1); + } + } // calculate projected center to center distance const auto c2cDist = this->ProjC2CDist(ii, jj, kk, "j"); @@ -2188,11 +2239,13 @@ void procBlock::CalcViscFluxJ(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii, jj - 1, kk) += sixth * velGrad; temperatureGrad_(ii, jj - 1, kk) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii, jj - 1, kk) += sixth * tkeGrad; - omegaGrad_(ii, jj - 1, kk) += sixth * omegaGrad; eddyViscosity_(ii, jj - 1, kk) += sixth * mut; - f1_(ii, jj - 1, kk) += sixth * f1; - f2_(ii, jj - 1, kk) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii, jj - 1, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj - 1, kk) += sixth * omegaGrad; + f1_(ii, jj - 1, kk) += sixth * f1; + f2_(ii, jj - 1, kk) += sixth * f2; + } } // if using block matrix on main diagonal, accumulate flux jacobian @@ -2215,11 +2268,13 @@ void procBlock::CalcViscFluxJ(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii, jj, kk) += sixth * tkeGrad; - omegaGrad_(ii, jj, kk) += sixth * omegaGrad; eddyViscosity_(ii, jj, kk) += sixth * mut; - f1_(ii, jj, kk) += sixth * f1; - f2_(ii, jj, kk) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + f1_(ii, jj, kk) += sixth * f1; + f2_(ii, jj, kk) += sixth * f2; + } } // calculate component of wave speed. This is done on a cell by cell @@ -2229,7 +2284,7 @@ void procBlock::CalcViscFluxJ(const sutherland &suth, const idealGas &eqnState, fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk), eqnState, suth, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut, turb); - const auto turbViscSpecRad = isTurbulent_ ? + const auto turbViscSpecRad = isRANS_ ? turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaJ_(ii, jj, kk), fAreaJ_(ii, jj + 1, kk), viscosity_(ii, jj, kk), @@ -2349,74 +2404,128 @@ void procBlock::CalcViscFluxK(const sutherland &suth, const idealGas &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 state; - auto wDist = 0.0; - auto mu = 0.0; - - if (inp.ViscousFaceReconstruction() == "central") { - // get cell widths - const vector cellWidth = {cellWidthK_(ii, jj, kk - 1), - cellWidthK_(ii, jj, kk)}; - - // Get state at face - state = FaceReconCentral(state_(ii, jj, kk - 1), - state_(ii, jj, kk), cellWidth); - state.LimitTurb(turb); - - // Get wall distance at face - wDist = FaceReconCentral(wallDist_(ii, jj, kk - 1), - wallDist_(ii, jj, kk), cellWidth); - - // Get wall distance at face - mu = FaceReconCentral(viscosity_(ii, jj, kk - 1), - viscosity_(ii, jj, kk), cellWidth); - - } else { // use 4th order reconstruction - // get cell widths - const vector cellWidth = {cellWidthK_(ii, jj, kk - 2), - cellWidthK_(ii, jj, kk - 1), - cellWidthK_(ii, jj, kk), - cellWidthK_(ii, jj, kk + 1)}; - - // Get state at face - 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); - - // 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); - - // 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); - } - - // calculate viscous flux + // calculate gradients tensor velGrad; vector3d tempGrad, tkeGrad, omegaGrad; - CalcGradsK(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); + this->CalcGradsK(ii, jj, kk, velGrad, tempGrad, tkeGrad, omegaGrad); - // calculate turbulent eddy viscosity and blending coefficients + // declare variables needed throughout function + primVars state; auto f1 = 0.0; auto f2 = 0.0; + auto mu = 0.0; auto mut = 0.0; - if (isTurbulent_) { - turb->EddyViscAndBlending(state, velGrad, tkeGrad, omegaGrad, mu, - wDist, suth, mut, f1, f2); + viscousFlux tempViscFlux; + + // get surface info if at boundary + auto surfType = 0; + if (kk == fAreaK_.PhysStartK()) { + surfType = 5; + } else if (kk == fAreaK_.PhysEndK() - 1) { + surfType = 6; + } + const auto isBoundary = (surfType > 0) ? true : false; + auto isWallLawBoundary = false; + auto isLowReBoundary = false; + auto wallDataInd = 0; + + if (isBoundary) { + // get boundary surface information + const auto surf = bc_.GetBCSurface(ii, jj, kk, surfType); + if (surf.BCType() == "viscousWall") { + wallDataInd = this->WallDataIndex(surf); + isWallLawBoundary = + wallData_[wallDataInd].IsWallLaw() && + !wallData_[wallDataInd].SwitchToLowRe(ii, jj, kk); + isLowReBoundary = !isWallLawBoundary; + } } - // calculate viscous flux - const viscousFlux tempViscFlux(velGrad, suth, eqnState, tempGrad, - this->FAreaUnitK(ii, jj, kk), - tkeGrad, omegaGrad, turb, state, mu, - mut, f1); + if (isWallLawBoundary) { + // wall law wall boundary + f1 = 1.0; + f2 = 1.0; + mu = wallData_[wallDataInd].WallViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + mut = wallData_[wallDataInd].WallEddyViscosity(ii, jj, kk) * + suth.InvNondimScaling(); + state = wallData_[wallDataInd].WallState(ii, jj, kk, eqnState); + 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); + } else { // not boundary, or low Re wall boundary + auto wDist = 0.0; + if (inp.ViscousFaceReconstruction() == "central") { + // get cell widths + const vector cellWidth = {cellWidthK_(ii, jj, kk - 1), + cellWidthK_(ii, jj, kk)}; + + // Get state at face + state = FaceReconCentral(state_(ii, jj, kk - 1), state_(ii, jj, kk), + cellWidth); + state.LimitTurb(turb); + + // Get wall distance at face + wDist = FaceReconCentral(wallDist_(ii, jj, kk - 1), + wallDist_(ii, jj, kk), cellWidth); + + // Get wall distance at face + mu = FaceReconCentral(viscosity_(ii, jj, kk - 1), + viscosity_(ii, jj, kk), cellWidth); + + } else { // use 4th order reconstruction + // get cell widths + const vector cellWidth = { + cellWidthK_(ii, jj, kk - 2), cellWidthK_(ii, jj, kk - 1), + cellWidthK_(ii, jj, kk), cellWidthK_(ii, jj, kk + 1)}; + + // Get state at face + 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); + + // 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); + + // 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); + } + + // 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, suth, lengthScale, mut, f1, f2); + } + + if (isLowReBoundary) { + // calculate viscous flux + auto wVars = tempViscFlux.CalcWallFlux( + velGrad, suth, eqnState, tempGrad, this->FAreaUnitK(ii, jj, kk), + tkeGrad, omegaGrad, turb, state, mu, mut, f1); + auto y = (surfType == 5) ? wallDist_(ii, jj, kk) + : wallDist_(ii, jj, kk - 1); + wVars.yplus_ = y * wVars.frictionVelocity_ * wVars.density_ / + (wVars.viscosity_ + wVars.turbEddyVisc_); + wallData_[wallDataInd](ii, jj, kk) = wVars; + } else { + // calculate viscous flux + tempViscFlux.CalcFlux(velGrad, suth, eqnState, tempGrad, + this->FAreaUnitK(ii, jj, kk), tkeGrad, + omegaGrad, turb, state, mu, mut, f1); + } + } // calculate projected center to center distance const auto c2cDist = this->ProjC2CDist(ii, jj, kk, "k"); @@ -2435,11 +2544,13 @@ void procBlock::CalcViscFluxK(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii, jj, kk - 1) += sixth * velGrad; temperatureGrad_(ii, jj, kk - 1) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii, jj, kk - 1) += sixth * tkeGrad; - omegaGrad_(ii, jj, kk - 1) += sixth * omegaGrad; eddyViscosity_(ii, jj, kk - 1) += sixth * mut; - f1_(ii, jj, kk - 1) += sixth * f1; - f2_(ii, jj, kk - 1) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii, jj, kk - 1) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk - 1) += sixth * omegaGrad; + f1_(ii, jj, kk - 1) += sixth * f1; + f2_(ii, jj, kk - 1) += sixth * f2; + } } // if using block matrix on main diagonal, accumulate flux jacobian @@ -2462,11 +2573,13 @@ void procBlock::CalcViscFluxK(const sutherland &suth, const idealGas &eqnState, velocityGrad_(ii, jj, kk) += sixth * velGrad; temperatureGrad_(ii, jj, kk) += sixth * tempGrad; if (isTurbulent_) { - tkeGrad_(ii, jj, kk) += sixth * tkeGrad; - omegaGrad_(ii, jj, kk) += sixth * omegaGrad; eddyViscosity_(ii, jj, kk) += sixth * mut; - f1_(ii, jj, kk) += sixth * f1; - f2_(ii, jj, kk) += sixth * f2; + if (isRANS_) { + tkeGrad_(ii, jj, kk) += sixth * tkeGrad; + omegaGrad_(ii, jj, kk) += sixth * omegaGrad; + f1_(ii, jj, kk) += sixth * f1; + f2_(ii, jj, kk) += sixth * f2; + } } // calculate component of wave speed. This is done on a cell by cell @@ -2477,7 +2590,7 @@ void procBlock::CalcViscFluxK(const sutherland &suth, const idealGas &eqnState, vol_(ii, jj, kk), viscosity_(ii, jj, kk), mut, turb); - const auto turbViscSpecRad = isTurbulent_ ? + const auto turbViscSpecRad = isRANS_ ? turb->ViscCellSpecRad(state_(ii, jj, kk), fAreaK_(ii, jj, kk), fAreaK_(ii, jj, kk + 1), viscosity_(ii, jj, kk), @@ -2569,7 +2682,7 @@ void procBlock::AssignGhostCellsGeom() { } // ----------------------------------------------------------------------- - // only supply geometry values for non interblock BCs + // only supply geometry values for non interblock BCs (including periodic) // for interblock do nothing if (bc_.GetBCTypes(ii) != "interblock") { // assign volume for layer of ghost cells @@ -2838,8 +2951,8 @@ void procBlock::AssignInviscidGhostCells(const input &inp, const auto r3 = bc_.RangeDir3(ii); const auto dir = bc_.Direction3(ii); - const auto surfType = bc_.GetSurfaceType(ii); - const auto tag = bc_.GetTag(ii); + const auto surf = bc_.GetSurface(ii); + const auto surfType = surf.SurfaceType(); auto gCell = 0, iCell = 0, aCell = 0; // indices for cells auto bnd = 0; // indices for faces @@ -2862,9 +2975,9 @@ void procBlock::AssignInviscidGhostCells(const input &inp, } // ----------------------------------------------------------------------- - // only supply cell values for non interblock BCs - // for interblock do nothing - if (bc_.GetBCTypes(ii) != "interblock") { + // only supply cell values for non connection BCs + // for connection do nothing + if (!bc_.IsConnection(ii)) { // get boundary condtion type (no viscous walls in invicid BCs) auto bcName = bc_.GetBCTypes(ii); if (bcName == "viscousWall") {bcName = "slipWall";} @@ -2885,9 +2998,9 @@ void procBlock::AssignInviscidGhostCells(const input &inp, const auto boundaryStates = (bcName == "slipWall") ? state_.Slice(dir, iCell, r1, r2) : state_.Slice(dir, aCell, r1, r2); - const auto ghostStates = GetGhostStates(boundaryStates, bcName, - faceAreas, wDist, surfType, inp, - tag, eos, suth, turb, layer); + const auto ghostStates = + this->GetGhostStates(boundaryStates, bcName, faceAreas, wDist, + surf, inp, eos, suth, turb, layer); state_.Insert(dir, gCell, r1, r2, ghostStates); } @@ -3002,21 +3115,12 @@ void procBlock::AssignInviscidGhostCellsEdge( // loop over edge for (auto d1 = 0; d1 <= max1; d1++) { - string bc_2 = "undefined"; - string bc_3 = "undefined"; - auto tag2 = 0, tag3 = 0; + boundarySurface bcSurf_2, bcSurf_3; vector3d fArea2, fArea3; if (dir == "i") { // boundary conditions at corner - bc_2 = bc_.GetBCName(d1, cFaceD2_2, cFaceD2_3, surf2); - if (bc_2 == "viscousWall") {bc_2 = "slipWall";} - - bc_3 = bc_.GetBCName(d1, cFaceD3_2, cFaceD3_3, surf3); - if (bc_3 == "viscousWall") {bc_3 = "slipWall";} - - // get tags at corners - tag2 = bc_.GetBCTag(d1, cFaceD2_2, cFaceD2_3, surf2); - tag3 = bc_.GetBCTag(d1, cFaceD3_2, cFaceD3_3, surf3); + bcSurf_2 = bc_.GetBCSurface(d1, cFaceD2_2, cFaceD2_3, surf2); + bcSurf_3 = bc_.GetBCSurface(d1, cFaceD3_2, cFaceD3_3, surf3); // get face area fArea2 = fAreaJ_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); @@ -3024,15 +3128,8 @@ void procBlock::AssignInviscidGhostCellsEdge( } else if (dir == "j") { // boundary conditions at corner - bc_2 = bc_.GetBCName(cFaceD2_3, d1, cFaceD2_2, surf2); - if (bc_2 == "viscousWall") {bc_2 = "slipWall";} - - bc_3 = bc_.GetBCName(cFaceD3_3, d1, cFaceD3_2, surf3); - if (bc_3 == "viscousWall") {bc_3 = "slipWall";} - - // get tags at corners - tag2 = bc_.GetBCTag(cFaceD2_3, d1, cFaceD2_2, surf2); - tag3 = bc_.GetBCTag(cFaceD3_3, d1, cFaceD3_2, surf3); + bcSurf_2 = bc_.GetBCSurface(cFaceD2_3, d1, cFaceD2_2, surf2); + bcSurf_3 = bc_.GetBCSurface(cFaceD3_3, d1, cFaceD3_2, surf3); // get face area fArea2 = fAreaK_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); @@ -3040,38 +3137,43 @@ void procBlock::AssignInviscidGhostCellsEdge( } else { // boundary conditions at corner - bc_2 = bc_.GetBCName(cFaceD2_2, cFaceD2_3, d1, surf2); - if (bc_2 == "viscousWall") {bc_2 = "slipWall";} - - bc_3 = bc_.GetBCName(cFaceD3_2, cFaceD3_3, d1, surf3); - if (bc_3 == "viscousWall") {bc_3 = "slipWall";} - - // get tags at corners - tag2 = bc_.GetBCTag(cFaceD2_2, cFaceD2_3, d1, surf2); - tag3 = bc_.GetBCTag(cFaceD3_2, cFaceD3_3, d1, surf3); + bcSurf_2 = bc_.GetBCSurface(cFaceD2_2, cFaceD2_3, d1, surf2); + bcSurf_3 = bc_.GetBCSurface(cFaceD3_2, cFaceD3_3, d1, surf3); // get face area fArea2 = fAreaI_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); fArea3 = fAreaJ_(dir, d1, gCellD2, cFaceD3_3).UnitVector(); } + // get bc type and tag + auto bc_2 = bcSurf_2.BCType(); + if (bc_2 == "viscousWall") {bc_2 = "slipWall";} + + auto bc_3 = bcSurf_3.BCType(); + if (bc_3 == "viscousWall") {bc_3 = "slipWall";} + + const auto tag2 = bcSurf_2.Tag(); + const auto tag3 = bcSurf_3.Tag(); + // get wall distance 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 + // 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, eos, suth, turb, - layer2); + wVars, layer2); // 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, eos, suth, turb, - layer3); + wVars, layer3); } else { // both surfaces or neither are walls - proceed as normal if (layer2 == layer3) { // need to average state_(dir, d1, gCellD2, gCellD3) = 0.5 * @@ -3113,8 +3215,8 @@ void procBlock::AssignViscousGhostCells(const input &inp, const idealGas &eos, const auto r3 = bc_.RangeDir3(ii); const auto dir = bc_.Direction3(ii); - const auto surfType = bc_.GetSurfaceType(ii); - const auto tag = bc_.GetTag(ii); + const auto surf = bc_.GetSurface(ii); + const auto surfType = surf.SurfaceType(); auto gCell = 0, iCell = 0, aCell = 0; // indices for cells auto bnd = 0; // indices for faces @@ -3155,9 +3257,9 @@ void procBlock::AssignViscousGhostCells(const input &inp, const idealGas &eos, // get interior boundary states and ghost states const auto boundaryStates = state_.Slice(dir, iCell, r1, r2); - const auto ghostStates = GetGhostStates(boundaryStates, bcName, - faceAreas, wDist, surfType, inp, - tag, eos, suth, turb, layer); + const auto ghostStates = + this->GetGhostStates(boundaryStates, bcName, faceAreas, wDist, + surf, inp, eos, suth, turb, layer); state_.Insert(dir, gCell, r1, r2, ghostStates); } @@ -3275,18 +3377,12 @@ void procBlock::AssignViscousGhostCellsEdge(const input &inp, // loop over edge for (auto d1 = 0; d1 <= max1; d1++) { - string bc_2 = "undefined"; - string bc_3 = "undefined"; - auto tag2 = 0, tag3 = 0; + boundarySurface bcSurf_2, bcSurf_3; vector3d fArea2, fArea3; if (dir == "i") { // boundary conditions at corner - bc_2 = bc_.GetBCName(d1, cFaceD2_2, cFaceD2_3, surf2); - bc_3 = bc_.GetBCName(d1, cFaceD3_2, cFaceD3_3, surf3); - - // get tags at corner - tag2 = bc_.GetBCTag(d1, cFaceD2_2, cFaceD2_3, surf2); - tag3 = bc_.GetBCTag(d1, cFaceD3_2, cFaceD3_3, surf3); + bcSurf_2 = bc_.GetBCSurface(d1, cFaceD2_2, cFaceD2_3, surf2); + bcSurf_3 = bc_.GetBCSurface(d1, cFaceD3_2, cFaceD3_3, surf3); // get face area fArea2 = fAreaJ_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); @@ -3294,12 +3390,8 @@ void procBlock::AssignViscousGhostCellsEdge(const input &inp, } else if (dir == "j") { // boundary conditions at corner - bc_2 = bc_.GetBCName(cFaceD2_3, d1, cFaceD2_2, surf2); - bc_3 = bc_.GetBCName(cFaceD3_3, d1, cFaceD3_2, surf3); - - // get tags at corner - tag2 = bc_.GetBCTag(cFaceD2_3, d1, cFaceD2_2, surf2); - tag3 = bc_.GetBCTag(cFaceD3_3, d1, cFaceD3_2, surf3); + bcSurf_2 = bc_.GetBCSurface(cFaceD2_3, d1, cFaceD2_2, surf2); + bcSurf_3 = bc_.GetBCSurface(cFaceD3_3, d1, cFaceD3_2, surf3); // get face area fArea2 = fAreaK_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); @@ -3307,22 +3399,26 @@ void procBlock::AssignViscousGhostCellsEdge(const input &inp, } else { // boundary conditions at corner - bc_2 = bc_.GetBCName(cFaceD2_2, cFaceD2_3, d1, surf2); - bc_3 = bc_.GetBCName(cFaceD3_2, cFaceD3_3, d1, surf3); - - // get tags at corner - tag2 = bc_.GetBCTag(cFaceD2_2, cFaceD2_3, d1, surf2); - tag3 = bc_.GetBCTag(cFaceD3_2, cFaceD3_3, d1, surf3); + bcSurf_2 = bc_.GetBCSurface(cFaceD2_2, cFaceD2_3, d1, surf2); + bcSurf_3 = bc_.GetBCSurface(cFaceD3_2, cFaceD3_3, d1, surf3); // get face area fArea2 = fAreaI_(dir, d1, cFaceD2_2, gCellD3).UnitVector(); fArea3 = fAreaJ_(dir, d1, gCellD2, cFaceD3_3).UnitVector(); } + // get bc type and tag + const auto bc_2 = bcSurf_2.BCType(); + const auto bc_3 = bcSurf_3.BCType(); + + const auto tag2 = bcSurf_2.Tag(); + const auto tag3 = bcSurf_3.Tag(); + // get wall distance 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 // assign states ------------------------------------------------- // surface-2 is a wall, but surface-3 is not - extend wall bc @@ -3330,13 +3426,13 @@ void procBlock::AssignViscousGhostCellsEdge(const input &inp, state_(dir, d1, gCellD2, gCellD3) = state_(dir, d1, pCellD2, gCellD3).GetGhostState( bc_2, fArea2, wDist2, surf2, inp, tag2, eos, suth, turb, - layer2); + wVars, layer2); // 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, eos, suth, turb, - layer3); + wVars, layer3); // both surfaces are walls - proceed as normal } else if (bc_2 == "viscousWall" && bc_3 == "viscousWall") { if (layer2 == layer3) { // need to average @@ -3486,8 +3582,66 @@ bool procBlock::AtEdgeInclusive(const int &ii, const int &jj, const int &kk, return atEdge; } +// returns true if the given indices are for a regular ghost cell, and not an +// edge ghost cell or physical cell. Also returns surface type of ghost cell +bool procBlock::AtGhostNonEdge(const int &ii, const int &jj, const int &kk, + string &dir, int &type) const { + // ii -- i index of location to test + // jj -- j index of location to test + // kk -- k index of location to test + // dir -- direction that edge runs in + + auto atGhost = false; + + // at il ghost cells - i in ghost cell range, j/k in physical cells + if (ii >= this->StartIG() && ii < this->StartI() && + jj >= this->StartJG() && jj < this->EndJG() && + kk >= this->StartKG() && kk < this->EndKG()) { + atGhost = true; + dir = "il"; + type = 1; + // at jl - j in ghost cell range, i/k in physical cells + } else if (jj >= this->StartJG() && jj < this->StartJ() && + ii >= this->StartIG() && ii < this->EndIG() && + kk >= this->StartKG() && kk < this->EndKG()) { + atGhost = true; + dir = "jl"; + type = 3; + // at kl - k in ghost cell range, i/j in physical cells + } else if (kk >= this->StartKG() && kk < this->StartK() && + jj >= this->StartJG() && jj < this->EndJG() && + ii >= this->StartIG() && ii < this->EndIG()) { + atGhost = true; + dir = "kl"; + type = 5; + // at iu ghost cells - i in ghost cell range, j/k in physical cells + } else if (ii >= this->EndI() && ii < this->EndIG() && + jj >= this->StartJG() && jj < this->EndJG() && + kk >= this->StartKG() && kk < this->EndKG()) { + atGhost = true; + dir = "iu"; + type = 2; + // at ju - j in ghost cell range, i/k in physical cells + } else if (jj >= this->EndJ() && jj < this->EndJG() && + ii >= this->StartIG() && ii < this->EndIG() && + kk >= this->StartKG() && kk < this->EndKG()) { + atGhost = true; + dir = "ju"; + type = 4; + // at ku - k in ghost cell range, i/j in physical cells + } else if (kk >= this->EndK() && kk < this->EndKG() && + jj >= this->StartJG() && jj < this->EndJG() && + ii >= this->StartIG() && ii < this->EndIG()) { + atGhost = true; + dir = "ku"; + type = 6; + } + + return atGhost; +} + -/* Function to swap ghost cells between two blocks at an interblock +/* 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 @@ -3503,34 +3657,44 @@ Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 | | The above diagram shows the resulting values after the ghost cell swap. The -logic ensures that the ghost cells at the interblock boundary exactly match +logic ensures that the ghost cells at the connection boundary exactly match their partner block as if there were no separation in the grid. */ -void procBlock::SwapStateSlice(const interblock &inter, procBlock &blk) { - // inter -- interblock boundary information - // blk -- second block involved in interblock boundary +void procBlock::SwapStateSlice(const connection &inter, procBlock &blk) { + // inter -- connection boundary information + // blk -- second block involved in connection boundary state_.SwapSlice(inter, blk.state_); } -void procBlock::SwapTurbSlice(const interblock &inter, procBlock &blk) { - // inter -- interblock boundary information - // blk -- second block involved in interblock boundary +void procBlock::SwapTurbSlice(const connection &inter, procBlock &blk) { + // inter -- connection boundary information + // blk -- second block involved in connection boundary - eddyViscosity_.SwapSlice(inter, blk.eddyViscosity_); f1_.SwapSlice(inter, blk.f1_); f2_.SwapSlice(inter, blk.f2_); } -void procBlock::SwapGradientSlice(const interblock &inter, procBlock &blk) { - // inter -- interblock boundary information - // blk -- second block involved in interblock boundary +void procBlock::SwapWallDistSlice(const connection &inter, procBlock &blk) { + // inter -- connection boundary information + // blk -- second block involved in connection boundary + + wallDist_.SwapSlice(inter, blk.wallDist_); +} + +void procBlock::SwapEddyViscAndGradientSlice(const connection &inter, + procBlock &blk) { + // inter -- connection boundary information + // blk -- second block involved in connection boundary 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_); } @@ -3541,28 +3705,34 @@ void procBlock::SwapGradientSlice(const interblock &inter, procBlock &blk) { function, but is called when the neighboring procBlocks are on different processors. */ -void procBlock::SwapStateSliceMPI(const interblock &inter, const int &rank, +void procBlock::SwapStateSliceMPI(const connection &inter, const int &rank, const MPI_Datatype &MPI_cellData) { - // inter -- interblock boundary information + // inter -- connection boundary information // rank -- processor rank // MPI_cellData -- MPI datatype for passing primVars, genArray state_.SwapSliceMPI(inter, rank, MPI_cellData); } -void procBlock::SwapTurbSliceMPI(const interblock &inter, const int &rank) { - // inter -- interblock boundary information +void procBlock::SwapTurbSliceMPI(const connection &inter, const int &rank) { + // inter -- connection boundary information // rank -- processor rank - eddyViscosity_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 1); f1_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 2); f2_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 3); } -void procBlock::SwapGradientSliceMPI(const interblock &inter, const int &rank, - const MPI_Datatype &MPI_tensorDouble, - const MPI_Datatype &MPI_vec3d) { - // inter -- interblock boundary information +void procBlock::SwapWallDistSliceMPI(const connection &inter, const int &rank) { + // inter -- connection boundary information + // rank -- processor rank + + wallDist_.SwapSliceMPI(inter, rank, MPI_DOUBLE, 1); +} + +void procBlock::SwapEddyViscAndGradientSliceMPI( + const connection &inter, const int &rank, + const MPI_Datatype &MPI_tensorDouble, const MPI_Datatype &MPI_vec3d) { + // inter -- connection boundary information // rank -- processor rank if (isViscous_) { @@ -3570,6 +3740,9 @@ void procBlock::SwapGradientSliceMPI(const interblock &inter, const int &rank, temperatureGrad_.SwapSliceMPI(inter, rank, MPI_vec3d, 2); } 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); } @@ -3577,11 +3750,11 @@ void procBlock::SwapGradientSliceMPI(const interblock &inter, const int &rank, /* Member function to overwrite a section of a procBlock's geometry with a -geomSlice. The function uses the orientation supplied in the interblock to +geomSlice. The function uses the orientation supplied in the connection to orient the geomSlice relative to the procBlock. It assumes that the procBlock -is listed first, and the geomSlice second in the interblock data structure. +is listed first, and the geomSlice second in the connection data structure. It returns a vector of 4 bools that are returned true if one of the 4 edges -of the interblock need to be updated because they border an interblock, +of the connection need to be updated because they border an connection, creating a possible "t" intersection. __________ _________ | | | | | | @@ -3596,8 +3769,8 @@ creating a possible "t" intersection. The block configuration shown above shows a "t"intersection. If blocks 0/1 are swapped first, block 1 gets all of its ghost cells including the edge cells -(marked X) from block 0, but block 0 knows that the interblock swapping with -block 1 borders another interblock (the one swapping with block 2), so it does +(marked X) from block 0, but block 0 knows that the connection swapping with +block 1 borders another connection (the one swapping with block 2), so it does not take the edge ghost cells from block 1. This is because the ghost cells that the edge of block 1 would supply will be supplied by the swap with block 2. If next, blocks 1/2 swap, block 1 now has garbage in its edge ghost cells. This is @@ -3614,13 +3787,13 @@ block 0 are not overwritten with the garbage ghost cells from block 2. The way this is enforced is the following. Initially all ghost cell volumes are initialized to 0. Therefore, if a cell from a geomSlice with a volume of 0 is trying to be inserted into the procBlock, this cell has not been given its proper -boundary conditions and should be ignored. Subsequently, the interblock should be +boundary conditions and should be ignored. Subsequently, the connection should be updated so that in the future this cell is not inserted. */ -vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, +vector procBlock::PutGeomSlice(const geomSlice &slice, connection &inter, const int &d3) { // slice -- geomSlice to insert int procBlock - // inter -- interblock data structure describing the patches and their + // inter -- connection data structure describing the patches and their // orientation // d3 -- distance of direction normal to patch to insert @@ -3637,7 +3810,7 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, exit(EXIT_FAILURE); } - // adjust insertion indices if patch borders another interblock on the same + // 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; @@ -3667,7 +3840,7 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, // its ghost value yet (needed at "t" intersection) if (slice.Vol(indS[0], indS[1], indS[2]) == 0.0) { // find out if on edge, if so save edge - // at a block edge -- possible need to adjust interblock + // at a block edge -- possible need to adjust connection string edgeDir = "undefined"; if (this->AtEdgeInclusive(indB[0], indB[1], indB[2], edgeDir)) { auto dir1 = 0; @@ -3684,7 +3857,7 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, } // find out edge direction - // edge direction matches interblock direction 1 + // edge direction matches connection direction 1 if (edgeDir == inter.Direction1First()) { // adjust edge on lower dir2 side if (indB[dir2] < inter.Dir2StartFirst() + numGhosts_) { @@ -3692,7 +3865,7 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, } else { // adjust edge on upper dir2 side adjEdge[3] = true; } - // edge direction matches interblock direction 2 + // edge direction matches connection direction 2 } else if (edgeDir == inter.Direction2First()) { // adjust edge on lower dir1 side if (indB[dir1] < inter.Dir1StartFirst() + numGhosts_) { @@ -3702,7 +3875,7 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, } } else { cerr << "ERROR: Error in procBlock::PutGeomSlice(). Ghost cell " - "edge direction does not match interblock direction 1 or " + "edge direction does not match connection direction 1 or " "2." << endl; cerr << "Edge direction is " << edgeDir << ", direction 1 is " << inter.Direction1First() << ", and direction 2 is " @@ -4475,15 +4648,15 @@ vector procBlock::PutGeomSlice(const geomSlice &slice, interblock &inter, } /* Member function to overwrite a section of a procBlock's states with a -slice of states. The function uses the orientation supplied in the interblock to +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 interblock data structure. +is listed first, and the slice second in the connection data structure. */ void procBlock::PutStateSlice(const multiArray3d &slice, - const interblock &inter, + const connection &inter, const int &d3, const int &numG) { // slice -- slice to insert in procBlock - // inter -- interblock data structure defining the patches and their + // inter -- connection data structure defining the patches and their // orientation // d3 -- distance of direction normal to patch to insert // numG -- number of ghost cells @@ -4495,10 +4668,12 @@ void procBlock::PutStateSlice(const multiArray3d &slice, * processor. */ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_vec3dMag) const { + const MPI_Datatype &MPI_vec3dMag, + const MPI_Datatype &MPI_wallData) const { // 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_vec3dMag -- MPI data type for a wallData // determine size of buffer to send auto sendBufSize = 0; @@ -4507,7 +4682,7 @@ 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(4, MPI_CXX_BOOL, MPI_COMM_WORLD, + MPI_Pack_size(5, 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, @@ -4550,15 +4725,21 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, auto stringSize = 0; for (auto jj = 0; jj < bc_.NumSurfaces(); jj++) { - MPI_Pack_size( - bc_.GetBCTypes(jj).size() + 1, MPI_CHAR, MPI_COMM_WORLD, - &tempSize); // add size for bc_ types (+1 for c_str end character) + // add size for bc_ types (+1 for c_str end character) + MPI_Pack_size(bc_.GetBCTypes(jj).size() + 1, MPI_CHAR, MPI_COMM_WORLD, + &tempSize); stringSize += tempSize; } sendBufSize += stringSize; + for (auto &wd : wallData_) { + wd.PackSize(sendBufSize, MPI_wallData); + } + // allocate buffer to pack data into - auto *sendBuffer = new char[sendBufSize]; + // use unique_ptr to manage memory; use underlying pointer with MPI calls + auto unqSendBuffer = unique_ptr(new char[sendBufSize]); + auto *sendBuffer = unqSendBuffer.get(); const auto numI = this->NumI(); const auto numJ = this->NumJ(); @@ -4587,6 +4768,8 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, MPI_COMM_WORLD); MPI_Pack(&isTurbulent_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&isRANS_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); MPI_Pack(&storeTimeN_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&isMultiLevelTime_, 1, MPI_CXX_BOOL, sendBuffer, sendBufSize, @@ -4617,30 +4800,39 @@ void procBlock::PackSendGeomMPI(const MPI_Datatype &MPI_cellData, // pack boundary condition data bc_.PackBC(sendBuffer, sendBufSize, position); + // pack wall data + for (auto &wd : wallData_) { + wd.PackWallData(sendBuffer, sendBufSize, position, MPI_wallData); + } + // send buffer to appropriate processor MPI_Send(sendBuffer, sendBufSize, MPI_PACKED, rank_, 2, MPI_COMM_WORLD); - - delete[] sendBuffer; // deallocate buffer } void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_vec3dMag) { + 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 // probe message to get correct data size auto recvBufSize = 0; MPI_Probe(ROOTP, 2, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_CHAR, &recvBufSize); // use MPI_CHAR because - // sending buffer was - // allocated with chars + // use MPI_CHAR because sending buffer was allocated with chars + MPI_Get_count(&status, MPI_CHAR, &recvBufSize); - auto *recvBuffer = new char[recvBufSize]; // allocate buffer of correct size + // allocate buffer of correct size + // use unique_ptr to manage memory; use underlying pointer with MPI + auto unqRecvBuffer = unique_ptr(new char[recvBufSize]); + auto *recvBuffer = unqRecvBuffer.get(); // receive message from ROOT MPI_Recv(recvBuffer, recvBufSize, MPI_PACKED, ROOTP, 2, MPI_COMM_WORLD, @@ -4671,6 +4863,8 @@ void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, MPI_CXX_BOOL, MPI_COMM_WORLD); MPI_Unpack(recvBuffer, recvBufSize, &position, &isTurbulent_, 1, MPI_CXX_BOOL, MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &isRANS_, 1, + MPI_CXX_BOOL, MPI_COMM_WORLD); MPI_Unpack(recvBuffer, recvBufSize, &position, &storeTimeN_, 1, MPI_CXX_BOOL, MPI_COMM_WORLD); MPI_Unpack(recvBuffer, recvBufSize, &position, &isMultiLevelTime_, 1, @@ -4702,13 +4896,13 @@ void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, MPI_COMM_WORLD); // unpack face area K MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(fCenterI_)), fCenterI_.Size(), MPI_vec3d, - MPI_COMM_WORLD); // unpack face center_ I + MPI_COMM_WORLD); // unpack face center I MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(fCenterJ_)), fCenterJ_.Size(), MPI_vec3d, - MPI_COMM_WORLD); // unpack face center_ J + MPI_COMM_WORLD); // unpack face center J MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(fCenterK_)), fCenterK_.Size(), MPI_vec3d, - MPI_COMM_WORLD); // unpack face center_ K + MPI_COMM_WORLD); // unpack face center K MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(vol_)), vol_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack volumes @@ -4716,7 +4910,11 @@ void procBlock::RecvUnpackGeomMPI(const MPI_Datatype &MPI_cellData, // unpack boundary conditions bc_.UnpackBC(recvBuffer, recvBufSize, position); - delete[] recvBuffer; // deallocate receiving buffer + // unpack wall data + wallData_.resize(bc_.NumViscousSurfaces()); + for (auto &wd : wallData_) { + wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_wallData, inp); + } } /*Member function to zero and resize the vectors in a procBlock to their @@ -4735,6 +4933,7 @@ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, if (isMultiLevelTime_) { consVarsNm1_.ClearResize(numI, numJ, numK, 0); } + center_.ClearResize(numI, numJ, numK, numGhosts); vol_.ClearResize(numI, numJ, numK, numGhosts); @@ -4747,6 +4946,10 @@ 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); + wallDist_.ClearResize(numI, numJ, numK, numGhosts, DEFAULTWALLDIST); residual_.ClearResize(numI, numJ, numK, 0); @@ -4762,9 +4965,12 @@ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, } if (isTurbulent_) { + eddyViscosity_.ClearResize(numI, numJ, numK, numGhosts); + } + + if (isRANS_) { tkeGrad_.ClearResize(numI, numJ, numK, numGhosts); omegaGrad_.ClearResize(numI, numJ, numK, numGhosts); - eddyViscosity_.ClearResize(numI, numJ, numK, numGhosts); f1_.ClearResize(numI, numJ, numK, numGhosts); f2_.ClearResize(numI, numJ, numK, numGhosts); } @@ -4775,11 +4981,15 @@ void procBlock::CleanResizeVecs(const int &numI, const int &numJ, void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_tensorDouble) { + 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 @@ -4791,8 +5001,10 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, MPI_Get_count(&status, MPI_CHAR, &recvBufSize); // use MPI_CHAR because // sending buffer was // allocated with chars - - auto *recvBuffer = new char[recvBufSize]; // allocate buffer of correct size + // allocate buffer of correct size + // use unique_ptr to manage memory; use underlying pointer for MPI calls + auto unqRecvBuffer = unique_ptr(new char[recvBufSize]); + auto *recvBuffer = unqRecvBuffer.get(); // receive message from non-ROOT MPI_Recv(recvBuffer, recvBufSize, MPI_PACKED, rank_, @@ -4814,6 +5026,15 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(dt_)), dt_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack time steps + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(cellWidthI_)), + cellWidthI_.Size(), MPI_DOUBLE, + MPI_COMM_WORLD); // unpack cell width I + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(cellWidthJ_)), + cellWidthJ_.Size(), MPI_DOUBLE, + MPI_COMM_WORLD); // unpack cell width J + MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(cellWidthK_)), + cellWidthK_.Size(), MPI_DOUBLE, + MPI_COMM_WORLD); // unpack cell width K MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(wallDist_)), wallDist_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack wall distance @@ -4840,6 +5061,9 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(eddyViscosity_)), eddyViscosity_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack eddy viscosity + } + + if (isRANS_) { MPI_Unpack(recvBuffer, recvBufSize, &position, &(*std::begin(f1_)), f1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD); // unpack blending variable f1 @@ -4854,7 +5078,11 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, MPI_COMM_WORLD); // unpack omega gradient } - delete[] recvBuffer; // deallocate receiving buffer + // unpack wall data + wallData_.resize(bc_.NumViscousSurfaces()); + for (auto &wd : wallData_) { + wd.UnpackWallData(recvBuffer, recvBufSize, position, MPI_wallData, inp); + } } /*Member function to pack and send procBlock state data to the ROOT proecessor. @@ -4863,11 +5091,13 @@ void procBlock::RecvUnpackSolMPI(const MPI_Datatype &MPI_cellData, void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, const MPI_Datatype &MPI_uncoupledScalar, const MPI_Datatype &MPI_vec3d, - const MPI_Datatype &MPI_tensorDouble) const { + const MPI_Datatype &MPI_tensorDouble, + const MPI_Datatype &MPI_wallData) const { // 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 // determine size of buffer to send auto sendBufSize = 0; @@ -4886,6 +5116,15 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, MPI_Pack_size(dt_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for time steps sendBufSize += tempSize; + MPI_Pack_size(cellWidthI_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, + &tempSize); // add size for cell width I + sendBufSize += tempSize; + MPI_Pack_size(cellWidthJ_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, + &tempSize); // add size for cell width J + sendBufSize += tempSize; + MPI_Pack_size(cellWidthK_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, + &tempSize); // add size for cell width K + sendBufSize += tempSize; MPI_Pack_size(wallDist_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for wall distance sendBufSize += tempSize; @@ -4912,6 +5151,9 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, MPI_Pack_size(eddyViscosity_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for eddy viscosity sendBufSize += tempSize; + } + + if (isRANS_) { MPI_Pack_size(f1_.Size(), MPI_DOUBLE, MPI_COMM_WORLD, &tempSize); // add size for blending variable f1 sendBufSize += tempSize; @@ -4926,9 +5168,14 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, sendBufSize += tempSize; } + for (auto &wd : wallData_) { + wd.PackSize(sendBufSize, MPI_wallData); + } - auto *sendBuffer = new char[sendBufSize]; // allocate buffer to pack data - // into + // allocate buffer to pack data into + // use unique_ptr to manage memory; use underlying pointer for MPI calls + auto unqSendBuffer = unique_ptr(new char[sendBufSize]); + auto *sendBuffer = unqSendBuffer.get(); // pack data to send into buffer auto position = 0; @@ -4942,6 +5189,12 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&(*std::begin(dt_)), dt_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(cellWidthI_)), cellWidthI_.Size(), MPI_DOUBLE, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(cellWidthJ_)), cellWidthJ_.Size(), MPI_DOUBLE, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + MPI_Pack(&(*std::begin(cellWidthK_)), cellWidthK_.Size(), MPI_DOUBLE, + sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&(*std::begin(wallDist_)), wallDist_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&(*std::begin(specRadius_)), specRadius_.Size(), MPI_uncoupledScalar, @@ -4962,6 +5215,9 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, if (isTurbulent_) { MPI_Pack(&(*std::begin(eddyViscosity_)), eddyViscosity_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); + } + + if (isRANS_) { MPI_Pack(&(*std::begin(f1_)), f1_.Size(), MPI_DOUBLE, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); MPI_Pack(&(*std::begin(f2_)), f2_.Size(), MPI_DOUBLE, @@ -4972,11 +5228,14 @@ void procBlock::PackSendSolMPI(const MPI_Datatype &MPI_cellData, sendBuffer, sendBufSize, &position, MPI_COMM_WORLD); } + // pack wall data + for (auto &wd : wallData_) { + wd.PackWallData(sendBuffer, sendBufSize, position, MPI_wallData); + } + // send buffer to appropriate processor MPI_Send(sendBuffer, sendBufSize, MPI_PACKED, ROOTP, globalPos_, MPI_COMM_WORLD); - - delete[] sendBuffer; // deallocate buffer } /* Member function to split a procBlock along a plane defined by a direction and @@ -4989,10 +5248,11 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, // ind -- index (face) to split at (w/o counting ghost cells) // num -- new block number // alteredSurf -- vector of surfaces whose partners will need to be altered - // after this split + // after this split auto bound1 = bc_; auto bound2 = bound1.Split(dir, ind, parBlock_, num, alteredSurf); + auto wd2 = this->SplitWallData(dir, ind); auto numI1 = 0, numI2 = 0; auto numJ1 = 0, numJ2 = 0; @@ -5025,9 +5285,9 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, } procBlock blk1(numI1, numJ1, numK1, numGhosts_, isViscous_, isTurbulent_, - storeTimeN_, isMultiLevelTime_); + isRANS_, storeTimeN_, isMultiLevelTime_); procBlock blk2(numI2, numJ2, numK2, numGhosts_, isViscous_, isTurbulent_, - storeTimeN_, isMultiLevelTime_); + isRANS_, storeTimeN_, isMultiLevelTime_); blk1.parBlock_ = parBlock_; blk2.parBlock_ = parBlock_; @@ -5040,6 +5300,12 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk1.vol_.Fill(vol_.Slice(dir, {vol_.Start(dir), blk1.vol_.End(dir)})); blk1.center_.Fill(center_.Slice(dir, {center_.Start(dir), blk1.center_.End(dir)})); + blk1.cellWidthI_.Fill(cellWidthI_.Slice(dir, {cellWidthI_.Start(dir), + blk1.cellWidthI_.End(dir)})); + blk1.cellWidthJ_.Fill(cellWidthJ_.Slice(dir, {cellWidthJ_.Start(dir), + blk1.cellWidthJ_.End(dir)})); + blk1.cellWidthK_.Fill(cellWidthK_.Slice(dir, {cellWidthK_.Start(dir), + blk1.cellWidthK_.End(dir)})); blk1.wallDist_.Fill(wallDist_.Slice(dir, {wallDist_.Start(dir), blk1.wallDist_.End(dir)})); blk1.temperature_.Fill(temperature_.Slice(dir, {temperature_.Start(dir), @@ -5052,6 +5318,8 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk1.eddyViscosity_.Fill( eddyViscosity_.Slice(dir, {eddyViscosity_.Start(dir), blk1.eddyViscosity_.End(dir)})); + } + if (isRANS_) { blk1.f1_.Fill(f1_.Slice(dir, {f1_.Start(dir), blk1.f1_.End(dir)})); blk1.f2_.Fill(f2_.Slice(dir, {f2_.Start(dir), blk1.f2_.End(dir)})); } @@ -5069,7 +5337,7 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, temperatureGrad_.Slice(dir, {temperatureGrad_.Start(dir), blk1.temperatureGrad_.End(dir)})); } - if (isTurbulent_) { + if (isRANS_) { blk1.tkeGrad_.Fill(tkeGrad_.Slice(dir, {tkeGrad_.Start(dir), blk1.tkeGrad_.End(dir)})); blk1.omegaGrad_.Fill(omegaGrad_.Slice(dir, {omegaGrad_.Start(dir), @@ -5097,6 +5365,9 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk2.state_.Fill(state_.Slice(dir, {ind, state_.End(dir)})); blk2.vol_.Fill(vol_.Slice(dir, {ind, vol_.End(dir)})); blk2.center_.Fill(center_.Slice(dir, {ind, center_.End(dir)})); + blk2.cellWidthI_.Fill(cellWidthI_.Slice(dir, {ind, cellWidthI_.End(dir)})); + blk2.cellWidthJ_.Fill(cellWidthJ_.Slice(dir, {ind, cellWidthJ_.End(dir)})); + blk2.cellWidthK_.Fill(cellWidthK_.Slice(dir, {ind, cellWidthK_.End(dir)})); blk2.wallDist_.Fill(wallDist_.Slice(dir, {ind, wallDist_.End(dir)})); blk2.temperature_.Fill(temperature_.Slice(dir, {ind, temperature_.End(dir)})); if (isViscous_) { @@ -5105,6 +5376,8 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, if (isTurbulent_) { blk2.eddyViscosity_.Fill(eddyViscosity_.Slice(dir, {ind, eddyViscosity_.End(dir)})); + } + if (isRANS_) { blk2.f1_.Fill(f1_.Slice(dir, {ind, f1_.End(dir)})); blk2.f2_.Fill(f2_.Slice(dir, {ind, f2_.End(dir)})); } @@ -5119,7 +5392,7 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, blk2.temperatureGrad_.Fill( temperatureGrad_.Slice(dir, {ind, temperatureGrad_.End(dir)})); } - if (isTurbulent_) { + if (isRANS_) { blk2.tkeGrad_.Fill(tkeGrad_.Slice(dir, {ind, tkeGrad_.End(dir)})); blk2.omegaGrad_.Fill(omegaGrad_.Slice(dir, {ind, omegaGrad_.End(dir)})); } @@ -5135,8 +5408,10 @@ procBlock procBlock::Split(const string &dir, const int &ind, const int &num, // assign boundary conditions blk1.bc_ = bound1; + blk1.wallData_ = wallData_; (*this) = blk1; blk2.bc_ = bound2; + blk2.wallData_ = wd2; return blk2; } @@ -5147,7 +5422,7 @@ void procBlock::Join(const procBlock &blk, const string &dir, // blk -- block to join with // dir -- plane to split along, either i, j, or k // alteredSurf -- vector of surfaces whose partners will need to be altered - // after this split + // after this join auto iTot = this->NumI(); auto jTot = this->NumJ(); @@ -5175,10 +5450,12 @@ void procBlock::Join(const procBlock &blk, const string &dir, } procBlock newBlk(iTot, jTot, kTot, numGhosts_, isViscous_, isTurbulent_, - storeTimeN_, isMultiLevelTime_); + isRANS_, storeTimeN_, isMultiLevelTime_); newBlk.bc_ = bc_; newBlk.bc_.Join(blk.bc_, dir, alteredSurf); + newBlk.wallData_ = wallData_; + newBlk.JoinWallData(blk.wallData_, dir); // assign variables from lower block ----------------------------- // assign cell variables with ghost cells @@ -5194,6 +5471,17 @@ void procBlock::Join(const procBlock &blk, const string &dir, center_.Slice(dir, {center_.Start(dir), center_.PhysEnd(dir)})); + newBlk.cellWidthI_.Insert(dir, {cellWidthI_.Start(dir), cellWidthI_.PhysEnd(dir)}, + cellWidthI_.Slice(dir, {cellWidthI_.Start(dir), + cellWidthI_.PhysEnd(dir)})); + newBlk.cellWidthJ_.Insert(dir, {cellWidthJ_.Start(dir), cellWidthJ_.PhysEnd(dir)}, + cellWidthJ_.Slice(dir, {cellWidthJ_.Start(dir), + cellWidthJ_.PhysEnd(dir)})); + newBlk.cellWidthK_.Insert(dir, {cellWidthK_.Start(dir), cellWidthK_.PhysEnd(dir)}, + cellWidthK_.Slice(dir, {cellWidthK_.Start(dir), + cellWidthK_.PhysEnd(dir)})); + + newBlk.wallDist_.Insert(dir, {wallDist_.Start(dir), wallDist_.PhysEnd(dir)}, wallDist_.Slice(dir, {wallDist_.Start(dir), wallDist_.PhysEnd(dir)})); @@ -5213,7 +5501,8 @@ void procBlock::Join(const procBlock &blk, const string &dir, eddyViscosity_.PhysEnd(dir)}, eddyViscosity_.Slice( dir, {eddyViscosity_.Start(dir), eddyViscosity_.PhysEnd(dir)})); - + } + if (isRANS_) { newBlk.f1_.Insert(dir, {f1_.Start(dir), f1_.PhysEnd(dir)}, f1_.Slice(dir, {f1_.Start(dir), f1_.PhysEnd(dir)})); newBlk.f2_.Insert(dir, {f2_.Start(dir), f2_.PhysEnd(dir)}, @@ -5243,7 +5532,7 @@ void procBlock::Join(const procBlock &blk, const string &dir, temperatureGrad_.Slice(dir, {temperatureGrad_.Start(dir), temperatureGrad_.PhysEnd(dir)})); } - if (isTurbulent_) { + if (isRANS_) { newBlk.tkeGrad_.Insert(dir, {tkeGrad_.Start(dir), tkeGrad_.PhysEnd(dir)}, tkeGrad_.Slice(dir, {tkeGrad_.Start(dir), tkeGrad_.PhysEnd(dir)})); @@ -5292,6 +5581,19 @@ void procBlock::Join(const procBlock &blk, const string &dir, blk.center_.Slice(dir, {blk.center_.PhysStart(dir), blk.center_.End(dir)})); + newBlk.cellWidthI_.Insert(dir, {cellWidthI_.PhysEnd(dir), + newBlk.cellWidthI_.End(dir)}, + blk.cellWidthI_.Slice(dir, {blk.cellWidthI_.PhysStart(dir), + blk.cellWidthI_.End(dir)})); + newBlk.cellWidthJ_.Insert(dir, {cellWidthJ_.PhysEnd(dir), + newBlk.cellWidthJ_.End(dir)}, + blk.cellWidthJ_.Slice(dir, {blk.cellWidthJ_.PhysStart(dir), + blk.cellWidthJ_.End(dir)})); + newBlk.cellWidthK_.Insert(dir, {cellWidthK_.PhysEnd(dir), + newBlk.cellWidthK_.End(dir)}, + blk.cellWidthK_.Slice(dir, {blk.cellWidthK_.PhysStart(dir), + blk.cellWidthK_.End(dir)})); + newBlk.wallDist_.Insert(dir, {wallDist_.PhysEnd(dir), newBlk.wallDist_.End(dir)}, blk.wallDist_.Slice(dir, {blk.wallDist_.PhysStart(dir), @@ -5313,7 +5615,8 @@ void procBlock::Join(const procBlock &blk, const string &dir, newBlk.eddyViscosity_.End(dir)}, blk.eddyViscosity_.Slice(dir, {blk.eddyViscosity_.PhysStart(dir), blk.eddyViscosity_.End(dir)})); - + } + if (isRANS_) { newBlk.f1_.Insert(dir, {f1_.PhysEnd(dir), newBlk.f1_.End(dir)}, blk.f1_.Slice(dir, {blk.f1_.PhysStart(dir), blk.f1_.End(dir)})); @@ -5349,7 +5652,7 @@ void procBlock::Join(const procBlock &blk, const string &dir, blk.temperatureGrad_.Slice(dir, {blk.temperatureGrad_.PhysStart(dir), blk.temperatureGrad_.End(dir)})); } - if (isTurbulent_) { + if (isRANS_) { newBlk.tkeGrad_.Insert(dir, {tkeGrad_.PhysEnd(dir), newBlk.tkeGrad_.End(dir)}, blk.tkeGrad_.Slice(dir, {blk.tkeGrad_.PhysStart(dir), @@ -5474,7 +5777,7 @@ void procBlock::CalcGradsI(const int &ii, const int &jj, const int &kk, temperature_(ii, jj, kk), tjl, tju, tkl, tku, ail, aiu, ajl, aju, akl, aku, vol); - if (isTurbulent_) { + if (isRANS_) { // calculate average tke on j and k faces of alternate control volume const auto tkeju = 0.25 * (state_(ii - 1, jj, kk).Tke() + state_(ii, jj, kk).Tke() + @@ -5596,7 +5899,7 @@ void procBlock::CalcGradsJ(const int &ii, const int &jj, const int &kk, temperature_(ii, jj, kk), tkl, tku, ail, aiu, ajl, aju, akl, aku, vol); - if (isTurbulent_) { + if (isRANS_) { // calculate average tke on i and k faces of alternate control volume const auto tkeiu = 0.25 * (state_(ii, jj - 1, kk).Tke() + state_(ii, jj, kk).Tke() + @@ -5718,7 +6021,7 @@ void procBlock::CalcGradsK(const int &ii, const int &jj, const int &kk, temperature_(ii, jj, kk), ail, aiu, ajl, aju, akl, aku, vol); - if (isTurbulent_) { + if (isRANS_) { // calculate average tke on i and j faces of alternate control volume const auto tkeiu = 0.25 * (state_(ii, jj, kk - 1).Tke() + state_(ii, jj, kk).Tke() + @@ -5776,6 +6079,7 @@ void procBlock::CalcSrcTerms(const sutherland &suth, 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), @@ -5784,7 +6088,8 @@ void procBlock::CalcSrcTerms(const sutherland &suth, omegaGrad_(ii, jj, kk), suth, vol_(ii, jj, kk), eddyViscosity_(ii, jj, kk), - f1_(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 @@ -5794,7 +6099,7 @@ void procBlock::CalcSrcTerms(const sutherland &suth, // 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), suth, - vol_(ii, jj, kk)); + vol_(ii, jj, kk), phi); specRadius_(ii, jj, kk).SubtractFromTurbVariable(turbSpecRad); // add contribution of source spectral radius to flux jacobian @@ -5814,15 +6119,57 @@ void procBlock::CalcSrcTerms(const sutherland &suth, // all cell centers void procBlock::CalcWallDistance(const kdtree &tree) { vector3d neighbor; + string surf = "none"; + auto type = 0; // loop over cells, including 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 should have negative wall distance so that wall distance - // at viscous face will be 0 during flux calculation - auto fac = this->IsPhysical(ii, jj, kk) ? 1.0 : -1.0; - wallDist_(ii, jj, kk) = fac * - tree.NearestNeighbor(center_(ii, jj, kk), neighbor); + // 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); + } else 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); + } 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); + } 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); + } 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); + } 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); + } 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); + } + } } } } @@ -5877,6 +6224,20 @@ multiArray3d procBlock::SliceState(const int &is, const int &ie, return state_.Slice({is, ie}, {js, je}, {ks, ke}); } +// member function to get a slice of the face centers of the cells on a +// boundary +multiArray3d> procBlock::SliceBoundaryCenters( + const int &surfInd) const { + const auto surf = bc_.GetSurface(surfInd); + if (surf.SurfaceType() <= 2) { // i-surface + return fCenterI_.Slice(surf.RangeI(), surf.RangeJ(), surf.RangeK()); + } else if (surf.SurfaceType() <= 4) { // j-surface + return fCenterJ_.Slice(surf.RangeI(), surf.RangeJ(), surf.RangeK()); + } else { // k-surface + return fCenterK_.Slice(surf.RangeI(), surf.RangeJ(), surf.RangeK()); + } +} + void procBlock::UpdateAuxillaryVariables(const idealGas &eos, const sutherland &suth, const bool includeGhosts) { @@ -5899,10 +6260,8 @@ void procBlock::UpdateUnlimTurbEddyVisc(const unique_ptr &turb, const bool &includeGhosts) { if (isTurbulent_) { for (auto kk = eddyViscosity_.StartK(); kk < eddyViscosity_.EndK(); kk++) { - for (auto jj = eddyViscosity_.StartJ(); jj < eddyViscosity_.EndJ(); - jj++) { - for (auto ii = eddyViscosity_.StartI(); ii < eddyViscosity_.EndI(); - ii++) { + for (auto jj = eddyViscosity_.StartJ(); jj < eddyViscosity_.EndJ(); jj++) { + for (auto ii = eddyViscosity_.StartI(); ii < eddyViscosity_.EndI(); ii++) { if (!this->AtCorner(ii, jj, kk) && (includeGhosts || this->IsPhysical(ii, jj, kk))) { eddyViscosity_(ii, jj, kk) = @@ -5914,6 +6273,64 @@ void procBlock::UpdateUnlimTurbEddyVisc(const unique_ptr &turb, } } +multiArray3d procBlock::GetGhostStates( + const multiArray3d &bndStates, const string &bcName, + const multiArray3d> &faceAreas, + const multiArray3d &wDist, const boundarySurface &surf, + const input &inp, const idealGas &eos, const sutherland &suth, + const unique_ptr &turb, const int layer) { + // bndStates -- states at cells adjacent to boundary + // bcName -- boundary condition type + // faceAreas -- face areas of boundary + // surf -- boundary surface + // inp -- input variables + // eos -- equation of state + // suth -- sutherland's law for viscosity + // turb -- turbulence model + // layer -- layer of ghost cell to return + // (1 closest to boundary, or 2 farthest) + + multiArray3d ghostStates( + bndStates.NumINoGhosts(), bndStates.NumJNoGhosts(), + bndStates.NumKNoGhosts(), bndStates.GhostLayers()); + 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, eos, suth, + turb, wVars, layer); + if (bcName == "viscousWall" && layer == 1) { + const auto ind = this->WallDataIndex(surf); + wallData_[ind](ii, jj, kk, true) = wVars; + } + } + } + } + return ghostStates; +} + +int procBlock::WallDataIndex(const boundarySurface &surf) const { + auto ind = -1; + for (auto ii = 0U; ii < wallData_.size(); ++ii) { + if (surf == wallData_[ii].Surface()) { + ind = ii; + break; + } + } + if (ind < 0) { + cerr << "ERROR. Given boundary surface does not match any in wallData" + << endl; + cerr << "Given boundary surface is: " << endl << surf << endl; + exit(EXIT_FAILURE); + } + return ind; +} + // member function to calculate the center to center distance across a cell face // projected along that face's area vector double procBlock::ProjC2CDist(const int &ii, const int &jj, const int &kk, @@ -5979,6 +6396,10 @@ void procBlock::DumpToFile(const string &var, const string &fName) const { outFile << velocityGrad_ << endl; } else if (var == "temperatureGradient") { outFile << temperatureGrad_ << endl; + } else if (var == "viscosity") { + outFile << viscosity_ << endl; + } else if (var == "eddyViscosity") { + outFile << eddyViscosity_ << endl; } else { cerr << "ERROR: Error in procBlock::DumpToFile(). Variable " << var << " is not supported!" << endl; @@ -5990,14 +6411,6 @@ void procBlock::DumpToFile(const string &var, const string &fName) const { } void procBlock::CalcCellWidths() { - // resize multiarrays - cellWidthI_.ClearResize(this->NumI(), this->NumJ(), this->NumK(), - this->NumGhosts()); - cellWidthJ_.ClearResize(this->NumI(), this->NumJ(), this->NumK(), - this->NumGhosts()); - cellWidthK_.ClearResize(this->NumI(), this->NumJ(), this->NumK(), - this->NumGhosts()); - // loop over all cells for (auto kk = this->StartKG(); kk < this->EndKG(); ++kk) { for (auto jj = this->StartJG(); jj < this->EndJG(); ++jj) { @@ -6014,101 +6427,59 @@ void procBlock::CalcCellWidths() { } -void procBlock::ReadSolFromRestart(ifstream &resFile, const input &inp, - const idealGas &eos, const sutherland &suth, - const unique_ptr &turb, - const vector &restartVars) { - // define reference speed of sound - const auto refSoS = inp.ARef(eos); +void procBlock::GetStatesFromRestart(const multiArray3d &restart) { + state_.Insert(restart.RangeI(), restart.RangeJ(), restart.RangeK(), restart); +} - // read the primative variables - // read dimensional variables -- 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++) { - genArray value; - // 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(); - } else if (var == "vel_x") { - resFile.read(reinterpret_cast(&value[1]), sizeof(value[1])); - value[1] /= refSoS; - } else if (var == "vel_y") { - resFile.read(reinterpret_cast(&value[2]), sizeof(value[2])); - value[2] /= refSoS; - } else if (var == "vel_z") { - resFile.read(reinterpret_cast(&value[3]), sizeof(value[3])); - value[3] /= refSoS; - } else if (var == "pressure") { - resFile.read(reinterpret_cast(&value[4]), sizeof(value[4])); - value[4] /= inp.RRef() * refSoS * refSoS; - } else if (var == "tke") { - resFile.read(reinterpret_cast(&value[5]), sizeof(value[5])); - value[5] /= refSoS * refSoS; - } else if (var == "sdr") { - resFile.read(reinterpret_cast(&value[6]), sizeof(value[6])); - value[6] /= refSoS * refSoS * inp.RRef() / suth.MuRef(); - } else { - cerr << "ERROR: Variable " << var - << " to read from restart file is not defined!" << endl; - exit(EXIT_FAILURE); - } - } - state_(ii, jj, kk) = primVars(value, true, eos, turb); - } - } +void procBlock::GetSolNm1FromRestart(const multiArray3d &restart) { + consVarsNm1_ = restart; +} + +// split all wallData in procBlock +// The calling instance keeps the lower wallData in the split, and the upper +// wallData is returned +vector procBlock::SplitWallData(const string &dir, const int &ind) { + vector upper; + vector delLower; + auto count = 0; + for (auto &lower : wallData_) { + auto split = false, low = false; + auto up = lower.Split(dir, ind, split, low); + if (split) { // surface split; upper and lower are valid + upper.push_back(up); + } else if (!low) { // not split; valid surface is upper + upper.push_back(up); + delLower.push_back(count); // need to remove b/c lower is invalid } + count++; + } - // Update temperature and viscosity - this->UpdateAuxillaryVariables(eos, suth, false); -} + // delete lower wall data not in lower split in reverse + for (auto ii = static_cast(delLower.size()) - 1; ii >= 0; --ii) { + wallData_.erase(std::begin(wallData_) + delLower[ii]); + } -void procBlock::ReadSolNm1FromRestart(ifstream &resFile, const input &inp, - const idealGas &eos, const sutherland &suth, - const unique_ptr &turb, - const vector &restartVars) { - // define reference speed of sound - const auto refSoS = inp.ARef(eos); + return upper; +} - // data is conserved variables - // read dimensional variables -- 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++) { - genArray value; - // 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(); - } else if (var == "vel_x") { // conserved var is rho-u - resFile.read(reinterpret_cast(&value[1]), sizeof(value[1])); - value[1] /= refSoS * inp.RRef(); - } else if (var == "vel_y") { // conserved var is rho-v - resFile.read(reinterpret_cast(&value[2]), sizeof(value[2])); - value[2] /= refSoS * inp.RRef(); - } else if (var == "vel_z") { // conserved var is rho-w - resFile.read(reinterpret_cast(&value[3]), sizeof(value[3])); - value[3] /= refSoS * inp.RRef(); - } else if (var == "pressure") { // conserved var is rho-E - resFile.read(reinterpret_cast(&value[4]), sizeof(value[4])); - value[4] /= inp.RRef() * refSoS * refSoS; - } else if (var == "tke") { // conserved var is rho-tke - resFile.read(reinterpret_cast(&value[5]), sizeof(value[5])); - value[5] /= refSoS * refSoS * inp.RRef(); - } else if (var == "sdr") { // conserved var is rho-sdr - resFile.read(reinterpret_cast(&value[6]), sizeof(value[6])); - value[6] /= refSoS * refSoS * inp.RRef() *inp.RRef() / suth.MuRef(); - } else { - cerr << "ERROR: Variable " << var - << " to read from restart file is not defined!" << endl; - exit(EXIT_FAILURE); - } - } - consVarsNm1_(ii, jj, kk) = value; +// Join all wallData in procBlock if possible. +void procBlock::JoinWallData(const vector &upper, const string &dir) { + vector joinedData; + for (auto ll = 0U; ll < wallData_.size(); ++ll) { + for (auto uu = 0U; uu < upper.size(); ++uu) { + auto joined = false; + wallData_[ll].Join(upper[uu], dir, joined); + if (joined) { // if joined, don't need to add upper data + joinedData.push_back(uu); } } } + + // add in unjoined upper data + for (auto ii = 0; ii < static_cast(upper.size()); ++ii) { + if (std::none_of(std::begin(joinedData), std::end(joinedData), + [&ii](const int &val) { return ii == val; })) { + wallData_.push_back(upper[ii]); + } + } } diff --git a/src/slices.cpp b/src/slices.cpp index 1c2593a..214ad13 100644 --- a/src/slices.cpp +++ b/src/slices.cpp @@ -17,7 +17,6 @@ #include #include "slices.hpp" #include "procBlock.hpp" -#include "boundaryConditions.hpp" // interblock #include "range.hpp" // range using std::cout; diff --git a/src/source.cpp b/src/source.cpp index c951275..ce0ae3c 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -53,7 +53,8 @@ squareMatrix source::CalcTurbSrc(const unique_ptr &turb, const vector3d &tkeGrad, const vector3d &omegaGrad, const sutherland &suth, const double &vol, - const double &mut, const double &f1) { + const double &mut, const double &f1, + const double &f2, const double &phi) { // turb -- turbulence model // state -- primative variables // velGrad -- velocity gradient @@ -64,12 +65,14 @@ squareMatrix source::CalcTurbSrc(const unique_ptr &turb, // vol -- cell volume // mut -- turbulent viscosity // f1 -- first blending coefficient + // f2 -- second blending coefficient + // phi -- factor to reduce tke destruction by for des // calculate turbulent source terms auto ksrc = 0.0; auto wsrc = 0.0; const auto srcJac = turb->CalcTurbSrc(state, velGrad, tkeGrad, omegaGrad, - suth, vol, mut, f1, ksrc, wsrc); + suth, vol, mut, f1, f2, phi, ksrc, wsrc); // assign turbulent source terms data_[5] = ksrc; diff --git a/src/turbulence.cpp b/src/turbulence.cpp index 1e7c17e..0877953 100644 --- a/src/turbulence.cpp +++ b/src/turbulence.cpp @@ -39,6 +39,11 @@ double turbModel::EddyViscNoLim(const primVars &state) const { return state.Rho() * state.Tke() / state.Omega(); } +// member function to return mean strain rate +tensor turbModel::MeanStrainRate(const tensor &vGrad) const { + return 0.5 * (vGrad + vGrad.Transpose()); +} + /* member function to calculate the Reynolds stress tensor using the Boussinesq approximation. @@ -82,9 +87,10 @@ double turbModel::ReynoldsStressDDotVelGrad(const primVars &state, // member function for destruction of tke // Dk = rho * k * w -double turbModel::TkeDestruction(const primVars &state) const { +double turbModel::TkeDestruction(const primVars &state, + const double &phi) const { // state -- primative variables - return state.Rho() * state.Tke() * state.Omega(); + return state.Rho() * state.Tke() * state.Omega() * phi; } // member function for destruction of omega @@ -252,22 +258,15 @@ squareMatrix turbModel::ViscousJacobian(const primVars &state, return squareMatrix(); } -// ------------------------------------------------------------------------- -// member functions for the turbNone class - -// member function to print out turbulence variables -void turbNone::Print() const { - cout << "No Turbulence Model" << endl; -} - // member function to calculate turbulence source terms -squareMatrix turbNone::CalcTurbSrc(const primVars &state, - const tensor &velGrad, - const vector3d &kGrad, - const vector3d &wGrad, - const sutherland &suth, const double &vol, - const double &turbVisc, const double &f1, - double &ksrc, double &wsrc) const { +squareMatrix turbModel::CalcTurbSrc(const primVars &state, + const tensor &velGrad, + const vector3d &kGrad, + const vector3d &wGrad, + const sutherland &suth, 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; @@ -276,12 +275,21 @@ squareMatrix turbNone::CalcTurbSrc(const primVars &state, return this->TurbSrcJac(state, 0.0, suth, vol); } -squareMatrix turbNone::TurbSrcJac(const primVars &state, const double &beta, - const sutherland &suth, - const double &vol) const { +squareMatrix turbModel::TurbSrcJac(const primVars &state, const double &beta, + const sutherland &suth, + const double &vol, + const double &phi) const { return squareMatrix(); } +// ------------------------------------------------------------------------- +// member functions for the turbNone class + +// member function to print out turbulence variables +void turbNone::Print() const { + cout << "No Turbulence Model" << endl; +} + squareMatrix turbNone::InviscidJacobian(const primVars &state, const unitVec3dMag &fArea, const bool &positive) const { @@ -315,11 +323,13 @@ squareMatrix turbNone::InviscidDissJacobian( // limiter double turbKWWilcox::EddyVisc(const primVars &state, const tensor &vGrad, - const sutherland &suth, const double &f2) const { + const sutherland &suth, const double &f2, + const double &length) const { // state -- primative variables // vGrad -- velocity gradient // suth -- sutherland's law for viscosity // f2 -- SST blending coefficient (not used in Wilcox K-W) + // length -- length scale (not used in Wilcox K-W) return state.Rho() * state.Tke() / this->OmegaTilda(state, vGrad, suth); } @@ -413,6 +423,7 @@ squareMatrix turbKWWilcox::CalcTurbSrc(const primVars &state, const sutherland &suth, const double &vol, const double &mut, const double &f1, + const double &f2, const double &width, double &ksrc, double &wsrc) const { // state -- primative variables // velGrad -- velocity gradient @@ -464,6 +475,7 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, const double &mu, const double &wallDist, const sutherland &suth, + const double &length, double &mut, double &f1, double &f2) const { // state -- primative variables @@ -473,6 +485,7 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, // mu -- laminar viscosity // walldist -- distance to nearest viscous wall // suth -- sutherland's law for viscosity + // length -- cell length scale // mut -- turbulent eddy viscosity // f1 -- first blending coefficient // f2 -- second blending coefficient @@ -481,7 +494,7 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, f2 = 0.0; // return eddy viscosity - mut = this->EddyVisc(state, velGrad, suth, f2); + mut = this->EddyVisc(state, velGrad, suth, f2, length); } @@ -496,7 +509,7 @@ void turbKWWilcox::EddyViscAndBlending(const primVars &state, */ double turbKWWilcox::SrcSpecRad(const primVars &state, const sutherland &suth, - const double &vol) const { + const double &vol, const double &phi) const { // state -- primative variables // suth -- sutherland's law for viscosity // vol -- cell volume @@ -508,11 +521,13 @@ double turbKWWilcox::SrcSpecRad(const primVars &state, squareMatrix turbKWWilcox::TurbSrcJac(const primVars &state, const double &beta, const sutherland &suth, - const double &vol) const { + const double &vol, + const double &phi) const { // state -- primative variables // beta -- destruction coefficient for omega equation // suth -- sutherland's law for viscosity // vol -- cell volume + // phi -- factor to reduce tke destruction for des squareMatrix jac(2); jac(0, 0) = -2.0 * betaStar_ * state.Omega() * vol * suth.InvNondimScaling(); @@ -593,6 +608,10 @@ double turbKWWilcox::ViscFaceSpecRad(const primVars &state, (mu + this->SigmaK(f1) * this->EddyViscNoLim(state)); } +double turbKWWilcox::TurbLengthScale(const primVars &state, + const sutherland &suth) const { + return sqrt(state.Tke()) / (betaStar_ * state.Omega()) * suth.NondimScaling(); +} // member function to print out turbulence variables void turbKWWilcox::Print() const { @@ -612,13 +631,15 @@ void turbKWWilcox::Print() const { // member function for eddy viscosity with limiter double turbKWSst::EddyVisc(const primVars &state, const tensor &vGrad, - const sutherland &suth, const double &f2) const { + const sutherland &suth, const double &f2, + const double &length) const { // state -- primative variables // vGrad -- velocity gradient // suth -- sutherland's law for viscosity // f2 -- SST blending coefficient + // length -- length scale (not used for SST) - const auto strainRate = 0.5 * (vGrad + vGrad.Transpose()); + const auto strainRate = this->MeanStrainRate(vGrad); // using DoubleDotTrans for speed // both tensors are symmetric so result is the same @@ -686,6 +707,7 @@ squareMatrix turbKWSst::CalcTurbSrc(const primVars &state, const vector3d &wGrad, const sutherland &suth, const double &vol, const double &mut, const double &f1, + const double &f2, const double &width, double &ksrc, double &wsrc) const { // state -- primative variables // velGrad -- velocity gradient @@ -745,6 +767,7 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, const double &mu, const double &wallDist, const sutherland &suth, + const double &length, double &mut, double &f1, double &f2) const { // state -- primative variables @@ -754,6 +777,7 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, // mu -- laminar viscosity // walldist -- distance to nearest viscous wall // suth -- sutherland's law for viscosity + // length -- length scale // mut -- turbulent eddy viscosity // f1 -- first blending coefficient // f2 -- second blending coefficient @@ -767,7 +791,7 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, f2 = this->F2(alpha1, alpha2); // return limited eddy viscosity - mut = this->EddyVisc(state, velGrad, suth, f2); + mut = this->EddyVisc(state, velGrad, suth, f2, length); } @@ -782,7 +806,7 @@ void turbKWSst::EddyViscAndBlending(const primVars &state, */ double turbKWSst::SrcSpecRad(const primVars &state, const sutherland &suth, - const double &vol) const { + const double &vol, const double &phi) const { // state -- primative variables // suth -- sutherland's law for viscosity @@ -793,14 +817,17 @@ double turbKWSst::SrcSpecRad(const primVars &state, squareMatrix turbKWSst::TurbSrcJac(const primVars &state, const double &beta, const sutherland &suth, - const double &vol) const { + const double &vol, + const double &phi) const { // state -- primative variables // beta -- destruction coefficient for omega equation // suth -- sutherland's law for viscosity // vol -- cell volume + // phi -- factor to reduce tke destruction for des squareMatrix jac(2); - jac(0, 0) = -2.0 * betaStar_ * state.Omega() * vol * suth.InvNondimScaling(); + jac(0, 0) = -2.0 * betaStar_ * state.Omega() * phi * vol * + suth.InvNondimScaling(); jac(1, 1) = -2.0 * beta * state.Omega() * vol * suth.InvNondimScaling(); // return jacobian scaled for nondimensional equations @@ -829,7 +856,7 @@ squareMatrix turbKWSst::ViscousJacobian(const primVars &state, (mu + this->SigmaK(f1) * mut); jacobian(1, 1) = fArea.Mag() * suth.NondimScaling() / (dist * state.Rho()) * (mu + this->SigmaW(f1) * mut); - + return jacobian; } @@ -874,6 +901,11 @@ double turbKWSst::ViscFaceSpecRad(const primVars &state, (mu + this->SigmaK(f1) * mut); } +double turbKWSst::TurbLengthScale(const primVars &state, + const sutherland &suth) const { + return sqrt(state.Tke()) / (betaStar_ * state.Omega()) * suth.NondimScaling(); +} + // member function to print out turbulence variables void turbKWSst::Print() const { cout << "Eddy Viscosity Method: " << this->EddyViscMethod() << endl; @@ -892,3 +924,143 @@ void turbKWSst::Print() const { cout << "Beta2: " << beta2_ << endl; cout << "Gamma2: " << gamma2_ << endl; } + +double turbSstDes::Phi(const primVars &state, const double &cdes, + const double &width, const double &f2, + const sutherland &suth) const { + return std::max((1.0 - f2) * this->TurbLengthScale(state, suth) / + (cdes * width), 1.0); +} + +// member function to calculate turbulence source terms and source jacobian +squareMatrix turbSstDes::CalcTurbSrc(const primVars &state, + const tensor &velGrad, + const vector3d &kGrad, + const vector3d &wGrad, + const sutherland &suth, const double &vol, + const double &mut, const double &f1, + const double &f2, const double &width, + double &ksrc, double &wsrc) const { + // state -- primative variables + // velGrad -- velocity gradient + // kGrad -- tke gradient + // wGrad -- omega gradient + // suth -- sutherland's law + // vol -- cell volume + // mut -- turbulent viscosity + // f1 -- first blending coefficient + // ksrc -- source term for tke equation + // wsrc -- source term for omega equation + + // calculate cross diffusion coefficient + const auto cdkw = this->CDkw(state, kGrad, wGrad); + + // calculate blended coefficients + const auto gamma = this->BlendedCoeff(this->Gamma1(), this->Gamma2(), f1); + const auto beta = this->BlendedCoeff(this->Beta1(), this->Beta2(), f1); + const auto cdes = this->BlendedCoeff(cdes1_, cdes2_, f1); + + // calculate tke destruction + const auto phi = this->Phi(state, cdes, width, f2, suth); + const auto tkeDest = suth.InvNondimScaling() * this->TkeDestruction(state, phi); + + // calculate omega destruction + const auto omgDest = suth.InvNondimScaling() * beta * + this->OmegaDestruction(state); + + // calculate tke production + auto tkeProd = min(suth.NondimScaling() * + this->ReynoldsStressDDotVelGrad(state, velGrad, suth, mut), + this->TkeProd2DestRatio() * tkeDest); + tkeProd = max(tkeProd, 0.0); + + // calculate omega production + auto omgProd = gamma * state.Rho() / mut * tkeProd; + omgProd = max(omgProd, 0.0); + + // calculate omega cross diffusion + // Using CDkw instead of whole cross diffusion term + // Both Loci/CHEM and SU2 use this implementation + const auto omgCd = suth.NondimScaling() * (1.0 - f1) * cdkw; + + // assign source term values + ksrc = tkeProd - tkeDest; + wsrc = omgProd - omgDest + omgCd; + + // return spectral radius of source jacobian + return this->TurbSrcJac(state, beta, suth, vol, phi); +} + + +double turbSstDes::SrcSpecRad(const primVars &state, + const sutherland &suth, + const double &vol, const double &phi) const { + // state -- primative variables + // suth -- sutherland's law for viscosity + + // return spectral radius scaled for nondimensional equations + auto beta = this->Beta2(); // using beta2 b/c it is larger than beta1 + auto jac = this->TurbSrcJac(state, beta, suth, vol, phi); + return -1.0 * jac.MaxAbsValOnDiagonal(); +} + + +// member function to print out turbulence variables +void turbSstDes::Print() const { + cout << "Eddy Viscosity Method: " << this->EddyViscMethod() << endl; + cout << "A1: " << this->A1() << endl; + cout << "Beta*: " << this->BetaStar() << endl; + cout << "Turbulent Prandtl Number: " << this->TurbPrandtlNumber() << endl; + cout << "Production to Destruction Ratio: " << this->TkeProd2DestRatio() + << endl; + + cout << "Sigma K1: " << this->SigmaK1() << endl; + cout << "Sigma W1: " << this->SigmaW1() << endl; + cout << "Beta1: " << this->Beta1() << endl; + cout << "Gamma1: " << this->Gamma1() << endl; + cout << "CDES1: " << this->CDes1() << endl; + + cout << "Sigma K2: " << this->SigmaK2() << endl; + cout << "Sigma W2: " << this->SigmaW2() << endl; + cout << "Beta2: " << this->Beta2() << endl; + cout << "Gamma2: " << this->Gamma2() << endl; + cout << "CDES2: " << this->CDes2() << endl; +} + +// member function to print out turbulence variables +void turbWale::Print() const { + cout << "Eddy Viscosity Method: " << this->EddyViscMethod() << endl; + cout << "Cw: " << this->Cw() << endl; +} + +// member function to determine eddy viscosity +double turbWale::EddyVisc(const primVars &state, const tensor &vGrad, + const sutherland &suth, const double &f2, + const double &length) const { + // state -- primative variables + // vGrad -- velocity gradient + // suth -- sutherland's law for viscosity + // f2 -- SST blending coefficient (not used in WALE) + // length -- cell length + + const auto strainRate = this->MeanStrainRate(vGrad); + const auto sigmaD = this->SigmaD(vGrad); + const auto sigmaDDoubleDot = sigmaD.DoubleDotTrans(sigmaD); + + const auto velGradTerm = pow(sigmaDDoubleDot, 1.5) / + (pow(strainRate.DoubleDotTrans(strainRate), 2.5) + + pow(sigmaDDoubleDot, 1.25) + EPS); + + const auto lengthScale = pow(cw_ * length, 2.0); + + return lengthScale * velGradTerm; +} + +tensor turbWale::SigmaD(const tensor &vGrad) const { + const auto vGradSq = vGrad.MatMult(vGrad); + + tensor I; + I.Identity(); + + return 0.5 * (vGradSq + vGradSq.Transpose()) - 1.0 / 3.0 * I * vGradSq.Trace(); +} diff --git a/src/utility.cpp b/src/utility.cpp index 24db66a..66b447a 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -185,7 +185,7 @@ vector3d ScalarGradGG( return temp; } -/* Function to swap ghost cell geometry between two blocks at an interblock +/* Function to swap ghost cell geometry 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 @@ -201,17 +201,17 @@ Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 Ui-3/2 Ui-1/2 | Uj+1/2 Uj+3/2 | | The above diagram shows the resulting values after the ghost cell swap. The -logic ensures that the ghost cells at the interblock boundary exactly match +logic ensures that the ghost cells at the connection boundary exactly match their partner block as if there were no separation in the grid. Only 3 faces at each ghost cell need to be swapped (i.e. the lower face for Ui is the upper face for Ui-1). At the end of a line (i-line, j-line or k-line), both the upper and lower faces need to be swapped. */ -void SwapGeomSlice(interblock &inter, procBlock &blk1, procBlock &blk2) { - // inter -- interblock boundary information - // blk1 -- first block involved in interblock boundary - // blk2 -- second block involved in interblock boundary +void SwapGeomSlice(connection &inter, procBlock &blk1, procBlock &blk2) { + // inter -- connection boundary information + // blk1 -- first block involved in connection boundary + // blk2 -- second block involved in connection boundary // Get indices for slice coming from first block to swap auto is1 = 0, ie1 = 0; @@ -230,19 +230,19 @@ void SwapGeomSlice(interblock &inter, procBlock &blk1, procBlock &blk2) { const auto geom1 = geomSlice(blk1, {is1, ie1}, {js1, je1}, {ks1, ke1}); const auto geom2 = geomSlice(blk2, {is2, ie2}, {js2, je2}, {ks2, ke2}); - // change interblocks to work with slice and ghosts - interblock inter1 = inter; - interblock inter2 = inter; + // change connections to work with slice and ghosts + connection inter1 = inter; + connection inter2 = inter; inter1.AdjustForSlice(false, blk1.NumGhosts()); inter2.AdjustForSlice(true, blk2.NumGhosts()); // put slices in proper blocks - // return vector determining if any of the 4 edges of the interblock need to + // return vector determining if any of the 4 edges of the connection need to // be updated for a "t" intersection const auto adjEdge1 = blk1.PutGeomSlice(geom2, inter2, blk2.NumGhosts()); const auto adjEdge2 = blk2.PutGeomSlice(geom1, inter1, blk1.NumGhosts()); - // if an interblock border needs to be updated, update + // if an connection border needs to be updated, update for (auto ii = 0U; ii < adjEdge1.size(); ii++) { if (adjEdge1[ii]) { inter.UpdateBorderFirst(ii); @@ -255,49 +255,47 @@ void SwapGeomSlice(interblock &inter, procBlock &blk1, procBlock &blk2) { /* Function to populate ghost cells with proper cell states for inviscid flow -calculation. This function operates on the entire grid and uses interblock +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 idealGas &eos, const sutherland &suth, const unique_ptr &turb, - vector &conn, const int &rank, + vector &connections, const int &rank, const MPI_Datatype &MPI_cellData) { // states -- vector of all procBlocks in the solution domain // inp -- all input variables // eos -- equation of state // suth -- sutherland's law for viscosity - // conn -- vector of interblock connections + // 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 ii = 0U; ii < states.size(); ii++) { - states[ii].AssignInviscidGhostCells(inp, eos, suth, turb); + for (auto &state : states) { + state.AssignInviscidGhostCells(inp, eos, suth, turb); } // loop over connections and swap ghost cells where needed - for (auto ii = 0U; ii < conn.size(); ii++) { - if (conn[ii].RankFirst() == rank && conn[ii].RankSecond() == rank) { - // both sides of interblock on this processor, swap w/o mpi - states[conn[ii].LocalBlockFirst()].SwapStateSlice( - conn[ii], states[conn[ii].LocalBlockSecond()]); - } else if (conn[ii].RankFirst() == rank) { - // rank matches rank of first side of interblock, swap over mpi - states[conn[ii].LocalBlockFirst()].SwapStateSliceMPI(conn[ii], rank, - MPI_cellData); - } else if (conn[ii].RankSecond() == rank) { - // rank matches rank of second side of interblock, swap over mpi - states[conn[ii].LocalBlockSecond()].SwapStateSliceMPI(conn[ii], rank, - MPI_cellData); + for (auto &conn : connections) { + if (conn.RankFirst() == rank && conn.RankSecond() == rank) { + // both sides of connection on this processor, swap w/o mpi + states[conn.LocalBlockFirst()].SwapStateSlice( + 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); + } else if (conn.RankSecond() == rank) { + // rank matches rank of second side of connection, swap over mpi + states[conn.LocalBlockSecond()].SwapStateSliceMPI(conn, rank, MPI_cellData); } - // if rank doesn't match either side of interblock, then do nothing and - // move on to the next interblock + // if rank doesn't match either side of connection, then do nothing and + // move on to the next connection } // loop over all blocks and get ghost cell edge data - for (auto ii = 0U; ii < states.size(); ii++) { - states[ii].AssignInviscidGhostCellsEdge(inp, eos, suth, turb); + for (auto &state : states) { + state.AssignInviscidGhostCellsEdge(inp, eos, suth, turb); } } @@ -383,27 +381,24 @@ void AssignSolToTimeNm1(vector &blocks) { } } -void ExplicitUpdate(vector &blocks, - const input &inp, const idealGas &eos, - const double &aRef, const sutherland &suth, +void ExplicitUpdate(vector &blocks, const input &inp, + const idealGas &eos, const sutherland &suth, const unique_ptr &turb, const int &mm, genArray &residL2, resid &residLinf) { // create dummy update (not used in explicit update) multiArray3d du(1, 1, 1, 0); // loop over all blocks and update - for (auto bb = 0U; bb < blocks.size(); bb++) { - blocks[bb].UpdateBlock(inp, eos, aRef, suth, du, turb, mm, residL2, residLinf); + for (auto &block : blocks) { + block.UpdateBlock(inp, eos, suth, du, turb, mm, residL2, residLinf); } } - double ImplicitUpdate(vector &blocks, vector> &mainDiagonal, const input &inp, const idealGas &eos, - const double &aRef, const sutherland &suth, - const unique_ptr &turb, const int &mm, - genArray &residL2, resid &residLinf, - const vector &connections, const int &rank, + const sutherland &suth, const unique_ptr &turb, + const int &mm, genArray &residL2, resid &residLinf, + const vector &connections, const int &rank, const MPI_Datatype &MPI_cellData) { // blocks -- vector of procBlocks on current processor // mainDiagonal -- main diagonal of A matrix for all blocks on processor @@ -482,7 +477,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, eos, aRef, suth, du[bb], turb, mm, residL2, + blocks[bb].UpdateBlock(inp, eos, suth, du[bb], turb, mm, residL2, residLinf); // Assign time n to time n-1 at end of nonlinear iterations @@ -498,100 +493,123 @@ double ImplicitUpdate(vector &blocks, } void SwapImplicitUpdate(vector> &du, - const vector &conn, const int &rank, + const vector &connections, const int &rank, const MPI_Datatype &MPI_cellData, const int &numGhosts) { // du -- implicit update in conservative variables - // conn -- interblock boundary conditions + // 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 interblock updates when necessary - for (auto ii = 0U; ii < conn.size(); ii++) { - if (conn[ii].RankFirst() == rank && conn[ii].RankSecond() == rank) { - // both sides of interblock are on this processor, swap w/o mpi - du[conn[ii].LocalBlockFirst()].SwapSlice(conn[ii], - du[conn[ii].LocalBlockSecond()]); - } else if (conn[ii].RankFirst() == rank) { - // rank matches rank of first side of interblock, swap over mpi - du[conn[ii].LocalBlockFirst()].SwapSliceMPI(conn[ii], rank, MPI_cellData); - } else if (conn[ii].RankSecond() == rank) { - // rank matches rank of second side of interblock, swap over mpi - du[conn[ii].LocalBlockSecond()].SwapSliceMPI(conn[ii], rank, MPI_cellData); + // loop over all connections and swap connection updates when necessary + for (auto &conn : connections) { + if (conn.RankFirst() == rank && conn.RankSecond() == rank) { + // both sides of connection are on this processor, swap w/o mpi + 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); + } else if (conn.RankSecond() == rank) { + // rank matches rank of second side of connection, swap over mpi + du[conn.LocalBlockSecond()].SwapSliceMPI(conn, rank, MPI_cellData); } - // if rank doesn't match either side of interblock, then do nothing and - // move on to the next interblock + // if rank doesn't match either side of connection, then do nothing and + // move on to the next connection } } void SwapTurbVars(vector &states, - const vector &conn, const int &rank, + const vector &connections, const int &rank, const int &numGhosts) { // states -- vector of all procBlocks in the solution domain - // conn -- interblock boundary conditions + // conn -- connection boundary conditions // rank -- processor rank // numGhosts -- number of ghost cells - // loop over all connections and swap interblock updates when necessary - for (auto ii = 0U; ii < conn.size(); ii++) { - if (conn[ii].RankFirst() == rank && conn[ii].RankSecond() == rank) { - // both sides of interblock are on this processor, swap w/o mpi - states[conn[ii].LocalBlockFirst()].SwapTurbSlice( - conn[ii], states[conn[ii].LocalBlockSecond()]); - } else if (conn[ii].RankFirst() == rank) { - // rank matches rank of first side of interblock, swap over mpi - states[conn[ii].LocalBlockFirst()].SwapTurbSliceMPI(conn[ii], rank); - } else if (conn[ii].RankSecond() == rank) { - // rank matches rank of second side of interblock, swap over mpi - states[conn[ii].LocalBlockSecond()].SwapTurbSliceMPI(conn[ii], rank); + // loop over all connections and swap connection updates when necessary + for (auto &conn : connections) { + if (conn.RankFirst() == rank && conn.RankSecond() == rank) { + // both sides of connection are on this processor, swap w/o mpi + states[conn.LocalBlockFirst()].SwapTurbSlice( + conn, states[conn.LocalBlockSecond()]); + } else if (conn.RankFirst() == rank) { + // rank matches rank of first side of connection, swap over mpi + states[conn.LocalBlockFirst()].SwapTurbSliceMPI(conn, rank); + } else if (conn.RankSecond() == rank) { + // rank matches rank of second side of connection, swap over mpi + states[conn.LocalBlockSecond()].SwapTurbSliceMPI(conn, rank); } - // if rank doesn't match either side of interblock, then do nothing and - // move on to the next interblock + // if rank doesn't match either side of connection, then do nothing and + // move on to the next connection } } -void SwapGradients(vector &states, - const vector &conn, const int &rank, - const MPI_Datatype &MPI_tensorDouble, - const MPI_Datatype &MPI_vec3d, - const int &numGhosts) { +void SwapEddyViscAndGradients(vector &states, + const vector &connections, + const int &rank, + const MPI_Datatype &MPI_tensorDouble, + const MPI_Datatype &MPI_vec3d, + const int &numGhosts) { // states -- vector of all procBlocks in the solution domain - // conn -- interblock boundary conditions + // conn -- connection boundary conditions // rank -- processor rank // MPI_tensorDouble -- MPI datatype for tensor // MPI_vec3d -- MPI datatype for vector3d // numGhosts -- number of ghost cells - // loop over all connections and swap interblock updates when necessary - for (auto ii = 0U; ii < conn.size(); ii++) { - if (conn[ii].RankFirst() == rank && conn[ii].RankSecond() == rank) { - // both sides of interblock are on this processor, swap w/o mpi - states[conn[ii].LocalBlockFirst()].SwapGradientSlice( - conn[ii], states[conn[ii].LocalBlockSecond()]); - } else if (conn[ii].RankFirst() == rank) { - // rank matches rank of first side of interblock, swap over mpi - states[conn[ii].LocalBlockFirst()].SwapGradientSliceMPI(conn[ii], rank, - MPI_tensorDouble, - MPI_vec3d); - } else if (conn[ii].RankSecond() == rank) { - // rank matches rank of second side of interblock, swap over mpi - states[conn[ii].LocalBlockSecond()].SwapGradientSliceMPI(conn[ii], rank, - MPI_tensorDouble, - MPI_vec3d); + // loop over all connections and swap connection updates when necessary + for (auto &conn : connections) { + if (conn.RankFirst() == rank && conn.RankSecond() == rank) { + // both sides of connection are on this processor, swap w/o mpi + states[conn.LocalBlockFirst()].SwapEddyViscAndGradientSlice( + conn, states[conn.LocalBlockSecond()]); + } else if (conn.RankFirst() == rank) { + // rank matches rank of first side of connection, swap over mpi + states[conn.LocalBlockFirst()].SwapEddyViscAndGradientSliceMPI( + conn, rank, MPI_tensorDouble, MPI_vec3d); + } else if (conn.RankSecond() == rank) { + // rank matches rank of second side of connection, swap over mpi + states[conn.LocalBlockSecond()].SwapEddyViscAndGradientSliceMPI( + conn, rank, MPI_tensorDouble, MPI_vec3d); } - // if rank doesn't match either side of interblock, then do nothing and - // move on to the next interblock + // if rank doesn't match either side of connection, then do nothing and + // move on to the next connection } } +void SwapWallDist(vector &states, + const vector &connections, const int &rank, + const int &numGhosts) { + // states -- vector of all procBlocks in the solution domain + // conn -- connection boundary conditions + // rank -- processor rank + // numGhosts -- number of ghost cells + + // loop over all connections and swap connection updates when necessary + for (auto &conn : connections) { + if (conn.RankFirst() == rank && conn.RankSecond() == rank) { + // both sides of connection are on this processor, swap w/o mpi + states[conn.LocalBlockFirst()].SwapWallDistSlice( + conn, states[conn.LocalBlockSecond()]); + } else if (conn.RankFirst() == rank) { + // rank matches rank of first side of connection, swap over mpi + states[conn.LocalBlockFirst()].SwapWallDistSliceMPI(conn, rank); + } else if (conn.RankSecond() == rank) { + // rank matches rank of second side of connection, swap over mpi + states[conn.LocalBlockSecond()].SwapWallDistSliceMPI(conn, rank); + } + // if rank doesn't match either side of connection, then do nothing and + // move on to the next connection + } +} void CalcResidual(vector &states, vector> &mainDiagonal, const sutherland &suth, const idealGas &eos, const input &inp, const unique_ptr &turb, - const vector &connections, const int &rank, + const vector &connections, const int &rank, const MPI_Datatype &MPI_tensorDouble, const MPI_Datatype &MPI_vec3d) { // states -- vector of all procBlocks on processor @@ -600,7 +618,7 @@ void CalcResidual(vector &states, // eos -- equation of state // inp -- input variables // turb -- turbulence model - // connections -- interblock boundary conditions + // connections -- connection boundary conditions // rank -- processor rank // MPI_tensorDouble -- MPI datatype for tensor // MPI_vec3d -- MPI datatype for vector3d @@ -609,11 +627,11 @@ void CalcResidual(vector &states, // calculate residual states[bb].CalcResidualNoSource(suth, eos, inp, turb, mainDiagonal[bb]); } - // swap gradients calculated during residual calculation - SwapGradients(states, connections, rank, MPI_tensorDouble, MPI_vec3d, - inp.NumberGhostLayers()); + // swap mut & gradients calculated during residual calculation + SwapEddyViscAndGradients(states, connections, rank, MPI_tensorDouble, + MPI_vec3d, inp.NumberGhostLayers()); - if (inp.IsTurbulent()) { + if (inp.IsRANS()) { // swap turbulence variables calculated during residual calculation SwapTurbVars(states, connections, rank, inp.NumberGhostLayers()); @@ -624,21 +642,19 @@ void CalcResidual(vector &states, } } -void CalcTimeStep(vector &states, const input &inp, - const double &aRef) { +void CalcTimeStep(vector &states, const input &inp) { // states -- vector of all procBlocks on processor // inp -- input variables - // aRef -- reference speed of sound - for (auto bb = 0U; bb < states.size(); bb++) { + for (auto &state : states) { // calculate time step - states[bb].CalcBlockTimeStep(inp, aRef); + state.CalcBlockTimeStep(inp); } } // function to reorder the block by hyperplanes -/*A hyperplane is a plane of i+j+k=constant within an individual block. The +/* A hyperplane is a plane of i+j+k=constant within an individual block. The LUSGS solver must sweep along these hyperplanes to avoid calculating a flux jacobian. Ex. The solver must visit all points on hyperplane 1 before visiting any points on hyperplane 2. @@ -666,22 +682,6 @@ vector> HyperplaneReorder(const int &imax, const int &jmax, return reorder; } -// void GetSolMMinusN(vector> &solMMinusN, -// const vector &states, -// const vector> &solN, -// const idealGas &eos, const input &inp, const int &mm) { -// // solMMinusN -- solution at time m minus solution at time n -// // solN -- solution at time n -// // eos -- equation of state -// // inp -- input variables -// // mm -- nonlinear iteration - -// for (auto bb = 0U; bb < solMMinusN.size(); bb++) { -// solMMinusN[bb] = states[bb].SolTimeMMinusN(solN[bb], eos, inp, mm); -// } -// } - - void ResizeArrays(const vector &states, const input &inp, vector> &jac) { // states -- all states on processor @@ -707,7 +707,14 @@ vector3d TauNormal(const tensor &velGrad, // wall shear stress return lambda * velGrad.Trace() * area + (mu + mut) * - (velGrad.MatMult(area) + velGrad.Transpose().MatMult(area)); + (velGrad + velGrad.Transpose()).MatMult(area); +} + +vector3d TauShear(const tensor &velGrad, + const vector3d &area, const double &mu, + const double &mut, const sutherland &suth) { + auto tauN = TauNormal(velGrad, area, mu, mut, suth); + return tauN - tauN.DotProd(area) * area; } // This function calculates the coefficients for three third order accurate @@ -798,3 +805,31 @@ primVars Beta2(const double &x_0, const double &x_1, const double &x_2, 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, + const vector3d &normArea, + const double &dist) { + // left -- left state (primative) + // right -- right state (primative) + // normArea -- unit area vector of face + // dist -- distance between centroid of left cell and right cell + + // calculate velocity derivatives + const auto velDeriv = (right.Velocity() - left.Velocity()) / dist; + + // populate velocity gradient tensor + tensor velGrad( + velDeriv.X() * normArea.X(), + velDeriv.Y() * normArea.X(), + velDeriv.Z() * normArea.X(), + velDeriv.X() * normArea.Y(), + velDeriv.Y() * normArea.Y(), + velDeriv.Z() * normArea.Y(), + velDeriv.X() * normArea.Z(), + velDeriv.Y() * normArea.Z(), + velDeriv.Z() * normArea.Z()); + + return velGrad; +} diff --git a/src/viscousFlux.cpp b/src/viscousFlux.cpp index e6acda0..3a0760f 100644 --- a/src/viscousFlux.cpp +++ b/src/viscousFlux.cpp @@ -23,6 +23,7 @@ #include "turbulence.hpp" // turbModel #include "matrix.hpp" // squareMatrix #include "utility.hpp" // TauNormal +#include "wallData.hpp" // wallVars using std::cout; using std::endl; @@ -55,13 +56,15 @@ 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. */ -viscousFlux::viscousFlux( - const tensor &velGrad, const sutherland &suth, - const idealGas &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 sutherland &suth, const idealGas &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) { // velGrad -- velocity gradient tensor // suth -- method to get viscosity (Sutherland's law) // eqnState -- equation of state @@ -79,10 +82,6 @@ viscousFlux::viscousFlux( const auto mu = suth.NondimScaling() * lamVisc; const auto mut = suth.NondimScaling() * turbVisc; - // get molecular diffusion coefficients for turbulence equations - const auto tkeCoeff = turb->SigmaK(f1); - const auto omgCoeff = turb->SigmaW(f1); - // wall shear stress const auto tau = TauNormal(velGrad, normArea, mu, mut, suth); @@ -95,6 +94,10 @@ viscousFlux::viscousFlux( tGrad.DotProd(normArea); // 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() ? @@ -103,6 +106,101 @@ viscousFlux::viscousFlux( data_[5] = (mu + omgCoeff * mutt) * omegaGrad.DotProd(normArea); } +wallVars viscousFlux::CalcWallFlux( + const tensor &velGrad, const sutherland &suth, + const idealGas &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) { + // velGrad -- velocity gradient tensor + // suth -- method to get viscosity (Sutherland's law) + // eqnState -- equation of state + // tGrad -- temperature gradient + // normArea -- unit area vector of face + // tkeGrad -- tke gradient + // omegaGrad -- omega gradient + // turb -- turbulence model + // state -- primative variables at face + // lamVisc -- laminar viscosity + // turbVisc -- turbulent viscosity + // f1 -- first blending coefficient + + wallVars wVars; + + // get viscosity with nondimensional normalization + wVars.viscosity_ = suth.NondimScaling() * lamVisc; + wVars.turbEddyVisc_ = suth.NondimScaling() * turbVisc; + + // wall shear stress + wVars.shearStress_ = + TauNormal(velGrad, normArea, wVars.viscosity_, wVars.turbEddyVisc_, suth); + + // wall heat flux + wVars.heatFlux_ = (eqnState.Conductivity(wVars.viscosity_) + + eqnState.TurbConductivity(wVars.turbEddyVisc_, + turb->TurbPrandtlNumber())) * + 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_; + + // calculate other wall data + wVars.density_ = state.Rho(); + wVars.temperature_ = state.Temperature(eqnState); + wVars.tke_ = state.Tke(); + wVars.sdr_ = state.Omega(); + 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() ? + suth.NondimScaling() * turb->EddyViscNoLim(state) : wVars.turbEddyVisc_; + data_[4] = (wVars.viscosity_ + tkeCoeff * mutt) * tkeGrad.DotProd(normArea); + data_[5] = (wVars.viscosity_ + omgCoeff * mutt) * omegaGrad.DotProd(normArea); + + return wVars; +} + +void viscousFlux::CalcWallLawFlux( + const vector3d &tauWall, const double &qWall, const double &muWall, + const double &mutWall, const vector3d &velWall, + const vector3d &normArea, const vector3d &tkeGrad, + const vector3d &omegaGrad, const unique_ptr &turb) { + // tauWall -- wall shear stress + // qWall -- wall heat flux + // muWall -- wall viscosity + // mutWall -- wall eddy viscosity + // normArea -- unit area vector of face + // tkeGrad -- tke gradient + // omegaGrad -- omega gradient + // turb -- turbulence model + + data_[0] = tauWall.X(); + data_[1] = tauWall.Y(); + data_[2] = tauWall.Z(); + data_[3] = 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); +} + + // non-member functions // ---------------------------------------------------------------------------- // operator overload for << - allows use of cout, cerr, etc. @@ -116,32 +214,3 @@ ostream &operator<<(ostream &os, viscousFlux &flux) { os << flux.MomO() << endl; return os; } - - -// function to calculate the velocity gradients at a cell face using the Thin -// Shear Layer approximation -tensor CalcVelGradTSL(const primVars &left, const primVars &right, - const vector3d &normArea, - const double &dist) { - // left -- left state (primative) - // right -- right state (primative) - // normArea -- unit area vector of face - // dist -- distance between centroid of left cell and right cell - - // calculate velocity derivatives - const auto velDeriv = (right.Velocity() - left.Velocity()) / dist; - - // populate velocity gradient tensor - tensor velGrad( - velDeriv.X() * normArea.X(), - velDeriv.Y() * normArea.X(), - velDeriv.Z() * normArea.X(), - velDeriv.X() * normArea.Y(), - velDeriv.Y() * normArea.Y(), - velDeriv.Z() * normArea.Y(), - velDeriv.X() * normArea.Z(), - velDeriv.Y() * normArea.Z(), - velDeriv.Z() * normArea.Z()); - - return velGrad; -} diff --git a/src/wallData.cpp b/src/wallData.cpp new file mode 100644 index 0000000..64d894f --- /dev/null +++ b/src/wallData.cpp @@ -0,0 +1,215 @@ +/* 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 "wallData.hpp" +#include "vector3d.hpp" +#include "input.hpp" +#include "eos.hpp" +#include "primVars.hpp" + +// member functions +vector3d wallData::WallShearStress(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).shearStress_; +} + +double wallData::WallHeatFlux(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).heatFlux_; +} + +double wallData::Yplus(const int &ii, const int &jj, const int &kk) const { + return (*this)(ii, jj, kk).yplus_; +} + +double wallData::WallTke(const int &ii, const int &jj, const int &kk) const { + return (*this)(ii, jj, kk).tke_; +} + +double wallData::WallSdr(const int &ii, const int &jj, const int &kk) const { + return (*this)(ii, jj, kk).sdr_; +} + +double wallData::WallTemperature(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).temperature_; +} + +double wallData::WallEddyViscosity(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).turbEddyVisc_; +} + +double wallData::WallPressure(const int &ii, const int &jj, const int &kk, + const idealGas &eos) const { + return eos.PressureRT(this->WallDensity(ii, jj, kk), + this->WallTemperature(ii, jj, kk)); +} + +double wallData::WallViscosity(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).viscosity_; +} + +double wallData::WallDensity(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).density_; +} + +double wallData::WallFrictionVelocity(const int &ii, const int &jj, + const int &kk) const { + return (*this)(ii, jj, kk).frictionVelocity_; +} + +void wallData::PackWallData(char *(&sendBuffer), const int &sendBufSize, + int &position, + const MPI_Datatype &MPI_wallData) const { + // sendBuffer -- buffer to pack data into + // sendBufSize -- size of buffer + // position -- location within buffer + + // pack force counters + MPI_Pack(&inviscidForce_, 1, MPI_DOUBLE, sendBuffer, sendBufSize, &position, + MPI_COMM_WORLD); + MPI_Pack(&viscousForce_, 1, MPI_DOUBLE, 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); +} + +void wallData::PackSize(int &sendBufSize, + const MPI_Datatype &MPI_wallData) const { + auto tempSize = 0; + // add sizes for force data + MPI_Pack_size(2, MPI_DOUBLE, 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; + // add size for bc types (+1 for c_str end character) + MPI_Pack_size(surf_.BCType().size() + 1, MPI_CHAR, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; + + // add array of wallData + MPI_Pack_size(data_.Size(), MPI_wallData, MPI_COMM_WORLD, &tempSize); + sendBufSize += tempSize; +} + +void wallData::UnpackWallData(char *(&recvBuffer), const int &recvBufSize, + int &position, const MPI_Datatype &MPI_wallData, + const input &inp) { + // recvBuffer -- buffer to unpack data from + // recvBufSize -- size of buffer + // position -- location within buffer + + // unpack forces + MPI_Unpack(recvBuffer, recvBufSize, &position, &inviscidForce_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + MPI_Unpack(recvBuffer, recvBufSize, &position, &viscousForce_, 1, MPI_DOUBLE, + MPI_COMM_WORLD); + + // unpack BC surface + surf_.UnpackBoundarySurface(recvBuffer, recvBufSize, position); + + // get bc data from tag + 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); +} + +// Split wallData at given direction and index +// The calling instance is modified to be the lower surface, and the upper +// surface is returned. If the calling instance is not split, the split +// boolean returns false and the returned wallData is garbage. The force +// variables are not split. +wallData wallData::Split(const string &dir, const int &ind, bool &split, + bool &low) { + wallData upper = *this; + // split if necessary + auto upperSurf = surf_.Split(dir, ind, split, low); + if (split) { // surface split; upper and lower valid + upper.surf_ = upperSurf; + upper.data_ = data_.Slice(dir, {ind, data_.End(dir)}); + data_ = data_.Slice(dir, {data_.Start(dir), ind}); + } else if (!low) { // not split; upper is valid + *this = wallData(); // invalidate lower; upper already equals *this + } else { // if not split and lower is valid, invalidate upper + upper = wallData(); + } + return upper; +} + +void wallData::Join(const wallData &upper, const string &dir, bool &joined) { + // modify upper surface to see if it is possible to join + auto upSurfMod = upper.surf_; + upSurfMod.IncrementDirection(dir, surf_.Max(dir)); + + // join if possible + surf_.Join(upSurfMod, dir, joined); + if (joined) { + inviscidForce_ += upper.inviscidForce_; + viscousForce_ += upper.viscousForce_; + + multiArray3d newVars(surf_.NumI(), surf_.NumJ(), surf_.NumK(), 0); + 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)}, + upper.data_.Slice(dir, {upper.data_.PhysStart(dir), + upper.data_.End(dir)})); + data_ = newVars; + } +} + + primVars wallData::WallState(const int &ii, const int &jj, const int &kk, + const idealGas &eos) const { + return primVars(this->WallDensity(ii, jj, kk), this->WallVelocity(), + this->WallPressure(ii, jj, kk, eos), + 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 << "BC Data: "; + bcData_->Print(os); + os << endl; + os << "BC Surface: " << surf_ << endl; + os << "Wall Data:" << endl; + os << data_ << endl; +} + +ostream &operator<<(ostream &os, const wallData &wd) { + wd.Print(os); + return os; +} + +ostream &operator<<(ostream &os, const wallVars &wv) { + os << wv.shearStress_ << "; " << wv.heatFlux_ << "; " << wv.yplus_ << "; " + << wv.temperature_ << "; " << wv.turbEddyVisc_ << "; " << wv.viscosity_ + << "; " << wv.density_ << "; " << wv.frictionVelocity_ << "; " << wv.tke_ + << "; " << wv.sdr_; + return os; +} \ No newline at end of file diff --git a/src/wallLaw.cpp b/src/wallLaw.cpp new file mode 100644 index 0000000..340a6e2 --- /dev/null +++ b/src/wallLaw.cpp @@ -0,0 +1,284 @@ +/* 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 "wallLaw.hpp" +#include "primVars.hpp" // primVars +#include "eos.hpp" // idealGas +#include "utility.hpp" // TauShear +#include "turbulence.hpp" +#include "wallData.hpp" + +using std::cout; +using std::endl; +using std::cerr; + +// ------------------------------------------------------------------------- +wallVars wallLaw::AdiabaticBCs(const vector3d &area, + const vector3d &velWall, + const idealGas &eos, const sutherland &suth, + const unique_ptr &turb, + const bool &isLower) { + // initialize wallVars + wallVars wVars; + wVars.heatFlux_ = 0.0; + + // get tangential velocity + const auto vel = state_.Velocity() - velWall; + const auto velTan = vel - vel.DotProd(area) * area; + const auto velTanMag = velTan.Mag(); + + // get wall temperature from crocco-busemann equation + this->CalcRecoveryFactor(eos); + // this is correct form of crocco-busemann, typo in Nichols & Nelson (2004) + auto tW = state_.Temperature(eos) + + 0.5 * recoveryFactor_ * velTanMag * velTanMag / eos.SpecificHeat(); + // set wall properties + this->SetWallVars(tW, eos, suth); + + auto func = [&](const double &yplus) { + // calculate u* and u+ from y+ + this->CalcVelocities(yplus, velTanMag); + // calculate constants + this->UpdateGamma(eos); + this->UpdateConstants(wVars.heatFlux_); + // calculate y+ from White & Christoph + this->CalcYplusWhite(); + // calculate root of y+ equation + wVars.yplus_ = yplus; + return this->CalcYplusRoot(yplus); + }; + + // iteratively solve for y+ + FindRoot(func, 1.0e1, 1.0e4, 1.0e-8); + + // calculate turbulent eddy viscosity from wall shear stress + // use compressible form of equation (Nichols & Nelson 2004) + // calculate turbulence variables from eddy viscosity + if (isRANS_) { + this->CalcTurbVars(turb, eos, suth, wVars.tke_, wVars.sdr_); + } + + wVars.density_ = rhoW_; + wVars.temperature_ = tW_; + wVars.viscosity_ = muW_; + wVars.turbEddyVisc_ = mutW_; + wVars.frictionVelocity_ = uStar_; + wVars.shearStress_ = this->ShearStressMag() * velTan / velTanMag; + if (!isLower) { + wVars.shearStress_ *= -1.0; + } + return wVars; +} + +wallVars wallLaw::HeatFluxBCs(const vector3d &area, + const vector3d &velWall, + const idealGas &eos, const sutherland &suth, + const unique_ptr &turb, + const double &heatFluxW, const bool &isLower) { + // initialize wallVars + wallVars wVars; + wVars.heatFlux_ = heatFluxW; + + // get tangential velocity + const auto vel = state_.Velocity() - velWall; + const auto velTan = vel - vel.DotProd(area) * area; + const auto velTanMag = velTan.Mag(); + + // get wall temperature from crocco-busemann equation + this->CalcRecoveryFactor(eos); + + // set wall properties - guess wall temperature equals interior temperature + wVars.temperature_ = state_.Temperature(eos); + this->SetWallVars(wVars.temperature_, eos, suth); + + 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(eos, wVars.heatFlux_); + this->SetWallVars(wVars.temperature_, eos, suth); + this->UpdateGamma(eos); + this->UpdateConstants(wVars.heatFlux_); + // calculate y+ from White & Christoph + this->CalcYplusWhite(); + // calculate root of y+ equation + wVars.yplus_ = yplus; + return this->CalcYplusRoot(yplus); + }; + + // iteratively solve for y+ + FindRoot(func, 1.0e1, 1.0e4, 1.0e-8); + + // calculate turbulent eddy viscosity from wall shear stress + // use compressible form of equation (Nichols & Nelson 2004) + // calculate turbulence variables from eddy viscosity + if (isRANS_) { + this->CalcTurbVars(turb, eos, suth, wVars.tke_, wVars.sdr_); + } + + wVars.density_ = rhoW_; + wVars.viscosity_ = muW_; + wVars.turbEddyVisc_ = mutW_; + wVars.frictionVelocity_ = uStar_; + wVars.shearStress_ = this->ShearStressMag() * velTan / velTanMag; + if (!isLower) { + wVars.shearStress_ *= -1.0; + } + return wVars; +} + +wallVars wallLaw::IsothermalBCs(const vector3d &area, + const vector3d &velWall, + const idealGas &eos, const sutherland &suth, + const unique_ptr &turb, + const double &tW, const bool &isLower) { + // initialize wallVars + wallVars wVars; + wVars.temperature_ = tW; + + // get tangential velocity + const auto vel = state_.Velocity() - velWall; + const auto velTan = vel - vel.DotProd(area) * area; + const auto velTanMag = velTan.Mag(); + + // get wall properties + this->CalcRecoveryFactor(eos); + this->SetWallVars(wVars.temperature_, eos, suth); + + 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(eos); + wVars.heatFlux_ = this->CalcHeatFlux(eos); + // calculate constants + this->UpdateConstants(wVars.heatFlux_); + // calculate y+ from White & Christoph + this->CalcYplusWhite(); + // calculate root of y+ equation + wVars.yplus_ = yplus; + return this->CalcYplusRoot(yplus); + }; + + // iteratively solve for y+ + FindRoot(func, 1.0e1, 1.0e4, 1.0e-8); + + // calculate turbulent eddy viscosity from yplus + // use compressible form of equation (Nichols & Nelson 2004) + // calculate turbulence variables from eddy viscosity + if (isRANS_) { + this->CalcTurbVars(turb, eos, suth, wVars.tke_, wVars.sdr_); + } + + wVars.density_ = rhoW_; + wVars.viscosity_ = muW_; + wVars.turbEddyVisc_ = mutW_; + wVars.frictionVelocity_ = uStar_; + wVars.shearStress_ = this->ShearStressMag() * velTan / velTanMag; + if (!isLower) { + wVars.shearStress_ *= -1.0; + } + return wVars; +} + +void wallLaw::UpdateGamma(const idealGas &eos) { + // calculate constants + gamma_ = recoveryFactor_ * uStar_ * uStar_ / (2.0 * eos.SpecificHeat() * tW_); +} + +void wallLaw::UpdateConstants(const double &heatFluxW) { + // calculate constants + beta_ = heatFluxW * muW_ / (rhoW_ * tW_ * kW_ * uStar_); // 0 for adiabatic + q_ = sqrt(beta_ * beta_ + 4.0 * gamma_); + phi_ = std::asin(-beta_ / q_); +} + +void wallLaw::CalcYplusWhite() { + yplusWhite_ = + std::exp((vonKarmen_ / sqrt(gamma_)) * + (std::asin((2.0 * gamma_ * uplus_ - beta_) / q_) - phi_)) * + yplus0_; +} + +double wallLaw::CalcHeatFlux(const idealGas &eos) const { + // calculate wall heat flux from croco-busemann equation + auto tmp = + (state_.Temperature(eos) / tW_ - 1.0 + gamma_ * uplus_ * uplus_) / uplus_; + return tmp * (rhoW_ * tW_ * kW_ * uStar_) / muW_; +} + +double wallLaw::CalcWallTemperature(const idealGas &eos, + const double &heatFluxW) const { + return state_.Temperature(eos) + + recoveryFactor_ * uStar_ * uStar_ * uplus_ * uplus_ / + (2.0 * eos.SpecificHeat() + + heatFluxW * muW_ / (rhoW_ * kW_ * uStar_)); +} + +void wallLaw::SetWallVars(const double &tW, const idealGas &eos, + const sutherland &suth) { + tW_ = tW; + rhoW_ = eos.DensityTP(tW_, state_.P()); + + // get wall viscosity, conductivity from wall temperature + muW_ = suth.EffectiveViscosity(tW_); + kW_ = eos.Conductivity(muW_); +} + +double wallLaw::CalcYplusRoot(const double &yplus) const { + constexpr auto sixth = 1.0 / 6.0; + const auto ku = vonKarmen_ * uplus_; + return yplus - (uplus_ + yplusWhite_ - + yplus0_ * (1.0 + ku + 0.5 * ku * ku + sixth * pow(ku, 3.0))); +} + +void wallLaw::EddyVisc(const idealGas &eos, const sutherland &suth) { + 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_), + 0.0)); + const auto ku = vonKarmen_ * uplus_; + mutW_ = muW_ * (1.0 + dYplusWhite - + vonKarmen_ * yplus0_ * (1.0 + ku + 0.5 * ku * ku)) - + suth.EffectiveViscosity(state_.Temperature(eos)); + mutW_ = std::max(mutW_, 0.0); +} + +void wallLaw::CalcVelocities(const double &yplus, const double &u) { + // calculate u* and u+ from y+ + uplus_ = (wallDist_ * rhoW_ * u) / (muW_ * yplus); + uStar_ = u / uplus_; +} + +void wallLaw::CalcTurbVars(const unique_ptr &turb, + const idealGas &eos, const sutherland &suth, + double &kWall, double &wWall) { + this->EddyVisc(eos, suth); + // calculate turbulence variables from eddy viscosity + auto wi = 6.0 * muW_ / (turb->WallBeta() * rhoW_ * wallDist_ * wallDist_); + wi *= suth.NondimScaling(); + auto wo = uStar_ / (sqrt(turb->BetaStar()) * vonKarmen_ * wallDist_); + wo *= suth.NondimScaling(); + wWall = sqrt(wi * wi + wo * wo); + kWall = wWall * mutW_ / state_.Rho() * suth.InvNondimScaling(); +} + +void wallLaw::CalcRecoveryFactor(const idealGas &eos) { + recoveryFactor_ = pow(eos.Prandtl(), 1.0 / 3.0); +} \ No newline at end of file diff --git a/testCases/couette/couette.inp b/testCases/couette/couette.inp new file mode 100644 index 0000000..6b65ea9 --- /dev/null +++ b/testCases/couette/couette.inp @@ -0,0 +1,45 @@ +#This is the input file + +gridName: couette + +#solver parameters +equationSet: navierStokes +timeIntegration: implicitEuler +cflStart: 1.0e5 +cflMax: 1.0e5 +faceReconstruction: thirdOrder +limiter: none +iterations: 200000 +outputFrequency: 10000 +outputVariables: +restartFrequency: 10000 + +#reference conditions +pressureRef: 101300.0 +densityRef: 1.2256 +temperatureRef: 288.0 +velocityRef: [75.4, 0.0, 0.0] + +initialConditions: + +matrixSolver: lusgs +matrixRelaxation: 1.0 + +boundaryStates: + +#------------------------------------------------------------- +boundaryConditions: 1 +# Block 0 -- Dimensions: 65 x 5 x 2 +2 2 2 +# i-surfaces + viscousWall 0 0 0 4 0 1 2 + viscousWall 64 64 0 4 0 1 1 +# j-surfaces + periodic 0 64 0 0 0 1 4 + periodic 0 64 4 4 0 1 5 +# k-surfaces + slipWall 0 64 0 4 0 0 3 + slipWall 0 64 0 4 1 1 3 diff --git a/testCases/couette/couette.xyz b/testCases/couette/couette.xyz new file mode 100644 index 0000000..f176b45 Binary files /dev/null and b/testCases/couette/couette.xyz differ diff --git a/testCases/rae2822/rae2822.inp b/testCases/rae2822/rae2822.inp index f8f192a..3248c5e 100644 --- a/testCases/rae2822/rae2822.inp +++ b/testCases/rae2822/rae2822.inp @@ -4,11 +4,11 @@ decompositionMethod: cubic #solver parameters equationSet: rans timeIntegration: implicitEuler -cflStart: 5 -cflMax: 5 +cflStart: 50 +cflMax: 50 faceReconstruction: thirdOrder limiter: vanAlbada -iterations: 5000 +iterations: 2000 outputFrequency: 1000 outputVariables: diff --git a/testCases/regressionTests.py b/testCases/regressionTests.py index 91ea2af..9808373 100755 --- a/testCases/regressionTests.py +++ b/testCases/regressionTests.py @@ -14,8 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -# This script runs regression tests to test builds on linux and osx for -# travis ci. +# This script runs regression tests to test builds on linux and macOS for +# travis ci, and windows for appveyor import os import optparse @@ -23,36 +23,38 @@ import sys import datetime import subprocess +import time class regressionTest: - caseName = "none" - iterations = 100 - procs = 1 - residuals = [1.0, 1.0, 1.0, 1.0, 1.0] - ignoreIndices = [] - location = "." - runDirectory = "." - aitherPath = "." - mpirunPath = "mpirun" - percentTolerance = 0.01 - isRestart = False - restartFile = "none" - def __init__(self): + self.caseName = "none" + self.iterations = 100 + self.procs = 1 + self.residuals = [1.0, 1.0, 1.0, 1.0, 1.0] + self.ignoreIndices = [] self.location = os.getcwd() - + self.runDirectory = "." + self.aitherPath = "aither" + self.mpirunPath = "mpirun" + self.percentTolerance = 0.01 + self.isRestart = False + self.restartFile = "none" + def SetRegressionCase(self, name): self.caseName = name - + def SetNumberOfIterations(self, num): self.iterations = num - + def SetNumberOfProcessors(self, num): self.procs = num - + + def Processors(self): + return self.procs + def SetResiduals(self, resid): self.residuals = resid - + def SetRunDirectory(self, path): self.runDirectory = path @@ -61,10 +63,10 @@ def SetAitherPath(self, path): def SetMpirunPath(self, path): self.mpirunPath = path - + def SetIgnoreIndices(self, ind): self.ignoreIndices.append(ind) - + def SetPercentTolerance(self, per): self.percentTolerance = per @@ -76,10 +78,10 @@ def SetRestart(self, resFlag): def SetRestartFile(self, resFile): self.restartFile = resFile - + def ReturnToHomeDirectory(self): os.chdir(self.location) - + def GetTestCaseResiduals(self): fname = self.caseName + ".resid" file = open(fname, "r") @@ -103,7 +105,7 @@ def CompareResiduals(self, returnCode): else: passing = [False for ii in resids] return passing, resids - + def GetResiduals(self): return self.residuals @@ -121,7 +123,7 @@ def ModifyInputFile(self): fout.write("outputFrequency: " + str(self.iterations) + "\n") else: fout.write(line) - + # modify the input file and run the test def RunCase(self): self.GoToRunDirectory() @@ -138,57 +140,69 @@ def RunCase(self): + " " + self.caseName + ".inp > " + self.caseName + ".out" print(cmd) start = datetime.datetime.now() + interval = start process = subprocess.Popen(cmd, shell=True) - returnCode = process.wait() + while process.poll() is None: + current = datetime.datetime.now() + if (current - interval).total_seconds() > 60.: + print("----- Run Time: %s -----" % (current - start)) + interval = current + time.sleep(0.5) + returnCode = process.poll() + if (returnCode == 0): print("Simulation completed with no errors") else: print("ERROR: Simulation terminated with errors") duration = datetime.datetime.now() - start - + # test residuals for pass/fail passed, resids = self.CompareResiduals(returnCode) - if (all(passed)): + 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("Residuals are:", resids) + print("Test Duration:",duration) print("---------- End Test:", self.caseName, "----------") + print("") + print("") self.ReturnToHomeDirectory() return passed - - + + def main(): # Set up options parser = optparse.OptionParser() parser.add_option("-a", "--aitherPath", action="store", dest="aitherPath", - default="aither", help="Path to aither executable.") + default="aither", + help="Path to aither executable. Default = aither") parser.add_option("-o", "--operatingSystem", action="store", dest="operatingSystem", default="linux", - help="Operating system that tests will run on [linux/osx]") + help="Operating system that tests will run on [linux/macOS/windows]. Default = linux") parser.add_option("-m", "--mpirunPath", action="store", - dest="mpirunPath", default="", - help="Path to mpirun") + dest="mpirunPath", default="mpirun", + help="Path to mpirun. Default = mpirun") options, remainder = parser.parse_args() - # travis osx images have 1 proc, ubuntu have 2 - if (options.operatingSystem == "linux"): + # 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 = 1 - + numIterations = 100 numIterationsRestart = 50 totalPass = True - + # ------------------------------------------------------------------ # Regression tests # ------------------------------------------------------------------ - + # ------------------------------------------------------------------ # subsonic cylinder # laminar, inviscid, lu-sgs @@ -201,11 +215,11 @@ def main(): subCyl.SetResiduals([1.5394e-1, 1.4989e-1, 1.5909e-1, 8.1415e-1, 1.5295e-1]) subCyl.SetIgnoreIndices(3) subCyl.SetMpirunPath(options.mpirunPath) - + # run regression case passed = subCyl.RunCase() totalPass = totalPass and all(passed) - + # ------------------------------------------------------------------ # multi-block subsonic cylinder # laminar, inviscid, lusgs, multi-block @@ -215,13 +229,13 @@ def main(): multiCyl.SetRunDirectory("multiblockCylinder") multiCyl.SetNumberOfProcessors(maxProcs) multiCyl.SetNumberOfIterations(numIterations) - if (options.operatingSystem == "linux"): + if (multiCyl.Processors() == 2): multiCyl.SetResiduals([2.3188e-1, 2.9621e-1, 4.5868e-1, 1.2813, 2.3009e-1]) else: multiCyl.SetResiduals([2.3188e-1, 2.9621e-1, 4.5868e-1, 1.2813, 2.3009e-1]) multiCyl.SetIgnoreIndices(3) multiCyl.SetMpirunPath(options.mpirunPath) - + # run regression case passed = multiCyl.RunCase() totalPass = totalPass and all(passed) @@ -239,11 +253,11 @@ def main(): shockTube.SetIgnoreIndices(2) shockTube.SetIgnoreIndices(3) shockTube.SetMpirunPath(options.mpirunPath) - + # run regression case passed = shockTube.RunCase() totalPass = totalPass and all(passed) - + # ------------------------------------------------------------------ # sod shock tube restart # laminar, inviscid, bdf2, weno @@ -255,7 +269,7 @@ def main(): # run regression case passed = shockTubeRestart.RunCase() totalPass = totalPass and all(passed) - + # ------------------------------------------------------------------ # supersonic wedge # laminar, inviscid, explicit euler @@ -268,7 +282,7 @@ def main(): supWedge.SetResiduals([4.1813e-1, 4.2549e-1, 3.6525e-1, 3.8013e-1, 4.0998e-1]) supWedge.SetIgnoreIndices(3) supWedge.SetMpirunPath(options.mpirunPath) - + # run regression case passed = supWedge.RunCase() totalPass = totalPass and all(passed) @@ -282,14 +296,14 @@ def main(): transBump.SetRunDirectory("transonicBump") transBump.SetNumberOfProcessors(1) transBump.SetNumberOfIterations(numIterations) - transBump.SetResiduals([1.1839e-1, 6.8615e-2, 8.4925e-2, 1.0398, 9.9669e-2]) + transBump.SetResiduals([1.1839e-1, 6.8615e-2, 8.4925e-2, 1.0398, 9.9669e-2]) transBump.SetIgnoreIndices(3) transBump.SetMpirunPath(options.mpirunPath) # run regression case passed = transBump.RunCase() totalPass = totalPass and all(passed) - + # ------------------------------------------------------------------ # viscous flat plate # laminar, viscous, lu-sgs @@ -299,7 +313,7 @@ def main(): viscPlate.SetRunDirectory("viscousFlatPlate") viscPlate.SetNumberOfProcessors(maxProcs) viscPlate.SetNumberOfIterations(numIterations) - if (options.operatingSystem == "linux"): + if (viscPlate.Processors() == 2): viscPlate.SetResiduals([7.7265e-2, 2.4712e-1, 5.6413e-2, 1.0228, 7.9363e-2]) else: viscPlate.SetResiduals([7.6468e-2, 2.4713e-1, 4.0109e-2, 9.8730e-1, 7.9237e-2]) @@ -308,7 +322,7 @@ def main(): # run regression case passed = viscPlate.RunCase() - totalPass = totalPass and all(passed) + totalPass = totalPass and all(passed) # ------------------------------------------------------------------ # turbulent flat plate @@ -319,7 +333,7 @@ def main(): turbPlate.SetRunDirectory("turbFlatPlate") turbPlate.SetNumberOfProcessors(maxProcs) turbPlate.SetNumberOfIterations(numIterations) - if (options.operatingSystem == "linux"): + if (turbPlate.Processors() == 2): turbPlate.SetResiduals([4.1174e-2, 4.2731e-2, 1.0641, 8.3686e-2, 3.9585e-2, 4.5098e-8, 1.1416e-5]) else: @@ -330,7 +344,7 @@ def main(): # run regression case passed = turbPlate.RunCase() - totalPass = totalPass and all(passed) + totalPass = totalPass and all(passed) # ------------------------------------------------------------------ # rae2822 @@ -341,19 +355,58 @@ def main(): rae2822.SetRunDirectory("rae2822") rae2822.SetNumberOfProcessors(maxProcs) rae2822.SetNumberOfIterations(numIterations) - if (options.operatingSystem == "linux"): - rae2822.SetResiduals([6.3790e-1, 1.0466, 6.1588e-1, 4.8859e-1, 5.8718e-1, - 2.5317e-5, 4.3633e-5]) + if (rae2822.Processors() == 2): + rae2822.SetResiduals([5.0196e-1, 1.2895, 4.6389e-1, 1.1253, 4.5099e-1, + 1.1526e-7, 1.9755e-5]) else: - rae2822.SetResiduals([6.3495e-1, 1.0553, 6.2108e-1, 6.0576e-1, 5.8816e-1, - 2.5315e-5, 4.3783e-5]) + rae2822.SetResiduals([5.0069e-1, 1.3219, 4.6502e-1, 9.1543e-1, 4.5357e-1, + 1.1694e-7, 2.0139e-5]) rae2822.SetIgnoreIndices(3) rae2822.SetMpirunPath(options.mpirunPath) # run regression case passed = rae2822.RunCase() - totalPass = totalPass and all(passed) - + totalPass = totalPass and all(passed) + + # ------------------------------------------------------------------ + # couette flow + # laminar, viscous, periodic bcs, moving wall, isothermal wall + couette = regressionTest() + couette.SetRegressionCase("couette") + couette.SetAitherPath(options.aitherPath) + couette.SetRunDirectory("couette") + couette.SetNumberOfProcessors(1) + couette.SetNumberOfIterations(numIterations) + couette.SetResiduals([1.1359e-1, 5.0726e-1, 7.3287e-2, 5.0139e-1, 2.2817e-1]) + couette.SetIgnoreIndices(3) + couette.SetMpirunPath(options.mpirunPath) + + # run regression case + passed = couette.RunCase() + totalPass = totalPass and all(passed) + + # ------------------------------------------------------------------ + # wall law + # wall law bc, turbulent, blusgs + wallLaw = regressionTest() + wallLaw.SetRegressionCase("wallLaw") + wallLaw.SetAitherPath(options.aitherPath) + wallLaw.SetRunDirectory("wallLaw") + wallLaw.SetNumberOfProcessors(maxProcs) + wallLaw.SetNumberOfIterations(20) + if (wallLaw.Processors() == 2): + wallLaw.SetResiduals([8.5709e-01, 1.2341e-01, 1.4102e-01, 9.2940e-01, + 8.6223e-01, 6.0548e-02, 6.7626e-05]) + else: + wallLaw.SetResiduals([8.4993e-01, 1.2039e-01, 1.3807e-01, 9.2928e-01, + 8.5502e-01, 6.0546e-02, 6.7616e-05]) + wallLaw.SetIgnoreIndices(1) + wallLaw.SetMpirunPath(options.mpirunPath) + + # run regression case + passed = wallLaw.RunCase() + totalPass = totalPass and all(passed) + # ------------------------------------------------------------------ # regression test overall pass/fail # ------------------------------------------------------------------ @@ -363,7 +416,7 @@ def main(): else: print("ERROR: Some tests failed") sys.exit(1) - - + + if __name__ == "__main__": main() diff --git a/testCases/wallLaw/wallLaw.inp b/testCases/wallLaw/wallLaw.inp new file mode 100644 index 0000000..5ec1edb --- /dev/null +++ b/testCases/wallLaw/wallLaw.inp @@ -0,0 +1,70 @@ +# grid name +gridName: wallLaw + +# solver parameters +decompositionMethod: cubic +equationSet: rans +timeIntegration: implicitEuler +cflStart: 100000 +cflMax: 100000 + +faceReconstruction: thirdOrder +inviscidFlux: roe +inviscidFluxJacobian: rusanov +viscousFaceReconstruction: central +limiter: minmod + +iterations: 2000 +outputFrequency: 500 +outputVariables: +wallOutputVariables: +restartFrequency: 1000 + +gamma: 1.4 +gasConstant: 287.058 + +# reference conditions +pressureRef: 101325 +densityRef: 1.2256 +temperatureRef: 288 +lengthRef: 1 +velocityRef: [0, 0, 75] + +initialConditions: + +matrixSolver: blusgs +matrixSweeps: 4 +matrixRelaxation: 1 + +turbulenceModel: sst2003 + +boundaryStates: + +#------------------------------------------------------------- +boundaryConditions: 2 +# Block 0 -- Dimensions: 3 x 31 x 51 +2 2 2 +# i-surfaces + slipWall 0 0 0 30 0 50 2 + slipWall 2 2 0 30 0 50 2 +# j-surfaces + interblock 0 2 30 30 0 50 1001 + stagnationInlet 0 2 0 0 0 50 4 +# k-surfaces + slipWall 0 2 0 30 0 0 3 + pressureOutlet 0 2 0 30 50 50 5 +# Block 1 -- Dimensions: 45 x 3 x 51 +2 2 2 +# i-surfaces + interblock 0 0 0 2 0 50 4000 + pressureOutlet 44 44 0 2 0 50 5 +# j-surfaces + slipWall 0 44 0 0 0 50 2 + slipWall 0 44 2 2 0 50 2 +# k-surfaces + viscousWall 0 44 0 2 0 0 1 + pressureOutlet 0 44 0 2 50 50 5 diff --git a/testCases/wallLaw/wallLaw.xyz b/testCases/wallLaw/wallLaw.xyz new file mode 100644 index 0000000..0769d76 Binary files /dev/null and b/testCases/wallLaw/wallLaw.xyz differ